/** * komeda_crtc_atomic_check - build display output data flow * @crtc: DRM crtc * @state: the crtc state object * * crtc_atomic_check is the final check stage, so beside build a display data * pipeline according to the crtc_state, but still needs to release or disable * the unclaimed pipeline resources. * * RETURNS: * Zero for success or -errno
*/ staticint
komeda_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
{ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc); struct komeda_crtc *kcrtc = to_kcrtc(crtc); struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_state); int err;
if (drm_atomic_crtc_needs_modeset(crtc_state))
komeda_crtc_update_clock_ratio(kcrtc_st);
if (crtc_state->active) {
err = komeda_build_display_data_flow(kcrtc, kcrtc_st); if (err) return err;
}
err = mdev->funcs->change_opmode(mdev, new_mode); if (err) {
DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n,",
mdev->dpmode, new_mode); goto unlock;
}
mdev->dpmode = new_mode; /* Only need to enable aclk on single display mode, but no need to * enable aclk it on dual display mode, since the dual mode always * switch from single display mode, the aclk already enabled, no need * to enable it again.
*/ if (new_mode != KOMEDA_MODE_DUAL_DISP) {
err = clk_set_rate(mdev->aclk, komeda_crtc_get_aclk(kcrtc_st)); if (err)
DRM_ERROR("failed to set aclk.\n");
err = clk_prepare_enable(mdev->aclk); if (err)
DRM_ERROR("failed to enable aclk.\n");
}
err = clk_set_rate(master->pxlclk, mode->crtc_clock * 1000); if (err)
DRM_ERROR("failed to set pxlclk for pipe%d\n", master->id);
err = clk_prepare_enable(master->pxlclk); if (err)
DRM_ERROR("failed to enable pxl clk for pipe%d.\n", master->id);
if (events & KOMEDA_EVENT_VSYNC)
drm_crtc_handle_vblank(crtc);
if (events & KOMEDA_EVENT_EOW) { struct komeda_wb_connector *wb_conn = kcrtc->wb_conn;
if (wb_conn)
drm_writeback_signal_completion(&wb_conn->base, 0); else
DRM_WARN("CRTC[%d]: EOW happen but no wb_connector.\n",
drm_crtc_index(&kcrtc->base));
} /* will handle it together with the write back support */ if (events & KOMEDA_EVENT_EOW)
DRM_DEBUG("EOW.\n");
if (events & KOMEDA_EVENT_FLIP) { unsignedlong flags; struct drm_pending_vblank_event *event;
spin_lock_irqsave(&crtc->dev->event_lock, flags); if (kcrtc->disable_done) {
complete_all(kcrtc->disable_done);
kcrtc->disable_done = NULL;
} elseif (crtc->state->event) {
event = crtc->state->event; /* * Consume event before notifying drm core that flip * happened.
*/
crtc->state->event = NULL;
drm_crtc_send_vblank_event(crtc, event);
} else {
DRM_WARN("CRTC[%d]: FLIP happened but no pending commit.\n",
drm_crtc_index(&kcrtc->base));
}
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
}
if (slave && has_bit(slave->id, old_st->active_pipes))
komeda_pipeline_disable(slave, old->state);
if (has_bit(master->id, old_st->active_pipes))
needs_phase2 = komeda_pipeline_disable(master, old->state);
/* crtc_disable has two scenarios according to the state->active switch. * 1. active -> inactive * this commit is a disable commit. and the commit will be finished * or done after the disable operation. on this case we can directly * use the crtc->state->event to tracking the HW disable operation. * 2. active -> active * the crtc->commit is not for disable, but a modeset operation when * crtc is active, such commit actually has been completed by 3 * DRM operations: * crtc_disable, update_planes(crtc_flush), crtc_enable * so on this case the crtc->commit is for the whole process. * we can not use it for tracing the disable, we need a temporary * flip_done for tracing the disable. and crtc->state->event for * the crtc_enable operation. * That's also the reason why skip modeset commit in * komeda_crtc_atomic_flush()
*/
disable_done = (needs_phase2 || crtc->state->active) ?
NULL : &crtc->state->commit->flip_done;
staticvoid
komeda_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
{ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc); struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,
crtc); /* commit with modeset will be handled in enable/disable */ if (drm_atomic_crtc_needs_modeset(crtc_state)) return;
komeda_crtc_do_flush(crtc, old);
}
/* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */ staticunsignedlong
komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc, unsignedlong pxlclk)
{ /* Once dual-link one display pipeline drives two display outputs, * the aclk needs run on the double rate of pxlclk
*/ if (kcrtc->master->dual_link) return pxlclk * 2; else return pxlclk;
}
/* Get current aclk rate that specified by state */ unsignedlong komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st)
{ struct drm_crtc *crtc = kcrtc_st->base.crtc; struct komeda_dev *mdev = crtc->dev->dev_private; unsignedlong pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000; unsignedlong min_aclk;
drm_mode_set_crtcinfo(adjusted_mode, 0); /* In dual link half the horizontal settings */ if (kcrtc->master->dual_link) {
adjusted_mode->crtc_clock /= 2;
adjusted_mode->crtc_hdisplay /= 2;
adjusted_mode->crtc_hsync_start /= 2;
adjusted_mode->crtc_hsync_end /= 2;
adjusted_mode->crtc_htotal /= 2;
}
clk_rate = adjusted_mode->crtc_clock * 1000; /* crtc_clock will be used as the komeda output pixel clock */
adjusted_mode->crtc_clock = clk_round_rate(kcrtc->master->pxlclk,
clk_rate) / 1000;
bridge = devm_drm_of_get_bridge(dev, pipe->of_node,
KOMEDA_OF_PORT_OUTPUT, 0); if (IS_ERR(bridge)) return dev_err_probe(dev, PTR_ERR(bridge), "remote bridge not found for pipe: %s\n",
of_node_full_name(pipe->of_node));
err = drm_bridge_attach(encoder, bridge, NULL, 0); if (err)
dev_err(dev, "bridge_attach() failed for pipe: %s\n",
of_node_full_name(pipe->of_node));
/* Construct an encoder for each pipeline and attach it to the remote * bridge
*/
kcrtc->encoder.possible_crtcs = drm_crtc_mask(crtc);
err = drm_simple_encoder_init(base, encoder, DRM_MODE_ENCODER_TMDS); if (err) return err;
if (pipe->of_output_links[0]) {
err = komeda_attach_bridge(base->dev, pipe, encoder); if (err) return err;
}
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.