/** * drm_atomic_get_crtc_state - get crtc state * @state: global atomic state object * @crtc: crtc to get state object for * * This function returns the crtc state for the given crtc, allocating it if * needed. It will also grab the relevant crtc lock to make sure that the state * is consistent. * * Returns: * * Either the allocated state or the error code encoded into the pointer. When * the error is EDEADLK then the w/w mutex code has detected a deadlock and the * entire atomic sequence must be restarted. All other errors are fatal. */ struct drm_crtc_state * drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc) { int ret, index = drm_crtc_index(crtc); struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (crtc_state) return crtc_state; ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); if (ret) return ERR_PTR(ret); crtc_state = crtc->funcs->atomic_duplicate_state(crtc); if (!crtc_state) return ERR_PTR(-ENOMEM); state->crtc_states[index] = crtc_state; state->crtcs[index] = crtc; crtc_state->state = state; DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n", crtc->base.id, crtc_state, state); return crtc_state; }
int malidp_mw_connector_init(struct drm_device *drm) { struct malidp_drm *malidp = drm->dev_private; u32 *formats; int ret, n_formats; if (!malidp->dev->hw->enable_memwrite) return 0; malidp->mw_connector.encoder.possible_crtcs = 1 << drm_crtc_index(&malidp->crtc); drm_connector_helper_add(&malidp->mw_connector.base, &malidp_mw_connector_helper_funcs); formats = get_writeback_formats(malidp, &n_formats); if (!formats) return -ENOMEM; ret = drm_writeback_connector_init(drm, &malidp->mw_connector, &malidp_mw_connector_funcs, &malidp_mw_encoder_helper_funcs, formats, n_formats); kfree(formats); if (ret) return ret; return 0; }
static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *plane) { struct kirin_drm_private *priv = dev->dev_private; struct device_node *port; int ret; /* set crtc port so that * drm_of_find_possible_crtcs call works */ port = of_get_child_by_name(dev->dev->of_node, "port"); if (!port) { DRM_ERROR("no port node found in %s\n", dev->dev->of_node->full_name); return -EINVAL; } of_node_put(port); crtc->port = port; ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &ade_crtc_funcs, NULL); if (ret) { DRM_ERROR("failed to init crtc.\n"); return ret; } drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); priv->crtc[drm_crtc_index(crtc)] = crtc; return 0; }
static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc) { struct rockchip_drm_private *priv = crtc->dev->dev_private; int pipe = drm_crtc_index(crtc); const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe]; if (crtc_funcs && crtc_funcs->wait_for_update) crtc_funcs->wait_for_update(crtc); }
void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc) { int pipe = drm_crtc_index(crtc); struct rockchip_drm_private *priv = crtc->dev->dev_private; if (pipe > ROCKCHIP_MAX_CRTC) return; priv->crtc_funcs[pipe] = NULL; }
int rockchip_register_crtc_funcs(struct drm_crtc *crtc, const struct rockchip_crtc_funcs *crtc_funcs) { int pipe = drm_crtc_index(crtc); struct rockchip_drm_private *priv = crtc->dev->dev_private; if (pipe > ROCKCHIP_MAX_CRTC) return -EINVAL; priv->crtc_funcs[pipe] = crtc_funcs; return 0; }
static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; struct drm_connector *con = &fsl_dev->connector.base; struct drm_display_mode *mode = &crtc->state->mode; unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0; index = drm_crtc_index(crtc); clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000); /* Configure timings: */ hbp = mode->htotal - mode->hsync_end; hfp = mode->hsync_start - mode->hdisplay; hsw = mode->hsync_end - mode->hsync_start; vbp = mode->vtotal - mode->vsync_end; vfp = mode->vsync_start - mode->vdisplay; vsw = mode->vsync_end - mode->vsync_start; /* INV_PXCK as default (most display sample data on rising edge) */ if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)) pol |= DCU_SYN_POL_INV_PXCK; if (mode->flags & DRM_MODE_FLAG_NHSYNC) pol |= DCU_SYN_POL_INV_HS_LOW; if (mode->flags & DRM_MODE_FLAG_NVSYNC) pol |= DCU_SYN_POL_INV_VS_LOW; regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, DCU_HSYN_PARA_BP(hbp) | DCU_HSYN_PARA_PW(hsw) | DCU_HSYN_PARA_FP(hfp)); regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, DCU_VSYN_PARA_BP(vbp) | DCU_VSYN_PARA_PW(vsw) | DCU_VSYN_PARA_FP(vfp)); regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol); regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0)); regmap_write(fsl_dev->regmap, DCU_DCU_MODE, DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); regmap_write(fsl_dev->regmap, DCU_THRESHOLD, DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); return; }
static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc); unsigned long flags; if (crtc->state->event) { struct drm_pending_vblank_event *event = crtc->state->event; crtc->state->event = NULL; event->pipe = drm_crtc_index(crtc); WARN_ON(drm_crtc_vblank_get(crtc) != 0); spin_lock_irqsave(&crtc->dev->event_lock, flags); list_add_tail(&event->base.link, &arcpgu->event_list); spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } }
/** * intel_enable_shared_dpll - enable PCH PLL * @dev_priv: i915 private structure * @pipe: pipe PLL to enable * * The PCH PLL needs to be enabled before the PCH transcoder, since it * drives the transcoder clock. */ void intel_enable_shared_dpll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_shared_dpll *pll = crtc->config->shared_dpll; unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); unsigned old_mask; if (WARN_ON(pll == NULL)) return; mutex_lock(&dev_priv->dpll_lock); old_mask = pll->active_mask; if (WARN_ON(!(pll->config.crtc_mask & crtc_mask)) || WARN_ON(pll->active_mask & crtc_mask)) goto out; pll->active_mask |= crtc_mask; DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n", pll->name, pll->active_mask, pll->on, crtc->base.base.id); if (old_mask) { WARN_ON(!pll->on); assert_shared_dpll_enabled(dev_priv, pll); goto out; } WARN_ON(pll->on); DRM_DEBUG_KMS("enabling %s\n", pll->name); pll->funcs.enable(dev_priv, pll); pll->on = true; out: mutex_unlock(&dev_priv->dpll_lock); }
void intel_disable_shared_dpll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_shared_dpll *pll = crtc->config->shared_dpll; unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); /* PCH only available on ILK+ */ if (INTEL_INFO(dev)->gen < 5) return; if (pll == NULL) return; mutex_lock(&dev_priv->dpll_lock); if (WARN_ON(!(pll->active_mask & crtc_mask))) goto out; DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n", pll->name, pll->active_mask, pll->on, crtc->base.base.id); assert_shared_dpll_enabled(dev_priv, pll); WARN_ON(!pll->on); pll->active_mask &= ~crtc_mask; if (pll->active_mask) goto out; DRM_DEBUG_KMS("disabling %s\n", pll->name); pll->funcs.disable(dev_priv, pll); pll->on = false; out: mutex_unlock(&dev_priv->dpll_lock); }
static void rcar_lvds_enable(struct drm_bridge *bridge) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); const struct drm_display_mode *mode = &lvds->display_mode; /* * FIXME: We should really retrieve the CRTC through the state, but how * do we get a state pointer? */ struct drm_crtc *crtc = lvds->bridge.encoder->crtc; u32 lvdpllcr; u32 lvdhcr; u32 lvdcr0; int ret; WARN_ON(lvds->enabled); ret = clk_prepare_enable(lvds->clock); if (ret < 0) return; /* * Hardcode the channels and control signals routing for now. * * HSYNC -> CTRL0 * VSYNC -> CTRL1 * DISP -> CTRL2 * 0 -> CTRL3 */ rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO | LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC | LVDCTRCR_CTR0SEL_HSYNC); if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES) lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1); else lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3); rcar_lvds_write(lvds, LVDCHCR, lvdhcr); /* PLL clock configuration. */ if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN2_PLLCR) lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock); else lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock); rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr); /* Set the LVDS mode and select the input. */ lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT; if (drm_crtc_index(crtc) == 2) lvdcr0 |= LVDCR0_DUSEL; rcar_lvds_write(lvds, LVDCR0, lvdcr0); /* Turn all the channels on. */ rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY); if (lvds->info->gen < 3) { /* Enable LVDS operation and turn the bias circuitry on. */ lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN; rcar_lvds_write(lvds, LVDCR0, lvdcr0); } /* Turn the PLL on. */ lvdcr0 |= LVDCR0_PLLON; rcar_lvds_write(lvds, LVDCR0, lvdcr0); if (lvds->info->gen > 2) { /* Set LVDS normal mode. */ lvdcr0 |= LVDCR0_PWD; rcar_lvds_write(lvds, LVDCR0, lvdcr0); } if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { /* Turn on the LVDS PHY. */ lvdcr0 |= LVDCR0_LVEN; rcar_lvds_write(lvds, LVDCR0, lvdcr0); } /* Wait for the startup delay. */ usleep_range(100, 150); /* Turn the output on. */ lvdcr0 |= LVDCR0_LVRES; rcar_lvds_write(lvds, LVDCR0, lvdcr0); if (lvds->panel) { drm_panel_prepare(lvds->panel); drm_panel_enable(lvds->panel); } lvds->enabled = true; }
/** * drm_atomic_helper_commit - commit validated state object * @dev: DRM device * @state: the driver state object * @nonblock: nonblocking commit * * This function commits a with drm_atomic_helper_check() pre-validated state * object. This can still fail when e.g. the framebuffer reservation fails. * * RETURNS * Zero for success or -errno. */ int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { struct msm_drm_private *priv = dev->dev_private; int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; struct msm_commit *c; int i, ret; ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; c = commit_init(state); if (!c) { ret = -ENOMEM; goto error; } /* * Figure out what crtcs we have: */ for (i = 0; i < ncrtcs; i++) { struct drm_crtc *crtc = state->crtcs[i]; if (!crtc) continue; c->crtc_mask |= (1 << drm_crtc_index(crtc)); } /* * Figure out what fence to wait for: */ for (i = 0; i < nplanes; i++) { struct drm_plane *plane = state->planes[i]; struct drm_plane_state *new_state = state->plane_states[i]; if (!plane) continue; if ((plane->state->fb != new_state->fb) && new_state->fb) { struct drm_gem_object *obj = msm_framebuffer_bo(new_state->fb, 0); struct msm_gem_object *msm_obj = to_msm_bo(obj); new_state->fence = reservation_object_get_excl_rcu(msm_obj->resv); } } /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: */ ret = start_atomic(dev->dev_private, c->crtc_mask); if (ret) { kfree(c); goto error; } /* * This is the point of no return - everything below never fails except * when the hw goes bonghits. Which means we can commit the new state on * the software side now. */ drm_atomic_helper_swap_state(dev, state); /* * Everything below can be run asynchronously without the need to grab * any modeset locks at all under one conditions: It must be guaranteed * that the asynchronous work has either been cancelled (if the driver * supports it, which at least requires that the framebuffers get * cleaned up with drm_atomic_helper_cleanup_planes()) or completed * before the new state gets committed on the software side with * drm_atomic_helper_swap_state(). * * This scheme allows new atomic state updates to be prepared and * checked in parallel to the asynchronous completion of the previous * update. Which is important since compositors need to figure out the * composition of the next frame right after having submitted the * current layout. */ if (nonblock) { queue_work(priv->atomic_wq, &c->work); return 0; } complete_commit(c, false); return 0; error: drm_atomic_helper_cleanup_planes(dev, state); return ret; }
/** * drm_atomic_helper_commit - commit validated state object * @dev: DRM device * @state: the driver state object * @async: asynchronous commit * * This function commits a with drm_atomic_helper_check() pre-validated state * object. This can still fail when e.g. the framebuffer reservation fails. For * now this doesn't implement asynchronous commits. * * RETURNS * Zero for success or -errno. */ int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; struct msm_commit *c; int i, ret; ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; c = new_commit(state); if (!c) return -ENOMEM; /* * Figure out what crtcs we have: */ for (i = 0; i < ncrtcs; i++) { struct drm_crtc *crtc = state->crtcs[i]; if (!crtc) continue; c->crtc_mask |= (1 << drm_crtc_index(crtc)); } /* * Figure out what fence to wait for: */ for (i = 0; i < nplanes; i++) { struct drm_plane *plane = state->planes[i]; struct drm_plane_state *new_state = state->plane_states[i]; if (!plane) continue; if ((plane->state->fb != new_state->fb) && new_state->fb) add_fb(c, new_state->fb); } /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: */ ret = start_atomic(dev->dev_private, c->crtc_mask); if (ret) return ret; /* * This is the point of no return - everything below never fails except * when the hw goes bonghits. Which means we can commit the new state on * the software side now. */ drm_atomic_helper_swap_state(dev, state); /* * Everything below can be run asynchronously without the need to grab * any modeset locks at all under one conditions: It must be guaranteed * that the asynchronous work has either been cancelled (if the driver * supports it, which at least requires that the framebuffers get * cleaned up with drm_atomic_helper_cleanup_planes()) or completed * before the new state gets committed on the software side with * drm_atomic_helper_swap_state(). * * This scheme allows new atomic state updates to be prepared and * checked in parallel to the asynchronous completion of the previous * update. Which is important since compositors need to figure out the * composition of the next frame right after having submitted the * current layout. */ if (async) { msm_queue_fence_cb(dev, &c->fence_cb, c->fence); return 0; } ret = msm_wait_fence_interruptable(dev, c->fence, NULL); if (ret) { WARN_ON(ret); // TODO unswap state back? or?? kfree(c); return ret; } complete_commit(c); return 0; }
static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; struct drm_display_mode *mode = &crtc->state->mode; unsigned int hbp, hfp, hsw, vbp, vfp, vsw, div, index; unsigned long dcuclk; int ret; index = drm_crtc_index(crtc); dcuclk = clk_get_rate(fsl_dev->clk); div = dcuclk / mode->clock / 1000; /* Configure timings: */ hbp = mode->htotal - mode->hsync_end; hfp = mode->hsync_start - mode->hdisplay; hsw = mode->hsync_end - mode->hsync_start; vbp = mode->vtotal - mode->vsync_end; vfp = mode->vsync_start - mode->vdisplay; vsw = mode->vsync_end - mode->vsync_start; ret = regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, DCU_HSYN_PARA_BP(hbp) | DCU_HSYN_PARA_PW(hsw) | DCU_HSYN_PARA_FP(hfp)); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, DCU_VSYN_PARA_BP(vbp) | DCU_VSYN_PARA_PW(vsw) | DCU_VSYN_PARA_FP(vfp)); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_SYN_POL, DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0)); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_DCU_MODE, DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_THRESHOLD, DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); if (ret) goto set_failed; ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); if (ret) goto set_failed; return; set_failed: dev_err(dev->dev, "set DCU register failed\n"); }