aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_drv.c
diff options
context:
space:
mode:
authorArchit Taneja <archit@ti.com>2014-01-02 04:19:51 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-01-09 08:17:25 -0500
commit3a01ab255637fdc2fbc97cf356f1b971c3fc0c64 (patch)
tree4d16b7c8395a6e795a4f7a611de2790e98235f92 /drivers/gpu/drm/omapdrm/omap_drv.c
parent6da9f89172b94411896130c6e1acf159da3dc760 (diff)
drm/omap: fix: Defer probe if an omapdss device requests for it at connect
With the omapdss device model changes. omapdrm is required to call dssdriver's connect() op to register a panel. This is currently done in omap_modeset_init() A call to connect() can fail if the omapdss panels or the encoders(HDMI/DPI) they connect to have some resource(like regulators, I2C adapter) missing. If this happens, the correct approach is to defer omapdrm's probe. omapdrm currently ignores those panels which return a non zero value when connected. This could result in omapdrm ignoring all panels on an omap board. The right approach would be for omapdrm to request for probe deferral when a panel's connect op returns -EPROBE_DEFER. In order to do this, we need to call connect() much earlier during omapdrm's probe to prevent too many things are already done by then. We now connect the panels during pdev_probe(), before anything else is initialized, so that we don't need to undo too many things if a defer was requested. Now when we enter omap_modeset_init(), we have a set of panels that have been connected. We now proceed with registering only those panels that are already connected. A special case has to be considered when no panels are available to connect when omapdrm probes. In this case too, we defer probe and expect that a panel will be available to connect the next time. Checking whether the panel has a driver or whether it has get_timing/read_edid ops in omap_modeset_init() are redundant with the new display model. These can be removed since a dssdev device will always have a driver associated with it, and all dssdev drivers have a get_timings op. This will mainly fix cases when omapdrm is built-in the kernel, since that's generally where resources like regulators or I2C are unavailable because of probe order dependencies. In particular this fixes boot with omapdrm built-in on an omap4 panda ES board. The regulators used by HDMI(provided by I2C based TWL regulators) aren't initialized because I2C isn't initialized, I2C isn't initialized as it's pins are not configured because pinctrl is yet to probe. Signed-off-by: Archit Taneja <archit@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c70
1 files changed, 48 insertions, 22 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index e7fa3cd96743..651f9022308f 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -87,6 +87,43 @@ static bool channel_used(struct drm_device *dev, enum omap_channel channel)
87 return false; 87 return false;
88} 88}
89 89
90static int omap_connect_dssdevs(void)
91{
92 int r;
93 struct omap_dss_device *dssdev = NULL;
94 bool no_displays = true;
95
96 for_each_dss_dev(dssdev) {
97 r = dssdev->driver->connect(dssdev);
98 if (r == -EPROBE_DEFER) {
99 omap_dss_put_device(dssdev);
100 goto cleanup;
101 } else if (r) {
102 dev_warn(dssdev->dev, "could not connect display: %s\n",
103 dssdev->name);
104 } else {
105 no_displays = false;
106 }
107 }
108
109 if (no_displays)
110 return -EPROBE_DEFER;
111
112 return 0;
113
114cleanup:
115 /*
116 * if we are deferring probe, we disconnect the devices we previously
117 * connected
118 */
119 dssdev = NULL;
120
121 for_each_dss_dev(dssdev)
122 dssdev->driver->disconnect(dssdev);
123
124 return r;
125}
126
90static int omap_modeset_init(struct drm_device *dev) 127static int omap_modeset_init(struct drm_device *dev)
91{ 128{
92 struct omap_drm_private *priv = dev->dev_private; 129 struct omap_drm_private *priv = dev->dev_private;
@@ -95,9 +132,6 @@ static int omap_modeset_init(struct drm_device *dev)
95 int num_mgrs = dss_feat_get_num_mgrs(); 132 int num_mgrs = dss_feat_get_num_mgrs();
96 int num_crtcs; 133 int num_crtcs;
97 int i, id = 0; 134 int i, id = 0;
98 int r;
99
100 omap_crtc_pre_init();
101 135
102 drm_mode_config_init(dev); 136 drm_mode_config_init(dev);
103 137
@@ -119,26 +153,8 @@ static int omap_modeset_init(struct drm_device *dev)
119 enum omap_channel channel; 153 enum omap_channel channel;
120 struct omap_overlay_manager *mgr; 154 struct omap_overlay_manager *mgr;
121 155
122 if (!dssdev->driver) { 156 if (!omapdss_device_is_connected(dssdev))
123 dev_warn(dev->dev, "%s has no driver.. skipping it\n",
124 dssdev->name);
125 continue;
126 }
127
128 if (!(dssdev->driver->get_timings ||
129 dssdev->driver->read_edid)) {
130 dev_warn(dev->dev, "%s driver does not support "
131 "get_timings or read_edid.. skipping it!\n",
132 dssdev->name);
133 continue;
134 }
135
136 r = dssdev->driver->connect(dssdev);
137 if (r) {
138 dev_err(dev->dev, "could not connect display: %s\n",
139 dssdev->name);
140 continue; 157 continue;
141 }
142 158
143 encoder = omap_encoder_init(dev, dssdev); 159 encoder = omap_encoder_init(dev, dssdev);
144 160
@@ -655,9 +671,19 @@ static void pdev_shutdown(struct platform_device *device)
655 671
656static int pdev_probe(struct platform_device *device) 672static int pdev_probe(struct platform_device *device)
657{ 673{
674 int r;
675
658 if (omapdss_is_initialized() == false) 676 if (omapdss_is_initialized() == false)
659 return -EPROBE_DEFER; 677 return -EPROBE_DEFER;
660 678
679 omap_crtc_pre_init();
680
681 r = omap_connect_dssdevs();
682 if (r) {
683 omap_crtc_pre_uninit();
684 return r;
685 }
686
661 DBG("%s", device->name); 687 DBG("%s", device->name);
662 return drm_platform_init(&omap_drm_driver, device); 688 return drm_platform_init(&omap_drm_driver, device);
663} 689}