The first patch removes CONFIG_DRM_OMAP_NUM_CRTCS config option. The rest cleans up the unnecessary complexity from omap_modeset_init().
Changes since first version: - drm/omapdrm: Get rid of DRM_OMAP_NUM_CRTCS config option - drm/omapdrm: -> drm/omap: - Drop: - drm/omapdrm: Change possible_crtcs to possible_crtcs_for_planes - drm/omapdrm: Separate ids for planes and CRTCs in omap_modeset_init() - Add: - drm/omap: Major omap_modeset_init() cleanup
Jyri Sarha (2): drm/omap: Get rid of DRM_OMAP_NUM_CRTCS config option drm/omap: Major omap_modeset_init() cleanup
drivers/gpu/drm/omapdrm/Kconfig | 9 -- drivers/gpu/drm/omapdrm/omap_crtc.c | 23 +++- drivers/gpu/drm/omapdrm/omap_drv.c | 210 ++++++++--------------------------- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 + 5 files changed, 73 insertions(+), 174 deletions(-)
Allocate one CRTC for each connected output and get rid of DRM_OMAP_NUM_CRTCS config option. We still can not create more CRTCs than we have DSS display managers. We also reserve one overlay per CRTC for primary plane so we can not have more CRTCs than we have overlays either.
Signed-off-by: Jyri Sarha jsarha@ti.com --- drivers/gpu/drm/omapdrm/Kconfig | 9 ------ drivers/gpu/drm/omapdrm/omap_drv.c | 59 +++++++++++--------------------------- 2 files changed, 16 insertions(+), 52 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 556f81f..b3d08c5 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -10,15 +10,6 @@ config DRM_OMAP
if DRM_OMAP
-config DRM_OMAP_NUM_CRTCS - int "Number of CRTCs" - range 1 10 - default 1 if ARCH_OMAP2 || ARCH_OMAP3 - default 2 if ARCH_OMAP4 - help - Select the number of video overlays which can be used as framebuffers. - The remaining overlays are reserved for video. - source "drivers/gpu/drm/omapdrm/dss/Kconfig" source "drivers/gpu/drm/omapdrm/displays/Kconfig"
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 79a4aad..17c40aa 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -34,11 +34,6 @@ #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0
-static int num_crtc = CONFIG_DRM_OMAP_NUM_CRTCS; - -MODULE_PARM_DESC(num_crtc, "Number of overlays to use as CRTCs"); -module_param(num_crtc, int, 0600); - /* * mode config funcs */ @@ -322,7 +317,7 @@ static int omap_modeset_init(struct drm_device *dev) struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); int num_mgrs = dss_feat_get_num_mgrs(); - int num_crtcs; + int num_crtcs = 0; int i, id = 0; int ret; u32 possible_crtcs; @@ -334,12 +329,15 @@ static int omap_modeset_init(struct drm_device *dev) return ret;
/* - * We usually don't want to create a CRTC for each manager, at least - * not until we have a way to expose private planes to userspace. - * Otherwise there would not be enough video pipes left for drm planes. - * We use the num_crtc argument to limit the number of crtcs we create. + * Let's create one CRTC for each connected DSS device if we + * have display managers and overlays (for primary planes) for + * them. */ - num_crtcs = min3(num_crtc, num_mgrs, num_ovls); + 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;
dssdev = NULL; @@ -379,11 +377,9 @@ static int omap_modeset_init(struct drm_device *dev) drm_mode_connector_attach_encoder(connector, encoder);
/* - * if we have reached the limit of the crtcs we are allowed to - * create, let's not try to look for a crtc for this - * panel/encoder and onwards, we will, of course, populate the - * the possible_crtcs field for all the encoders with the final - * set of crtcs we create + * 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; @@ -418,33 +414,6 @@ static int omap_modeset_init(struct drm_device *dev) }
/* - * we have allocated crtcs according to the need of the panels/encoders, - * adding more crtcs here if needed - */ - for (; id < num_crtcs; id++) { - - /* find a free manager for this crtc */ - for (i = 0; i < num_mgrs; i++) { - if (!channel_used(dev, i)) - break; - } - - if (i == num_mgrs) { - /* this shouldn't really happen */ - dev_err(dev->dev, "no managers left for crtc\n"); - return -ENOMEM; - } - - ret = omap_modeset_create_crtc(dev, id, i, - possible_crtcs); - if (ret < 0) { - dev_err(dev->dev, - "could not create CRTC (channel %u)\n", i); - return ret; - } - } - - /* * Create normal planes for the remaining overlays: */ for (; id < num_ovls; id++) { @@ -459,6 +428,10 @@ static int omap_modeset_init(struct drm_device *dev) 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 =
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: Jyri Sarha jsarha@ti.com --- drivers/gpu/drm/omapdrm/omap_crtc.c | 23 ++++- drivers/gpu/drm/omapdrm/omap_drv.c | 173 +++++++++-------------------------- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 + 4 files changed, 68 insertions(+), 133 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 2fe735c..4bafc7b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -521,6 +521,11 @@ static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
void omap_crtc_pre_init(void) { + int i; + + for (i = 0; i < ARRAY_SIZE(omap_crtcs); i++) + omap_crtcs[i] = NULL; + dss_install_mgr_ops(&mgr_ops); }
@@ -531,17 +536,27 @@ 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 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;
@@ -553,8 +568,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 17c40aa..7bea6f5 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; @@ -275,31 +261,6 @@ static int omap_connect_dssdevs(void) 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; @@ -318,9 +279,9 @@ static int omap_modeset_init(struct drm_device *dev) int num_ovls = dss_feat_get_num_ovls(); int num_mgrs = dss_feat_get_num_mgrs(); int num_crtcs = 0; - int i, id = 0; + int crtc_idx = 0, plane_idx = 0; int ret; - u32 possible_crtcs; + u32 plane_crtc_mask;
drm_mode_config_init(dev);
@@ -329,134 +290,88 @@ 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. */ 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;
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 9098ea1..1e077a9 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -135,7 +135,7 @@ static inline void omap_fbdev_free(struct drm_device *dev) 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); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 386d90a..8fc1f4a 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -371,6 +371,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_names[id]); + kfree(omap_plane); return NULL; }
On 20/03/17 18:06, Jyri Sarha wrote:
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: Jyri Sarha jsarha@ti.com
drivers/gpu/drm/omapdrm/omap_crtc.c | 23 ++++- drivers/gpu/drm/omapdrm/omap_drv.c | 173 +++++++++-------------------------- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 + 4 files changed, 68 insertions(+), 133 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 2fe735c..4bafc7b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -521,6 +521,11 @@ static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
void omap_crtc_pre_init(void) {
- int i;
- for (i = 0; i < ARRAY_SIZE(omap_crtcs); i++)
omap_crtcs[i] = NULL;
Use memset to clear.
@@ -318,9 +279,9 @@ static int omap_modeset_init(struct drm_device *dev) int num_ovls = dss_feat_get_num_ovls(); int num_mgrs = dss_feat_get_num_mgrs(); int num_crtcs = 0;
- int i, id = 0;
- int crtc_idx = 0, plane_idx = 0;
In a bit longer function it's usually better to initialize the variables near to the place where they are first used, so that you will see the initial value when looking at the code in question.
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 386d90a..8fc1f4a 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -371,6 +371,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_names[id]);
- kfree(omap_plane); return NULL;
}
omap_plane_init() still uses "id" instead of "idx", and it's stored in struct omap_plane as 'id', and there's no explicit mapping of the DRM idx to the DSS plane id. This is confusing as the DRM plane idx is not strictly tied to the DSS plane id.
So, call it "idx" when it's about the DRM plane index and call it something else when it's about the dss plane id (it's "enum omap_plane" in dss, but that clashes with drm's struct omap_plane. So... 'dss_plane'?). And create a function that maps the DRM plane idx to DSS plane id (for now it can be just a direct map).
This change should probably be an additional patch.
Otherwise I think this looks good, much cleaner than the current confusion.
Tomi
On Mon, Mar 20, 2017 at 06:06:37PM +0200, Jyri Sarha wrote:
The first patch removes CONFIG_DRM_OMAP_NUM_CRTCS config option. The rest cleans up the unnecessary complexity from omap_modeset_init().
Changes since first version:
- drm/omapdrm: Get rid of DRM_OMAP_NUM_CRTCS config option
- drm/omapdrm: -> drm/omap:
- Drop:
- drm/omapdrm: Change possible_crtcs to possible_crtcs_for_planes
- drm/omapdrm: Separate ids for planes and CRTCs in omap_modeset_init()
- Add:
- drm/omap: Major omap_modeset_init() cleanup
Jyri Sarha (2): drm/omap: Get rid of DRM_OMAP_NUM_CRTCS config option drm/omap: Major omap_modeset_init() cleanup
On the topic of entirely useless connector limits, max_conn_count from the fbdev helpers is also dead ever since we started to dynamically alloc connectors because of dp mst hotplugging. In case you want to remove more cruft :-) -Daniel
drivers/gpu/drm/omapdrm/Kconfig | 9 -- drivers/gpu/drm/omapdrm/omap_crtc.c | 23 +++- drivers/gpu/drm/omapdrm/omap_drv.c | 210 ++++++++--------------------------- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 + 5 files changed, 73 insertions(+), 174 deletions(-)
-- 1.9.1
dri-devel@lists.freedesktop.org