Commit e8e13b15 authored by Jyri Sarha's avatar Jyri Sarha Committed by Tomi Valkeinen

drm/omap: Major omap_modeset_init() cleanup

Cleanup overly complex omap_modeset_init(). The function is trying to
support many unusual configuration, that have never been tested and
are not supported by other parts of the dirver.

After cleanup the init 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.
Signed-off-by: default avatarJyri Sarha <jsarha@ti.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
parent 694c99cf
...@@ -573,6 +573,8 @@ static const char *channel_names[] = { ...@@ -573,6 +573,8 @@ static const char *channel_names[] = {
void omap_crtc_pre_init(void) void omap_crtc_pre_init(void)
{ {
memset(omap_crtcs, 0, sizeof(omap_crtcs));
dss_install_mgr_ops(&mgr_ops); dss_install_mgr_ops(&mgr_ops);
} }
...@@ -583,18 +585,28 @@ void omap_crtc_pre_uninit(void) ...@@ -583,18 +585,28 @@ void omap_crtc_pre_uninit(void)
/* initialize crtc */ /* initialize crtc */
struct drm_crtc *omap_crtc_init(struct drm_device *dev, 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 omap_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc = NULL; struct drm_crtc *crtc = NULL;
struct omap_crtc *omap_crtc; struct omap_crtc *omap_crtc;
enum omap_channel channel;
struct omap_dss_device *out;
int ret; int ret;
out = omapdss_find_output_from_display(dssdev);
channel = out->dispc_channel;
omap_dss_put_device(out);
DBG("%s", channel_names[channel]); 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); omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
if (!omap_crtc) if (!omap_crtc)
return NULL; return ERR_PTR(-ENOMEM);
crtc = &omap_crtc->base; crtc = &omap_crtc->base;
...@@ -606,8 +618,10 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -606,8 +618,10 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
&omap_crtc_funcs, NULL); &omap_crtc_funcs, NULL);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
__func__, dssdev->name);
kfree(omap_crtc); kfree(omap_crtc);
return NULL; return ERR_PTR(ret);
} }
drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
......
...@@ -219,20 +219,6 @@ static int get_connector_type(struct omap_dss_device *dssdev) ...@@ -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) static void omap_disconnect_dssdevs(void)
{ {
struct omap_dss_device *dssdev = NULL; struct omap_dss_device *dssdev = NULL;
...@@ -272,31 +258,6 @@ static int omap_connect_dssdevs(void) ...@@ -272,31 +258,6 @@ static int omap_connect_dssdevs(void)
return r; 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) static int omap_modeset_init_properties(struct drm_device *dev)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
...@@ -314,10 +275,9 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -314,10 +275,9 @@ static int omap_modeset_init(struct drm_device *dev)
struct omap_dss_device *dssdev = NULL; struct omap_dss_device *dssdev = NULL;
int num_ovls = priv->dispc_ops->get_num_ovls(); int num_ovls = priv->dispc_ops->get_num_ovls();
int num_mgrs = priv->dispc_ops->get_num_mgrs(); int num_mgrs = priv->dispc_ops->get_num_mgrs();
int num_crtcs = 0; int num_crtcs, crtc_idx, plane_idx;
int i, id = 0;
int ret; int ret;
u32 possible_crtcs; u32 plane_crtc_mask;
drm_mode_config_init(dev); drm_mode_config_init(dev);
...@@ -326,134 +286,91 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -326,134 +286,91 @@ static int omap_modeset_init(struct drm_device *dev)
return ret; return ret;
/* /*
* Let's create one CRTC for each connected DSS device if we * This function creates exactly one connector, encoder, crtc,
* have display managers and overlays (for primary planes) for * and primary plane per each connected dss-device. Each
* them. * 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) for_each_dss_dev(dssdev)
if (omapdss_device_is_connected(dssdev)) if (omapdss_device_is_connected(dssdev))
num_crtcs++; num_crtcs++;
num_crtcs = min3(num_crtcs, num_mgrs, num_ovls); if (num_crtcs > num_mgrs || num_crtcs > num_ovls ||
possible_crtcs = (1 << num_crtcs) - 1; 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; dssdev = NULL;
crtc_idx = 0;
plane_idx = 0;
for_each_dss_dev(dssdev) { for_each_dss_dev(dssdev) {
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
enum omap_channel channel; struct drm_plane *plane;
struct omap_dss_device *out; struct drm_crtc *crtc;
if (!omapdss_device_is_connected(dssdev)) if (!omapdss_device_is_connected(dssdev))
continue; continue;
encoder = omap_encoder_init(dev, dssdev); encoder = omap_encoder_init(dev, dssdev);
if (!encoder)
if (!encoder) {
dev_err(dev->dev, "could not create encoder: %s\n",
dssdev->name);
return -ENOMEM; return -ENOMEM;
}
connector = omap_connector_init(dev, connector = omap_connector_init(dev,
get_connector_type(dssdev), dssdev, encoder); get_connector_type(dssdev), dssdev, encoder);
if (!connector)
if (!connector) {
dev_err(dev->dev, "could not create connector: %s\n",
dssdev->name);
return -ENOMEM; return -ENOMEM;
}
BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY,
BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); plane_crtc_mask);
if (IS_ERR(plane))
return PTR_ERR(plane);
priv->encoders[priv->num_encoders++] = encoder; crtc = omap_crtc_init(dev, plane, dssdev);
priv->connectors[priv->num_connectors++] = connector; if (IS_ERR(crtc))
return PTR_ERR(crtc);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << crtc_idx);
/* priv->crtcs[priv->num_crtcs++] = crtc;
* if we have reached the limit of the crtcs we can priv->planes[priv->num_planes++] = plane;
* create, let's not try to create a crtc for this priv->encoders[priv->num_encoders++] = encoder;
* panel/encoder and onwards. priv->connectors[priv->num_connectors++] = connector;
*/
if (id == num_crtcs)
continue;
/* plane_idx++;
* get the recommended DISPC channel for this encoder. For now, crtc_idx++;
* 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++;
}
} }
/* /*
* Create normal planes for the remaining overlays: * Create normal planes for the remaining overlays:
*/ */
for (; id < num_ovls; id++) { for (; plane_idx < num_ovls; plane_idx++) {
struct drm_plane *plane; struct drm_plane *plane;
plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY, if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)))
possible_crtcs); return -EINVAL;
plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY,
plane_crtc_mask);
if (IS_ERR(plane)) if (IS_ERR(plane))
return PTR_ERR(plane); return PTR_ERR(plane);
BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
priv->planes[priv->num_planes++] = plane; 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", DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
priv->num_planes, priv->num_crtcs, priv->num_encoders, priv->num_planes, priv->num_crtcs, priv->num_encoders,
priv->num_connectors); priv->num_connectors);
......
...@@ -137,13 +137,13 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); ...@@ -137,13 +137,13 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
void omap_crtc_pre_init(void); void omap_crtc_pre_init(void);
void omap_crtc_pre_uninit(void); void omap_crtc_pre_uninit(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev, 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); int omap_crtc_wait_pending(struct drm_crtc *crtc);
void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus);
void omap_crtc_vblank_irq(struct drm_crtc *crtc); void omap_crtc_vblank_irq(struct drm_crtc *crtc);
struct drm_plane *omap_plane_init(struct drm_device *dev, 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); u32 possible_crtcs);
void omap_plane_install_properties(struct drm_plane *plane, void omap_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj); struct drm_mode_object *obj);
......
...@@ -324,24 +324,37 @@ static const struct drm_plane_funcs omap_plane_funcs = { ...@@ -324,24 +324,37 @@ static const struct drm_plane_funcs omap_plane_funcs = {
.atomic_get_property = omap_plane_atomic_get_property, .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_GFX] = "gfx",
[OMAP_DSS_VIDEO1] = "vid1", [OMAP_DSS_VIDEO1] = "vid1",
[OMAP_DSS_VIDEO2] = "vid2", [OMAP_DSS_VIDEO2] = "vid2",
[OMAP_DSS_VIDEO3] = "vid3", [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 */ /* initialize plane */
struct drm_plane *omap_plane_init(struct drm_device *dev, 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) u32 possible_crtcs)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
struct drm_plane *plane; struct drm_plane *plane;
struct omap_plane *omap_plane; struct omap_plane *omap_plane;
enum omap_plane_id id;
int ret; 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); omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
if (!omap_plane) if (!omap_plane)
...@@ -351,7 +364,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, ...@@ -351,7 +364,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
omap_plane->formats, ARRAY_SIZE(omap_plane->formats), omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
priv->dispc_ops->ovl_get_color_modes(id)); priv->dispc_ops->ovl_get_color_modes(id));
omap_plane->id = id; omap_plane->id = id;
omap_plane->name = plane_names[id]; omap_plane->name = plane_id_to_name[id];
plane = &omap_plane->base; plane = &omap_plane->base;
...@@ -368,6 +381,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, ...@@ -368,6 +381,9 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
return plane; return plane;
error: error:
dev_err(dev->dev, "%s(): could not create plane: %s\n",
__func__, plane_id_to_name[id]);
kfree(omap_plane); kfree(omap_plane);
return NULL; return NULL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment