struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, enum exynos_drm_output_type out_type) { struct drm_crtc *crtc; drm_for_each_crtc(crtc, drm_dev) if (to_exynos_crtc(crtc)->type == out_type) return to_exynos_crtc(crtc); return ERR_PTR(-ENODEV); }
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->te_handler) exynos_crtc->ops->te_handler(exynos_crtc); }
static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->disable_vblank) exynos_crtc->ops->disable_vblank(exynos_crtc); }
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); drm_crtc_cleanup(crtc); kfree(exynos_crtc); }
static int exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane = exynos_crtc->plane; unsigned int crtc_w; unsigned int crtc_h; int pipe = exynos_crtc->pipe; int ret; /* * copy the mode data adjusted by mode_fixup() into crtc->mode * so that hardware can be seet to proper mode. */ memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); crtc_w = crtc->primary->fb->width - x; crtc_h = crtc->primary->fb->height - y; ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, x, y, crtc_w, crtc_h); if (ret) return ret; plane->crtc = crtc; plane->fb = crtc->primary->fb; exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); return 0; }
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); if (exynos_crtc->dpms == mode) { DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); return; } mutex_lock(&dev->struct_mutex); switch (mode) { case DRM_MODE_DPMS_ON: exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); exynos_crtc->dpms = mode; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); exynos_crtc->dpms = mode; break; default: DRM_ERROR("unspecified mode %d\n", mode); break; } mutex_unlock(&dev->struct_mutex); }
static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("%s\n", __FILE__); /* * when set_crtc is requested from user or at booting time, * crtc->commit would be called without dpms call so if dpms is * no power on then crtc->dpms should be called * with DRM_MODE_DPMS_ON for the hardware power to be on. */ if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) { int mode = DRM_MODE_DPMS_ON; /* * enable hardware(power on) to all encoders hdmi connected * to current crtc. */ exynos_drm_crtc_dpms(crtc, mode); /* * enable dma to all encoders connected to current crtc and * lcd panel. */ exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_dpms_from_crtc); } exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, exynos_drm_encoder_crtc_commit); }
static int exynos_drm_crtc_update(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc; struct exynos_drm_overlay *overlay; struct exynos_drm_crtc_pos pos; struct drm_display_mode *mode = &crtc->mode; struct drm_framebuffer *fb = crtc->fb; if (!mode || !fb) return -EINVAL; exynos_crtc = to_exynos_crtc(crtc); overlay = &exynos_crtc->overlay; memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos)); /* it means the offset of framebuffer to be displayed. */ pos.fb_x = crtc->x; pos.fb_y = crtc->y; /* OSD position to be displayed. */ pos.crtc_x = 0; pos.crtc_y = 0; pos.crtc_w = fb->width - crtc->x; pos.crtc_h = fb->height - crtc->y; return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos); }
static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane = exynos_crtc->plane; unsigned int crtc_w; unsigned int crtc_h; int ret; /* when framebuffer changing is requested, crtc's dpms should be on */ if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { DRM_ERROR("failed framebuffer changing request.\n"); return -EPERM; } crtc_w = crtc->primary->fb->width - x; crtc_h = crtc->primary->fb->height - y; ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, x, y, crtc_w, crtc_h); if (ret) return ret; exynos_drm_crtc_commit(crtc); return 0; }
static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); }
static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("%s\n", __FILE__); /* */ if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) { int mode = DRM_MODE_DPMS_ON; /* */ exynos_drm_crtc_dpms(crtc, mode); /* */ exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_dpms_from_crtc); } exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, exynos_drm_encoder_crtc_commit); }
static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->atomic_flush) exynos_crtc->ops->atomic_flush(exynos_crtc); }
static void exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->commit) exynos_crtc->ops->commit(exynos_crtc); }
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_private *private = crtc->dev->dev_private; DRM_DEBUG_KMS("%s\n", __FILE__); private->crtc[exynos_crtc->pipe] = NULL;
static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); exynos_plane_commit(exynos_crtc->plane); exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); }
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) { struct drm_device *dev = crtc->dev; struct exynos_drm_private *dev_priv = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_framebuffer *old_fb = crtc->fb; int ret = -EINVAL; DRM_DEBUG_KMS("%s\n", __FILE__); /* when the page flip is requested, crtc's dpms should be on */ if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { DRM_ERROR("failed page flip request.\n"); return -EINVAL; } mutex_lock(&dev->struct_mutex); if (event) { /* * the pipe from user always is 0 so we can set pipe number * of current owner to event. */ event->pipe = exynos_crtc->pipe; ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); goto out; } spin_lock_irq(&dev->event_lock); list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); atomic_set(&exynos_crtc->pending_flip, 1); spin_unlock_irq(&dev->event_lock); crtc->fb = fb; ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, NULL); if (ret) { crtc->fb = old_fb; spin_lock_irq(&dev->event_lock); drm_vblank_put(dev, exynos_crtc->pipe); list_del(&event->base.link); spin_unlock_irq(&dev->event_lock); goto out; } } out: mutex_unlock(&dev->struct_mutex); return ret; }
static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("%s\n", __FILE__); exynos_plane_commit(exynos_crtc->plane); exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); }
static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); DRM_DEBUG_KMS("%s\n", __FILE__); exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); }
static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->enable_vblank) return exynos_crtc->ops->enable_vblank(exynos_crtc); return 0; }
static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); drm_crtc_vblank_off(crtc); if (exynos_crtc->ops->disable) exynos_crtc->ops->disable(exynos_crtc); }
static void exynos_drm_crtc_apply(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_overlay *overlay = &exynos_crtc->overlay; exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_crtc_mode_set); exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, exynos_drm_encoder_crtc_commit); }
static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->mode_valid) return exynos_crtc->ops->mode_valid(exynos_crtc, mode); return MODE_OK; }
static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->enable) exynos_crtc->ops->enable(exynos_crtc); drm_crtc_vblank_on(crtc); }
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) { struct drm_device *dev = crtc->dev; struct exynos_drm_private *dev_priv = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_framebuffer *old_fb = crtc->fb; int ret = -EINVAL; DRM_DEBUG_KMS("%s\n", __FILE__); mutex_lock(&dev->struct_mutex); if (event) { /* */ event->pipe = exynos_crtc->pipe; ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); list_del(&event->base.link); goto out; } list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); crtc->fb = fb; ret = exynos_drm_crtc_update(crtc); if (ret) { crtc->fb = old_fb; drm_vblank_put(dev, exynos_crtc->pipe); list_del(&event->base.link); goto out; } /* */ exynos_drm_crtc_apply(crtc); } out: mutex_unlock(&dev->struct_mutex); return ret; }
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) { struct drm_device *dev = crtc->dev; struct exynos_drm_private *dev_priv = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_framebuffer *old_fb = crtc->fb; int ret = -EINVAL; DRM_DEBUG_KMS("%s\n", __FILE__); mutex_lock(&dev->struct_mutex); if (event) { /* * the pipe from user always is 0 so we can set pipe number * of current owner to event. */ event->pipe = exynos_crtc->pipe; ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); list_del(&event->base.link); goto out; } list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); crtc->fb = fb; ret = exynos_drm_crtc_update(crtc); if (ret) { crtc->fb = old_fb; drm_vblank_put(dev, exynos_crtc->pipe); list_del(&event->base.link); goto out; } /* * the values related to a buffer of the drm framebuffer * to be applied should be set at here. because these values * first, are set to shadow registers and then to * real registers at vsync front porch period. */ exynos_drm_crtc_apply(crtc); } out: mutex_unlock(&dev->struct_mutex); return ret; }
static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (exynos_crtc->ops->mode_fixup) return exynos_crtc->ops->mode_fixup(exynos_crtc, mode, adjusted_mode); return true; }
static int exynos_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); if (!state->enable) return 0; if (exynos_crtc->ops->atomic_check) return exynos_crtc->ops->atomic_check(exynos_crtc, state); return 0; }
int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data, bool enable) { struct exynos_dp_device *dp = to_dp(plat_data); struct drm_encoder *encoder = &dp->encoder; if (!encoder->crtc) return -EPERM; exynos_drm_pipe_clk_enable(to_exynos_crtc(encoder->crtc), enable); return 0; }
static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane; drm_atomic_crtc_for_each_plane(plane, crtc) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); if (exynos_crtc->ops->atomic_flush) exynos_crtc->ops->atomic_flush(exynos_crtc, exynos_plane); } }
static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane; exynos_crtc->event = crtc->state->event; drm_atomic_crtc_for_each_plane(plane, crtc) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); if (exynos_crtc->ops->atomic_begin) exynos_crtc->ops->atomic_begin(exynos_crtc, exynos_plane); } }