diff options
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 177 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_plane.c | 24 |
4 files changed, 86 insertions, 139 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 4f03f74685f0..dccd03726796 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -573,6 +573,8 @@ static const char *channel_names[] = { void omap_crtc_pre_init(void) { + memset(omap_crtcs, 0, sizeof(omap_crtcs)); + dss_install_mgr_ops(&mgr_ops); } @@ -583,18 +585,28 @@ void omap_crtc_pre_uninit(void) /* initialize crtc */ struct drm_crtc *omap_crtc_init(struct drm_device *dev, - struct drm_plane *plane, enum omap_channel channel, int id) + struct drm_plane *plane, struct omap_dss_device *dssdev) { struct omap_drm_private *priv = dev->dev_private; struct drm_crtc *crtc = NULL; struct omap_crtc *omap_crtc; + enum omap_channel channel; + struct omap_dss_device *out; int ret; + out = omapdss_find_output_from_display(dssdev); + channel = out->dispc_channel; + omap_dss_put_device(out); + DBG("%s", channel_names[channel]); + /* Multiple displays on same channel is not allowed */ + if (WARN_ON(omap_crtcs[channel] != NULL)) + return ERR_PTR(-EINVAL); + omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); if (!omap_crtc) - return NULL; + return ERR_PTR(-ENOMEM); crtc = &omap_crtc->base; @@ -606,8 +618,10 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &omap_crtc_funcs, NULL); if (ret < 0) { + dev_err(dev->dev, "%s(): could not init crtc for: %s\n", + __func__, dssdev->name); kfree(omap_crtc); - return NULL; + return ERR_PTR(ret); } drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index a8927cfebdac..e1f47f0b3ccf 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -219,20 +219,6 @@ static int get_connector_type(struct omap_dss_device *dssdev) } } -static bool channel_used(struct drm_device *dev, enum omap_channel channel) -{ - struct omap_drm_private *priv = dev->dev_private; - int i; - - for (i = 0; i < priv->num_crtcs; i++) { - struct drm_crtc *crtc = priv->crtcs[i]; - - if (omap_crtc_channel(crtc) == channel) - return true; - } - - return false; -} static void omap_disconnect_dssdevs(void) { struct omap_dss_device *dssdev = NULL; @@ -272,31 +258,6 @@ cleanup: return r; } -static int omap_modeset_create_crtc(struct drm_device *dev, int id, - enum omap_channel channel, - u32 possible_crtcs) -{ - struct omap_drm_private *priv = dev->dev_private; - struct drm_plane *plane; - struct drm_crtc *crtc; - - plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY, - possible_crtcs); - if (IS_ERR(plane)) - return PTR_ERR(plane); - - crtc = omap_crtc_init(dev, plane, channel, id); - - BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); - priv->crtcs[id] = crtc; - priv->num_crtcs++; - - priv->planes[id] = plane; - priv->num_planes++; - - return 0; -} - static int omap_modeset_init_properties(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; @@ -314,10 +275,9 @@ static int omap_modeset_init(struct drm_device *dev) struct omap_dss_device *dssdev = NULL; int num_ovls = priv->dispc_ops->get_num_ovls(); int num_mgrs = priv->dispc_ops->get_num_mgrs(); - int num_crtcs = 0; - int i, id = 0; + int num_crtcs, crtc_idx, plane_idx; int ret; - u32 possible_crtcs; + u32 plane_crtc_mask; drm_mode_config_init(dev); @@ -326,134 +286,91 @@ static int omap_modeset_init(struct drm_device *dev) return ret; /* - * Let's create one CRTC for each connected DSS device if we - * have display managers and overlays (for primary planes) for - * them. + * This function creates exactly one connector, encoder, crtc, + * and primary plane per each connected dss-device. Each + * connector->encoder->crtc chain is expected to be separate + * and each crtc is connect to a single dss-channel. If the + * configuration does not match the expectations or exceeds + * the available resources, the configuration is rejected. */ + num_crtcs = 0; for_each_dss_dev(dssdev) if (omapdss_device_is_connected(dssdev)) num_crtcs++; - num_crtcs = min3(num_crtcs, num_mgrs, num_ovls); - possible_crtcs = (1 << num_crtcs) - 1; + if (num_crtcs > num_mgrs || num_crtcs > num_ovls || + num_crtcs > ARRAY_SIZE(priv->crtcs) || + num_crtcs > ARRAY_SIZE(priv->planes) || + num_crtcs > ARRAY_SIZE(priv->encoders) || + num_crtcs > ARRAY_SIZE(priv->connectors)) { + dev_err(dev->dev, "%s(): Too many connected displays\n", + __func__); + return -EINVAL; + } + + /* All planes can be put to any CRTC */ + plane_crtc_mask = (1 << num_crtcs) - 1; dssdev = NULL; + crtc_idx = 0; + plane_idx = 0; for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; - enum omap_channel channel; - struct omap_dss_device *out; + struct drm_plane *plane; + struct drm_crtc *crtc; if (!omapdss_device_is_connected(dssdev)) continue; encoder = omap_encoder_init(dev, dssdev); - - if (!encoder) { - dev_err(dev->dev, "could not create encoder: %s\n", - dssdev->name); + if (!encoder) return -ENOMEM; - } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); - - if (!connector) { - dev_err(dev->dev, "could not create connector: %s\n", - dssdev->name); + if (!connector) return -ENOMEM; - } - BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); - BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); + plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY, + plane_crtc_mask); + if (IS_ERR(plane)) + return PTR_ERR(plane); - priv->encoders[priv->num_encoders++] = encoder; - priv->connectors[priv->num_connectors++] = connector; + crtc = omap_crtc_init(dev, plane, dssdev); + if (IS_ERR(crtc)) + return PTR_ERR(crtc); drm_mode_connector_attach_encoder(connector, encoder); + encoder->possible_crtcs = (1 << crtc_idx); - /* - * if we have reached the limit of the crtcs we can - * create, let's not try to create a crtc for this - * panel/encoder and onwards. - */ - if (id == num_crtcs) - continue; + priv->crtcs[priv->num_crtcs++] = crtc; + priv->planes[priv->num_planes++] = plane; + priv->encoders[priv->num_encoders++] = encoder; + priv->connectors[priv->num_connectors++] = connector; - /* - * get the recommended DISPC channel for this encoder. For now, - * we only try to get create a crtc out of the recommended, the - * other possible channels to which the encoder can connect are - * not considered. - */ - - out = omapdss_find_output_from_display(dssdev); - channel = out->dispc_channel; - omap_dss_put_device(out); - - /* - * if this channel hasn't already been taken by a previously - * allocated crtc, we create a new crtc for it - */ - if (!channel_used(dev, channel)) { - ret = omap_modeset_create_crtc(dev, id, channel, - possible_crtcs); - if (ret < 0) { - dev_err(dev->dev, - "could not create CRTC (channel %u)\n", - channel); - return ret; - } - - id++; - } + plane_idx++; + crtc_idx++; } /* * Create normal planes for the remaining overlays: */ - for (; id < num_ovls; id++) { + for (; plane_idx < num_ovls; plane_idx++) { struct drm_plane *plane; - plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY, - possible_crtcs); + if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes))) + return -EINVAL; + + plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY, + plane_crtc_mask); if (IS_ERR(plane)) return PTR_ERR(plane); - BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; } - /* - * populate the the possible_crtcs field for all the encoders - * we created. - */ - for (i = 0; i < priv->num_encoders; i++) { - struct drm_encoder *encoder = priv->encoders[i]; - struct omap_dss_device *dssdev = - omap_encoder_get_dssdev(encoder); - struct omap_dss_device *output; - - output = omapdss_find_output_from_display(dssdev); - - /* figure out which crtc's we can connect the encoder to: */ - encoder->possible_crtcs = 0; - for (id = 0; id < priv->num_crtcs; id++) { - struct drm_crtc *crtc = priv->crtcs[id]; - enum omap_channel crtc_channel; - - crtc_channel = omap_crtc_channel(crtc); - - if (output->dispc_channel == crtc_channel) { - encoder->possible_crtcs |= (1 << id); - break; - } - } - - omap_dss_put_device(output); - } - DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", priv->num_planes, priv->num_crtcs, priv->num_encoders, priv->num_connectors); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 3cb7bf259670..7a4c57eb6536 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -137,13 +137,13 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); void omap_crtc_pre_init(void); void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, - struct drm_plane *plane, enum omap_channel channel, int id); + struct drm_plane *plane, struct omap_dss_device *dssdev); int omap_crtc_wait_pending(struct drm_crtc *crtc); void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); void omap_crtc_vblank_irq(struct drm_crtc *crtc); struct drm_plane *omap_plane_init(struct drm_device *dev, - int id, enum drm_plane_type type, + int idx, enum drm_plane_type type, u32 possible_crtcs); void omap_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 7abb49b7d606..9168154d749e 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -324,24 +324,37 @@ static const struct drm_plane_funcs omap_plane_funcs = { .atomic_get_property = omap_plane_atomic_get_property, }; -static const char *plane_names[] = { +static const char *plane_id_to_name[] = { [OMAP_DSS_GFX] = "gfx", [OMAP_DSS_VIDEO1] = "vid1", [OMAP_DSS_VIDEO2] = "vid2", [OMAP_DSS_VIDEO3] = "vid3", }; +static const enum omap_plane_id plane_idx_to_id[] = { + OMAP_DSS_GFX, + OMAP_DSS_VIDEO1, + OMAP_DSS_VIDEO2, + OMAP_DSS_VIDEO3, +}; + /* initialize plane */ struct drm_plane *omap_plane_init(struct drm_device *dev, - int id, enum drm_plane_type type, + int idx, enum drm_plane_type type, u32 possible_crtcs) { struct omap_drm_private *priv = dev->dev_private; struct drm_plane *plane; struct omap_plane *omap_plane; + enum omap_plane_id id; int ret; - DBG("%s: type=%d", plane_names[id], type); + if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id))) + return ERR_PTR(-EINVAL); + + id = plane_idx_to_id[idx]; + + DBG("%s: type=%d", plane_id_to_name[id], type); omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); if (!omap_plane) @@ -351,7 +364,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, omap_plane->formats, ARRAY_SIZE(omap_plane->formats), priv->dispc_ops->ovl_get_color_modes(id)); omap_plane->id = id; - omap_plane->name = plane_names[id]; + omap_plane->name = plane_id_to_name[id]; plane = &omap_plane->base; @@ -368,6 +381,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, return plane; error: + dev_err(dev->dev, "%s(): could not create plane: %s\n", + __func__, plane_id_to_name[id]); + kfree(omap_plane); return NULL; } |