if (!old_state->fb ||
old_state->fb->format->format != new_state->fb->format->format)
format_changed = true;
/* * If the format has changed (including going from a previously * disabled state to any format), reconfigure the format. Disable the * plane first if needed.
*/ if (format_changed) { if (old_state->fb)
zynqmp_disp_layer_disable(layer);
if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
plane->state->alpha >> 8);
/* * Unconditionally enable the layer, as it may have been disabled * previously either explicitly to reconfigure layer format, or * implicitly after DPSUB reset during display mode change. DRM * framework calls this callback for enabled planes only.
*/
zynqmp_disp_layer_enable(layer);
}
staticint zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub)
{ unsignedint i; int ret;
for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++) { struct zynqmp_disp_layer *layer = dpsub->layers[i]; struct drm_plane *plane = &dpsub->drm->planes[i]; enum drm_plane_type type; unsignedint num_formats;
u32 *formats;
formats = zynqmp_disp_layer_drm_formats(layer, &num_formats); if (!formats) return -ENOMEM;
/* Graphics layer is primary, and video layer is overlay. */
type = i == ZYNQMP_DPSUB_LAYER_VID
? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
ret = drm_universal_plane_init(&dpsub->drm->dev, plane, 0,
&zynqmp_dpsub_plane_funcs,
formats, num_formats,
NULL, type, NULL);
kfree(formats); if (ret) return ret;
ret = clk_prepare_enable(dpsub->vid_clk); if (ret) {
dev_err(dpsub->dev, "failed to enable a pixel clock\n");
pm_runtime_put_sync(dpsub->dev); return;
}
zynqmp_disp_enable(dpsub->disp);
/* Delay of 3 vblank intervals for timing gen to be stable */
vrefresh = (adjusted_mode->clock * 1000) /
(adjusted_mode->vtotal * adjusted_mode->htotal);
msleep(3 * 1000 / vrefresh);
}
/* * Disable the plane if active. The old plane state can be NULL in the * .shutdown() path if the plane is already disabled, skip * zynqmp_disp_plane_atomic_disable() in that case.
*/
old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary); if (old_plane_state)
zynqmp_dpsub_plane_atomic_disable(crtc->primary, state);
for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++)
dpsub->drm->planes[i].possible_crtcs = possible_crtcs;
}
/** * zynqmp_dpsub_drm_handle_vblank - Handle the vblank event * @dpsub: DisplayPort subsystem * * This function handles the vblank interrupt, and sends an event to * CRTC object. This will be called by the DP vblank interrupt handler.
*/ void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub)
{
drm_crtc_handle_vblank(&dpsub->drm->crtc);
}
/* Enforce the alignment constraints of the DMA engine. */ for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
/* Create the planes and the CRTC. */
ret = zynqmp_dpsub_create_planes(dpsub); if (ret) return ret;
ret = zynqmp_dpsub_create_crtc(dpsub); if (ret < 0) return ret;
zynqmp_dpsub_map_crtc_to_plane(dpsub);
/* Create the encoder and attach the bridge. */
encoder->possible_crtcs |= drm_crtc_mask(&dpsub->drm->crtc);
drm_simple_encoder_init(&dpsub->drm->dev, encoder, DRM_MODE_ENCODER_NONE);
ret = drm_bridge_attach(encoder, dpsub->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) {
dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); goto err_encoder;
}
/* Create the connector for the chain of bridges. */
connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder); if (IS_ERR(connector)) {
dev_err(dpsub->dev, "failed to created connector\n");
ret = PTR_ERR(connector); goto err_encoder;
}
ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) {
dev_err(dpsub->dev, "failed to attach connector to encoder\n"); goto err_encoder;
}
int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
{ struct zynqmp_dpsub_drm *dpdrm; struct drm_device *drm; int ret;
/* * Allocate the drm_device and immediately add a cleanup action to * release the zynqmp_dpsub instance. If any of those operations fail, * dpsub->drm will remain NULL, which tells the caller that it must * cleanup manually.
*/
dpdrm = devm_drm_dev_alloc(dpsub->dev, &zynqmp_dpsub_drm_driver, struct zynqmp_dpsub_drm, dev); if (IS_ERR(dpdrm)) return PTR_ERR(dpdrm);
dpdrm->dpsub = dpsub;
drm = &dpdrm->dev;
ret = drmm_add_action(drm, zynqmp_dpsub_drm_release, dpdrm); if (ret < 0) return ret;
dpsub->drm = dpdrm;
/* Initialize mode config, vblank and the KMS poll helper. */
ret = drmm_mode_config_init(drm); if (ret < 0) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.