Hi,
Changes since RFC: - Comments from Laurent have been addressed: - Get alias ID once and store it for later use in sorting - Commit message updated for 'drm/omap: Manage the usable omap_dss_device list within omap_drm_private' patch - I have kept the first patch to convert to use devm_kzalloc for the private struct as I still think it is as correct as the way Laurent is proposing.
The series adds support for changing the order of the displays defined by DT display aliases.
The motivation to do such a thing is that for example the fb emulation is treating the first display/crtc as the 'main' display and will create the fb emulation based on the first display's properties. There are many custom applications using DRM directly and they assume that the first connector is the 'main' display. Afaik weston provides no means either to change the 'main/preferred' display.
It should be the work of user space application (except the fb emulation) to somehow deal with the 'main' display selection for their needs, but unfortunately they are not capable of diong so for some reason.
We have boards with LCD panel and HDMI for example and in DT the LCD is set as display0, but in certain useage scenarios it is desired to have the HDMI as the 'main' display instead of the LCD.
With the kernel cmd line parameter it is possible to change the pre defined order without recompiling the kernel/DT.
If the board have two active displays: 0 - LCD 1 - HDMI then: omapdrm.displays=0,1 - represents the original order (LCD, HDMI) omapdrm.displays=1,0 - represents reverse order (HDMI, LCD) omapdrm.displays=0 - only the LCD is enabled omapdrm.displays=1 - only the HDMI is enabled omapdrm.displays=-1 - disable all displays
The first 6 patch of the series is doing some generic clean up and prepares the code so the display ordering is going to be easy to add.
Regards, Peter --- Peter Ujfalusi (7): drm/omap: Use devm_kzalloc() to allocate omap_drm_private drm/omap: Allocate drm_device earlier and unref it as last step drm/omap: Manage the usable omap_dss_device list within omap_drm_private drm/omap: Separate the dssdevs array setup from the connect function drm/omap: Do dss_device (display) ordering in omap_drv.c drm/omap: dss: Remove display ordering from dss/display.c drm/omap: Add kernel parameter to specify the desired display order
drivers/gpu/drm/omapdrm/dss/display.c | 15 +-- drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 +- drivers/gpu/drm/omapdrm/omap_drv.c | 240 ++++++++++++++++++++++++---------- drivers/gpu/drm/omapdrm/omap_drv.h | 3 + 4 files changed, 181 insertions(+), 80 deletions(-)
It makes the cleanup paths a bit cleaner.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index ba3d22fae55b..3f9ea2971277 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -561,19 +561,17 @@ static int pdev_probe(struct platform_device *pdev) return ret; }
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + omap_crtc_pre_init();
ret = omap_connect_dssdevs(); if (ret) goto err_crtc_uninit;
- /* Allocate and initialize the driver private structure. */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_disconnect_dssdevs; - } - + /* Initialize the driver private structure. */ priv->dispc_ops = dispc_get_ops();
soc = soc_device_match(omapdrm_soc_devices); @@ -587,7 +585,7 @@ static int pdev_probe(struct platform_device *pdev) ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev); if (IS_ERR(ddev)) { ret = PTR_ERR(ddev); - goto err_free_priv; + goto err_destroy_wq; }
ddev->dev_private = priv; @@ -642,10 +640,8 @@ static int pdev_probe(struct platform_device *pdev) err_free_drm_dev: omap_gem_deinit(ddev); drm_dev_unref(ddev); -err_free_priv: +err_destroy_wq: destroy_workqueue(priv->wq); - kfree(priv); -err_disconnect_dssdevs: omap_disconnect_dssdevs(); err_crtc_uninit: omap_crtc_pre_uninit(); @@ -677,7 +673,6 @@ static int pdev_remove(struct platform_device *pdev) drm_dev_unref(ddev);
destroy_workqueue(priv->wq); - kfree(priv);
omap_disconnect_dssdevs(); omap_crtc_pre_uninit();
If we allocate the drm_device earlier we can just return the error code without the need to use goto. Do the unref of the drm_device as a last step when cleaning up. This will make the drm_device available longer for us and makes sure that we only free up the memory when all other cleanups have been already done.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 3f9ea2971277..2c1d04fb36f2 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -565,6 +565,14 @@ static int pdev_probe(struct platform_device *pdev) if (!priv) return -ENOMEM;
+ /* Allocate and initialize the DRM device. */ + ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + ddev->dev_private = priv; + platform_set_drvdata(pdev, ddev); + omap_crtc_pre_init();
ret = omap_connect_dssdevs(); @@ -581,16 +589,6 @@ static int pdev_probe(struct platform_device *pdev) spin_lock_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list);
- /* Allocate and initialize the DRM device. */ - ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev); - if (IS_ERR(ddev)) { - ret = PTR_ERR(ddev); - goto err_destroy_wq; - } - - ddev->dev_private = priv; - platform_set_drvdata(pdev, ddev); - /* Get memory bandwidth limits */ if (priv->dispc_ops->get_memory_bandwidth_limit) priv->max_bandwidth = @@ -601,7 +599,7 @@ static int pdev_probe(struct platform_device *pdev) ret = omap_modeset_init(ddev); if (ret) { dev_err(&pdev->dev, "omap_modeset_init failed: ret=%d\n", ret); - goto err_free_drm_dev; + goto err_gem_deinit; }
/* Initialize vblank handling, start with all CRTCs disabled. */ @@ -637,14 +635,13 @@ static int pdev_probe(struct platform_device *pdev) err_cleanup_modeset: drm_mode_config_cleanup(ddev); omap_drm_irq_uninstall(ddev); -err_free_drm_dev: +err_gem_deinit: omap_gem_deinit(ddev); - drm_dev_unref(ddev); -err_destroy_wq: destroy_workqueue(priv->wq); omap_disconnect_dssdevs(); err_crtc_uninit: omap_crtc_pre_uninit(); + drm_dev_unref(ddev); return ret; }
@@ -670,13 +667,13 @@ static int pdev_remove(struct platform_device *pdev) omap_drm_irq_uninstall(ddev); omap_gem_deinit(ddev);
- drm_dev_unref(ddev); - destroy_workqueue(priv->wq);
omap_disconnect_dssdevs(); omap_crtc_pre_uninit();
+ drm_dev_unref(ddev); + return 0; }
Instead of reaching back to DSS to iterate through the dss_devices every time, use an internal array where we store the available and usable dss_devices.
At the same time remove the omapdss_device_is_connected() check from omap_modeset_init() as it became irrelevant: We are not adding dssdevs if their connect failed.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 95 +++++++++++++++++++++++--------------- drivers/gpu/drm/omapdrm/omap_drv.h | 3 ++ 2 files changed, 62 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 2c1d04fb36f2..40f28eab0e16 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -159,18 +159,27 @@ static int get_connector_type(struct omap_dss_device *dssdev) } }
-static void omap_disconnect_dssdevs(void) +static void omap_disconnect_dssdevs(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i];
- for_each_dss_dev(dssdev) dssdev->driver->disconnect(dssdev); + priv->dssdevs[i] = NULL; + omap_dss_put_device(dssdev); + } + + priv->num_dssdevs = 0; }
-static int omap_connect_dssdevs(void) +static int omap_connect_dssdevs(struct drm_device *ddev) { - int r; + struct omap_drm_private *priv = ddev->dev_private; struct omap_dss_device *dssdev = NULL; + int r;
if (!omapdss_stack_is_ready()) return -EPROBE_DEFER; @@ -183,6 +192,14 @@ static int omap_connect_dssdevs(void) } else if (r) { dev_warn(dssdev->dev, "could not connect display: %s\n", dssdev->name); + } else { + omap_dss_get_device(dssdev); + priv->dssdevs[priv->num_dssdevs++] = dssdev; + if (priv->num_dssdevs == ARRAY_SIZE(priv->dssdevs)) { + /* To balance the 'for_each_dss_dev' loop */ + omap_dss_put_device(dssdev); + break; + } } }
@@ -193,7 +210,7 @@ static int omap_connect_dssdevs(void) * if we are deferring probe, we disconnect the devices we previously * connected */ - omap_disconnect_dssdevs(); + omap_disconnect_dssdevs(ddev);
return r; } @@ -218,7 +235,7 @@ static int omap_modeset_init(struct drm_device *dev) int num_ovls = priv->dispc_ops->get_num_ovls(); int num_mgrs = priv->dispc_ops->get_num_mgrs(); int num_crtcs, crtc_idx, plane_idx; - int ret; + int ret, i; u32 plane_crtc_mask;
drm_mode_config_init(dev); @@ -235,11 +252,7 @@ static int omap_modeset_init(struct drm_device *dev) * 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 = priv->num_dssdevs; if (num_crtcs > num_mgrs || num_crtcs > num_ovls || num_crtcs > ARRAY_SIZE(priv->crtcs) || num_crtcs > ARRAY_SIZE(priv->planes) || @@ -257,15 +270,13 @@ static int omap_modeset_init(struct drm_device *dev)
crtc_idx = 0; plane_idx = 0; - for_each_dss_dev(dssdev) { + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i]; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_plane *plane; struct drm_crtc *crtc;
- if (!omapdss_device_is_connected(dssdev)) - continue; - encoder = omap_encoder_init(dev, dssdev); if (!encoder) return -ENOMEM; @@ -339,11 +350,14 @@ static int omap_modeset_init(struct drm_device *dev) /* * Enable the HPD in external components if supported */ -static void omap_modeset_enable_external_hpd(void) +static void omap_modeset_enable_external_hpd(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + int i; + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i];
- for_each_dss_dev(dssdev) { if (dssdev->driver->enable_hpd) dssdev->driver->enable_hpd(dssdev); } @@ -352,11 +366,14 @@ static void omap_modeset_enable_external_hpd(void) /* * Disable the HPD in external components if supported */ -static void omap_modeset_disable_external_hpd(void) +static void omap_modeset_disable_external_hpd(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + int i; + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i];
- for_each_dss_dev(dssdev) { if (dssdev->driver->disable_hpd) dssdev->driver->disable_hpd(dssdev); } @@ -575,7 +592,7 @@ static int pdev_probe(struct platform_device *pdev)
omap_crtc_pre_init();
- ret = omap_connect_dssdevs(); + ret = omap_connect_dssdevs(ddev); if (ret) goto err_crtc_uninit;
@@ -615,7 +632,7 @@ static int pdev_probe(struct platform_device *pdev) priv->fbdev = omap_fbdev_init(ddev);
drm_kms_helper_poll_init(ddev); - omap_modeset_enable_external_hpd(); + omap_modeset_enable_external_hpd(ddev);
/* * Register the DRM device with the core and the connectors with @@ -628,7 +645,7 @@ static int pdev_probe(struct platform_device *pdev) return 0;
err_cleanup_helpers: - omap_modeset_disable_external_hpd(); + omap_modeset_disable_external_hpd(ddev); drm_kms_helper_poll_fini(ddev); if (priv->fbdev) omap_fbdev_free(ddev); @@ -638,7 +655,7 @@ static int pdev_probe(struct platform_device *pdev) err_gem_deinit: omap_gem_deinit(ddev); destroy_workqueue(priv->wq); - omap_disconnect_dssdevs(); + omap_disconnect_dssdevs(ddev); err_crtc_uninit: omap_crtc_pre_uninit(); drm_dev_unref(ddev); @@ -654,7 +671,7 @@ static int pdev_remove(struct platform_device *pdev)
drm_dev_unregister(ddev);
- omap_modeset_disable_external_hpd(); + omap_modeset_disable_external_hpd(ddev); drm_kms_helper_poll_fini(ddev);
if (priv->fbdev) @@ -669,7 +686,7 @@ static int pdev_remove(struct platform_device *pdev)
destroy_workqueue(priv->wq);
- omap_disconnect_dssdevs(); + omap_disconnect_dssdevs(ddev); omap_crtc_pre_uninit();
drm_dev_unref(ddev); @@ -678,11 +695,14 @@ static int pdev_remove(struct platform_device *pdev) }
#ifdef CONFIG_PM_SLEEP -static int omap_drm_suspend_all_displays(void) +static int omap_drm_suspend_all_displays(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + int i; + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i];
- for_each_dss_dev(dssdev) { if (!dssdev->driver) continue;
@@ -697,11 +717,14 @@ static int omap_drm_suspend_all_displays(void) return 0; }
-static int omap_drm_resume_all_displays(void) +static int omap_drm_resume_all_displays(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + int i; + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i];
- for_each_dss_dev(dssdev) { if (!dssdev->driver) continue;
@@ -721,7 +744,7 @@ static int omap_drm_suspend(struct device *dev) drm_kms_helper_poll_disable(drm_dev);
drm_modeset_lock_all(drm_dev); - omap_drm_suspend_all_displays(); + omap_drm_suspend_all_displays(drm_dev); drm_modeset_unlock_all(drm_dev);
return 0; @@ -732,7 +755,7 @@ static int omap_drm_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev);
drm_modeset_lock_all(drm_dev); - omap_drm_resume_all_displays(); + omap_drm_resume_all_displays(drm_dev); drm_modeset_unlock_all(drm_dev);
drm_kms_helper_poll_enable(drm_dev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index d404e8c56b61..d49715272080 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -51,6 +51,9 @@ struct omap_drm_private {
const struct dispc_ops *dispc_ops;
+ unsigned int num_dssdevs; + struct omap_dss_device *dssdevs[8]; + unsigned int num_crtcs; struct drm_crtc *crtcs[8];
In order to ease up on the logic, break the current code to gather the dssdevs:
first get all available dssdevs, then call connect on each dssdev. As the last step remove the dssdevs which failed to connect from the available dssdev list.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 54 ++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 40f28eab0e16..173aa6a95757 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -175,34 +175,60 @@ static void omap_disconnect_dssdevs(struct drm_device *ddev) priv->num_dssdevs = 0; }
-static int omap_connect_dssdevs(struct drm_device *ddev) +static void omap_collect_dssdevs(struct drm_device *ddev) { struct omap_drm_private *priv = ddev->dev_private; struct omap_dss_device *dssdev = NULL; - int r; + + for_each_dss_dev(dssdev) { + omap_dss_get_device(dssdev); + priv->dssdevs[priv->num_dssdevs++] = dssdev; + if (priv->num_dssdevs == ARRAY_SIZE(priv->dssdevs)) { + /* To balance the 'for_each_dss_dev' loop */ + omap_dss_put_device(dssdev); + break; + } + } +} + +static int omap_connect_dssdevs(struct drm_device *ddev) +{ + struct omap_drm_private *priv = ddev->dev_private; + u32 working = 0; + int r, i, j;
if (!omapdss_stack_is_ready()) return -EPROBE_DEFER;
- for_each_dss_dev(dssdev) { + omap_collect_dssdevs(ddev); + + for (i = 0; i < priv->num_dssdevs; i++) { + struct omap_dss_device *dssdev = priv->dssdevs[i]; + r = dssdev->driver->connect(dssdev); - if (r == -EPROBE_DEFER) { - omap_dss_put_device(dssdev); + if (r == -EPROBE_DEFER) goto cleanup; - } else if (r) { + else if (r) dev_warn(dssdev->dev, "could not connect display: %s\n", - dssdev->name); + dssdev->name); + else + working |= BIT(i); + } + + /* Remove the dssdevs if their connect failed */ + j = 0; + for (i = 0; i < priv->num_dssdevs; i++) { + if (working & BIT(i)) { + if (j != i) + priv->dssdevs[j] = priv->dssdevs[i]; + j++; } else { - omap_dss_get_device(dssdev); - priv->dssdevs[priv->num_dssdevs++] = dssdev; - if (priv->num_dssdevs == ARRAY_SIZE(priv->dssdevs)) { - /* To balance the 'for_each_dss_dev' loop */ - omap_dss_put_device(dssdev); - break; - } + omap_dss_put_device(priv->dssdevs[i]); } }
+ priv->num_dssdevs = j; + return 0;
cleanup:
Sort the dssdev array based on DT aliases.
With this change we can remove the panel ordering from dss/display.c and have all sorting related to dssdevs in one place.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/dss/display.c | 2 ++ drivers/gpu/drm/omapdrm/dss/omapdss.h | 1 + drivers/gpu/drm/omapdrm/omap_drv.c | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 42279933790e..1159bf8e2c6c 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -55,6 +55,8 @@ int omapdss_register_display(struct omap_dss_device *dssdev) if (id < 0) id = disp_num_counter++;
+ dssdev->alias_id = id; + snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
/* Use 'label' property for name, if it exists */ diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index c2166d2d3f29..89588984d913 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -478,6 +478,7 @@ struct omap_dss_device {
/* alias in the form of "display%d" */ char alias[16]; + int alias_id;
enum omap_display_type type; enum omap_display_type output_type; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 173aa6a95757..4e58343d5db2 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -17,6 +17,8 @@ * this program. If not, see http://www.gnu.org/licenses/. */
+#include <linux/of.h> +#include <linux/sort.h> #include <linux/sys_soc.h>
#include <drm/drm_atomic.h> @@ -175,6 +177,18 @@ static void omap_disconnect_dssdevs(struct drm_device *ddev) priv->num_dssdevs = 0; }
+static int omap_compare_dssdevs(const void *a, const void *b) +{ + const struct omap_dss_device *dssdev1 = *(struct omap_dss_device **)a; + const struct omap_dss_device *dssdev2 = *(struct omap_dss_device **)b; + + if (dssdev1->alias_id > dssdev2->alias_id) + return 1; + else if (dssdev1->alias_id < dssdev2->alias_id) + return -1; + return 0; +} + static void omap_collect_dssdevs(struct drm_device *ddev) { struct omap_drm_private *priv = ddev->dev_private; @@ -189,6 +203,10 @@ static void omap_collect_dssdevs(struct drm_device *ddev) break; } } + + /* Sort the list by DT aliases */ + sort(priv->dssdevs, priv->num_dssdevs, sizeof(priv->dssdevs[0]), + omap_compare_dssdevs, NULL); }
static int omap_connect_dssdevs(struct drm_device *ddev)
The previous patch implements the ordering of the dss_devices based on DT aliases in omap_drm.c, so there is no need to do the ordering in dss/display.c anymore.
At the same time remove the alias member of the omap_dss_device struct since it is no longer needed. The only place it was used is in the omapdss_register_display() function.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/dss/display.c | 15 +++------------ drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 -- 2 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 1159bf8e2c6c..afb615bccc7b 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -44,7 +44,6 @@ static int disp_num_counter; int omapdss_register_display(struct omap_dss_device *dssdev) { struct omap_dss_driver *drv = dssdev->driver; - struct list_head *cur; int id;
/* @@ -57,26 +56,18 @@ int omapdss_register_display(struct omap_dss_device *dssdev)
dssdev->alias_id = id;
- snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); - /* Use 'label' property for name, if it exists */ of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name);
if (dssdev->name == NULL) - dssdev->name = dssdev->alias; + dssdev->name = devm_kasprintf(dssdev->dev, GFP_KERNEL, + "display%d", id);
if (drv && drv->get_timings == NULL) drv->get_timings = omapdss_default_get_timings;
mutex_lock(&panel_list_mutex); - list_for_each(cur, &panel_list) { - struct omap_dss_device *ldev = list_entry(cur, - struct omap_dss_device, - panel_list); - if (strcmp(ldev->alias, dssdev->alias) > 0) - break; - } - list_add_tail(&dssdev->panel_list, cur); + list_add_tail(&dssdev->panel_list, &panel_list); mutex_unlock(&panel_list_mutex); return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 89588984d913..3e9654355011 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -476,8 +476,6 @@ struct omap_dss_device {
struct list_head panel_list;
- /* alias in the form of "display%d" */ - char alias[16]; int alias_id;
enum omap_display_type type;
omapdrm.displays (int array) can be used to reorder the displays by id if needed. It can be also used to disable display.
If the board have two active displays: 0 - LCD 1 - HDMI then: omapdrm.displays=0,1 - represents the original order (LCD, HDMI) omapdrm.displays=1,0 - represents reverse order (HDMI, LCD) omapdrm.displays=0 - only the LCD is enabled omapdrm.displays=1 - only the HDMI is enabled omapdrm.displays=-1 - disable all displays
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 4e58343d5db2..4604ad36d566 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -36,6 +36,14 @@ #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0
+#define MAX_NR_DISPLAYS 8 +static int display_order[MAX_NR_DISPLAYS]; +static int display_order_nelm; +module_param_array_named(displays, display_order, int, &display_order_nelm, + 0444); +MODULE_PARM_DESC(displays, + "ID array to specify the order of the active displays"); + /* * mode config funcs */ @@ -192,12 +200,21 @@ static int omap_compare_dssdevs(const void *a, const void *b) static void omap_collect_dssdevs(struct drm_device *ddev) { struct omap_drm_private *priv = ddev->dev_private; + struct omap_dss_device *dssdevs[ARRAY_SIZE(priv->dssdevs)]; struct omap_dss_device *dssdev = NULL; + int num_dssdevs = 0; + unsigned long dssdev_mask = 0; + int i; + + /* No displays should be enabled */ + if (display_order_nelm == 1 && display_order[0] < 0) + return;
for_each_dss_dev(dssdev) { omap_dss_get_device(dssdev); - priv->dssdevs[priv->num_dssdevs++] = dssdev; - if (priv->num_dssdevs == ARRAY_SIZE(priv->dssdevs)) { + set_bit(num_dssdevs, &dssdev_mask); + dssdevs[num_dssdevs++] = dssdev; + if (num_dssdevs == ARRAY_SIZE(dssdevs)) { /* To balance the 'for_each_dss_dev' loop */ omap_dss_put_device(dssdev); break; @@ -205,8 +222,38 @@ static void omap_collect_dssdevs(struct drm_device *ddev) }
/* Sort the list by DT aliases */ - sort(priv->dssdevs, priv->num_dssdevs, sizeof(priv->dssdevs[0]), - omap_compare_dssdevs, NULL); + sort(dssdevs, num_dssdevs, sizeof(dssdevs[0]), omap_compare_dssdevs, + NULL); + + /* Do ordering based on the display_order parameter array */ + for (i = 0; i < display_order_nelm; i++) { + int old_index = display_order[i]; + + if ((old_index >= 0 && old_index < num_dssdevs) && + (dssdev_mask & BIT(old_index))) { + priv->dssdevs[priv->num_dssdevs++] = dssdevs[old_index]; + clear_bit(old_index, &dssdev_mask); + } else { + dev_err(ddev->dev, + "Ignoring invalid displays module parameter\n"); + priv->num_dssdevs = 0; + break; + } + } + + /* if the target list is empty, copy the collected dssdevs, if any */ + if (priv->num_dssdevs == 0) { + for (i = 0; i < num_dssdevs; i++) + priv->dssdevs[i] = dssdevs[i]; + + priv->num_dssdevs = num_dssdevs; + } else { + u32 idx; + + /* check if we have dssdev which is not carried over */ + for_each_set_bit(idx, &dssdev_mask, ARRAY_SIZE(dssdevs)) + omap_dss_put_device(dssdevs[idx]); + } }
static int omap_connect_dssdevs(struct drm_device *ddev)
dri-devel@lists.freedesktop.org