[PATCH] drm/omap: use omapdss low level API
Rob Clark
robdclark at gmail.com
Fri Nov 16 05:59:04 PST 2012
On Fri, Nov 16, 2012 at 12:44 AM, Archit Taneja <archit at ti.com> wrote:
> On Friday 16 November 2012 05:30 AM, Rob Clark wrote:
>>
>> +static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
>> + const struct dss_lcd_mgr_config *config)
>> +{
>> + struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc,
>> mgr);
>> + DBG("%s", omap_crtc->name);
>> + dispc_mgr_set_lcd_config(omap_crtc->channel, config);
>
>
> Maybe you should move this dispc write also to omap_crtc_pre_apply, the same
> way it's done for timings. We'll also be confident about having the clocks
> required if this is called in pre_apply.
>
That was the first thing I had tried, although the order doesn't
really work out well and lcd config ends up getting set on the n+1'th
apply. Currently this is only called indirectly from
omap_encoder_set_enabled() -> dssdrv->enable() which always happens on
apply worker. In fact no dispc or dssdev fxn that changes state is
called outside of apply worker. (Only things like detect and reading
edid are happening outside of apply worker.)
When we get to the point of having more sophisticated panel drivers,
these callbacks from the panel are probably going to need some sort of
if (is_in_apply_worker()) sort of check.
>> +static void apply_worker(struct work_struct *work)
>> +{
>> + struct omap_crtc *omap_crtc =
>> + container_of(work, struct omap_crtc, apply_work);
>> + struct drm_crtc *crtc = &omap_crtc->base;
>> + struct drm_device *dev = crtc->dev;
>> + struct omap_drm_apply *apply, *n;
>> + bool need_apply;
>> +
>> + /*
>> + * Synchronize everything on mode_config.mutex, to keep
>> + * the callbacks and list modification all serialized
>> + * with respect to modesetting ioctls from userspace.
>> + */
>> + mutex_lock(&dev->mode_config.mutex);
>> + dispc_runtime_get();
>> +
>> + /*
>> + * If we are still pending a previous update, wait.. when the
>> + * pending update completes, we get kicked again.
>> + */
>> + if (omap_crtc->apply_irq.registered)
>> + goto out;
>> +
>> + /* finish up previous apply's: */
>> + list_for_each_entry_safe(apply, n,
>> + &omap_crtc->pending_applies, pending_node) {
>> + apply->post_apply(apply);
>> + list_del(&apply->pending_node);
>> + }
>> +
>> + need_apply = !list_empty(&omap_crtc->queued_applies);
>> +
>> + /* then handle the next round of of queued apply's: */
>> + list_for_each_entry_safe(apply, n,
>> + &omap_crtc->queued_applies, queued_node) {
>> + apply->pre_apply(apply);
>> + list_del(&apply->queued_node);
>> + apply->queued = false;
>> + list_add_tail(&apply->pending_node,
>> + &omap_crtc->pending_applies);
>> + }
>> +
>> + if (need_apply) {
>> + enum omap_channel channel = omap_crtc->channel;
>> +
>> + DBG("%s: GO", omap_crtc->name);
>> +
>> + if (dispc_mgr_is_enabled(channel)) {
>> + omap_irq_register(dev, &omap_crtc->apply_irq);
>> + dispc_mgr_go(channel);
>> + } else if (!dispc_mgr_go_busy(channel)) {
>
>
> I'm not clear about this. Why would GO be set in the first place if the
> manager isn't enabled? This could be replaced with a simple 'else'
>
Yeah, that extra if should be redundant
>
>> +static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
>> +{
>> + struct omap_crtc *omap_crtc =
>> + container_of(apply, struct omap_crtc, apply);
>> + struct drm_crtc *crtc = &omap_crtc->base;
>> + struct drm_encoder *encoder = NULL;
>> +
>> + DBG("%s: enabled=%d, full=%d", omap_crtc->name,
>> + omap_crtc->enabled, omap_crtc->full_update);
>> +
>> + if (omap_crtc->full_update) {
>
>
> If I get it right, full_update refers to manager properties that previously
> used to propogate downstream from the output driver to dispc, i.e, things
> like timings and so on. and the ones which aren't full_update are upstream
> properties like transparency keys, default_color and so on?
>
Well, it basically means power or timings have changed. So it means
closer to "full modeset" vs "pageflip".
But this function does deal with one mismatch between DRM and DSS.. in
DRM, everything gets setup in crtc -> downstream order, whereas
omapdss to accommodate more sophisticated panels does things in the
reverse order. So the crtc here propagates timing/power state change
to the encoder (which may turn into mgr op callbacks), rather than
relying on the encoder-helper fxn ptrs called from KMS.
And in fact other DRM drivers will need the same thing eventually if
they are to support the common panel/display framework. So I think
eventually a new / alternate set of crtc helpers (at least
drm_crtc_helper_set_{config,mode})()) will be needed. But I think it
would be easier to introduce after the atomic modeset changes.
>
>>
>> -static int omap_modeset_init(struct drm_device *dev)
>> -{
>> - const struct omap_drm_platform_data *pdata =
>> dev->dev->platform_data;
>> - struct omap_kms_platform_data *kms_pdata = NULL;
>> - struct omap_drm_private *priv = dev->dev_private;
>> - struct omap_dss_device *dssdev = NULL;
>> - int i, j;
>> - unsigned int connected_connectors = 0;
>> + encoder = omap_encoder_init(dev, dssdev);
>>
>> - drm_mode_config_init(dev);
>> -
>> - if (pdata && pdata->kms_pdata) {
>> - kms_pdata = pdata->kms_pdata;
>> -
>> - /* if platform data is provided by the board file, use it
>> to
>> - * control which overlays, managers, and devices we own.
>> - */
>> - for (i = 0; i < kms_pdata->mgr_cnt; i++) {
>> - struct omap_overlay_manager *mgr =
>> - omap_dss_get_overlay_manager(
>> - kms_pdata->mgr_ids[i]);
>> - create_encoder(dev, mgr);
>> - }
>> -
>> - for (i = 0; i < kms_pdata->dev_cnt; i++) {
>> - struct omap_dss_device *dssdev =
>> - omap_dss_find_device(
>> - (void *)kms_pdata->dev_names[i],
>> - match_dev_name);
>> - if (!dssdev) {
>> - dev_warn(dev->dev, "no such dssdev: %s\n",
>> - kms_pdata->dev_names[i]);
>> - continue;
>> - }
>> - create_connector(dev, dssdev);
>> + if (!encoder) {
>> + dev_err(dev->dev, "could not create encoder:
>> %s\n",
>> + dssdev->name);
>> + return -ENOMEM;
>> }
>>
>> - connected_connectors = detect_connectors(dev);
>> + connector = omap_connector_init(dev,
>> + get_connector_type(dssdev), dssdev,
>> encoder);
>>
>> - j = 0;
>> - for (i = 0; i < kms_pdata->ovl_cnt; i++) {
>> - struct omap_overlay *ovl =
>> -
>> omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
>> - create_crtc(dev, ovl, &j, connected_connectors);
>> + if (!connector) {
>> + dev_err(dev->dev, "could not create connector:
>> %s\n",
>> + dssdev->name);
>> + return -ENOMEM;
>> }
>>
>> - for (i = 0; i < kms_pdata->pln_cnt; i++) {
>> - struct omap_overlay *ovl =
>> -
>> omap_dss_get_overlay(kms_pdata->pln_ids[i]);
>> - create_plane(dev, ovl, (1 << priv->num_crtcs) -
>> 1);
>> - }
>> - } else {
>> - /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and
>> try
>> - * to make educated guesses about everything else
>> - */
>> - int max_overlays = min(omap_dss_get_num_overlays(),
>> num_crtc);
>> + BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders));
>> + BUG_ON(priv->num_connectors >=
>> ARRAY_SIZE(priv->connectors));
>>
>> - for (i = 0; i < omap_dss_get_num_overlay_managers(); i++)
>> - create_encoder(dev,
>> omap_dss_get_overlay_manager(i));
>> -
>> - for_each_dss_dev(dssdev) {
>> - create_connector(dev, dssdev);
>> - }
>> + priv->encoders[priv->num_encoders++] = encoder;
>> + priv->connectors[priv->num_connectors++] = connector;
>>
>> - connected_connectors = detect_connectors(dev);
>> + drm_mode_connector_attach_encoder(connector, encoder);
>>
>> - j = 0;
>> - for (i = 0; i < max_overlays; i++) {
>> - create_crtc(dev, omap_dss_get_overlay(i),
>> - &j, connected_connectors);
>> - }
>> -
>> - /* use any remaining overlays as drm planes */
>> - for (; i < omap_dss_get_num_overlays(); i++) {
>> - struct omap_overlay *ovl =
>> omap_dss_get_overlay(i);
>> - create_plane(dev, ovl, (1 << priv->num_crtcs) -
>> 1);
>> + /* figure out which crtc's we can connect the encoder to:
>> */
>> + encoder->possible_crtcs = 0;
>> + for (id = 0; id < priv->num_crtcs; id++) {
>> + enum omap_display_type supported_displays =
>> +
>> dss_feat_get_supported_displays(pipe2chan(id));
>
>
> We could use the newer version here: dss_feat_get_supported_outputs(), this
> will tell what all outputs a manager can connect to.
ok, I guess I started on this before that fxn existed
BR,
-R
More information about the dri-devel
mailing list