aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2016-10-31 11:34:22 -0400
committerJyri Sarha <jsarha@ti.com>2016-11-30 07:17:52 -0500
commitec9eab097a50040c743fe612c4635fd8ea5c5936 (patch)
tree081fbfcb8c9e5b7eca0335075174daf641e124d3
parentdc55ac3b52e69be4868687acabf232af81e0ef8b (diff)
drm/tilcdc: Add drm bridge support for attaching drm bridge drivers
Adds drm bride support for attaching drm bridge drivers to tilcdc. The decision whether a video port leads to an external encoder or bridge is made simply based on remote device's compatible string. The code has been tested with BeagleBone-Black with and without BeagleBone DVI-D Cape Rev A3 using ti-tfp410 driver. Signed-off-by: Jyri Sarha <jsarha@ti.com> Tested-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c11
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c260
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.h5
4 files changed, 207 insertions, 74 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 3d2cea090d6f..7f4d3bc7152f 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -209,7 +209,7 @@ static void tilcdc_fini(struct drm_device *dev)
209 209
210 drm_irq_uninstall(dev); 210 drm_irq_uninstall(dev);
211 drm_mode_config_cleanup(dev); 211 drm_mode_config_cleanup(dev);
212 tilcdc_remove_external_encoders(dev); 212 tilcdc_remove_external_device(dev);
213 213
214#ifdef CONFIG_CPU_FREQ 214#ifdef CONFIG_CPU_FREQ
215 if (priv->freq_transition.notifier_call) 215 if (priv->freq_transition.notifier_call)
@@ -381,12 +381,17 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
381 if (ret < 0) 381 if (ret < 0)
382 goto init_failed; 382 goto init_failed;
383 383
384 ret = tilcdc_add_external_encoders(ddev); 384 ret = tilcdc_add_component_encoder(ddev);
385 if (ret < 0) 385 if (ret < 0)
386 goto init_failed; 386 goto init_failed;
387 } else {
388 ret = tilcdc_attach_external_device(ddev);
389 if (ret)
390 goto init_failed;
387 } 391 }
388 392
389 if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { 393 if (!priv->external_connector &&
394 ((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
390 dev_err(dev, "no encoders/connectors found\n"); 395 dev_err(dev, "no encoders/connectors found\n");
391 ret = -ENXIO; 396 ret = -ENXIO;
392 goto init_failed; 397 goto init_failed;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index d31fe5d8ab9d..411f8a8d8158 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -88,7 +88,10 @@ struct tilcdc_drm_private {
88 88
89 unsigned int num_connectors; 89 unsigned int num_connectors;
90 struct drm_connector *connectors[8]; 90 struct drm_connector *connectors[8];
91 const struct drm_connector_helper_funcs *connector_funcs[8]; 91
92 struct drm_encoder *external_encoder;
93 struct drm_connector *external_connector;
94 const struct drm_connector_helper_funcs *connector_funcs;
92 95
93 bool is_registered; 96 bool is_registered;
94 bool is_componentized; 97 bool is_componentized;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 06a4c584f3cb..c67d7cd7d57e 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -28,44 +28,50 @@ static const struct tilcdc_panel_info panel_info_tda998x = {
28 .raster_order = 0, 28 .raster_order = 0,
29}; 29};
30 30
31static const struct tilcdc_panel_info panel_info_default = {
32 .ac_bias = 255,
33 .ac_bias_intrpt = 0,
34 .dma_burst_sz = 16,
35 .bpp = 16,
36 .fdd = 0x80,
37 .tft_alt_mode = 0,
38 .sync_edge = 0,
39 .sync_ctrl = 1,
40 .raster_order = 0,
41};
42
31static int tilcdc_external_mode_valid(struct drm_connector *connector, 43static int tilcdc_external_mode_valid(struct drm_connector *connector,
32 struct drm_display_mode *mode) 44 struct drm_display_mode *mode)
33{ 45{
34 struct tilcdc_drm_private *priv = connector->dev->dev_private; 46 struct tilcdc_drm_private *priv = connector->dev->dev_private;
35 int ret, i; 47 int ret;
36 48
37 ret = tilcdc_crtc_mode_valid(priv->crtc, mode); 49 ret = tilcdc_crtc_mode_valid(priv->crtc, mode);
38 if (ret != MODE_OK) 50 if (ret != MODE_OK)
39 return ret; 51 return ret;
40 52
41 for (i = 0; i < priv->num_connectors && 53 BUG_ON(priv->external_connector != connector);
42 priv->connectors[i] != connector; i++) 54 BUG_ON(!priv->connector_funcs);
43 ;
44
45 BUG_ON(priv->connectors[i] != connector);
46 BUG_ON(!priv->connector_funcs[i]);
47 55
48 /* If the connector has its own mode_valid call it. */ 56 /* If the connector has its own mode_valid call it. */
49 if (!IS_ERR(priv->connector_funcs[i]) && 57 if (!IS_ERR(priv->connector_funcs) &&
50 priv->connector_funcs[i]->mode_valid) 58 priv->connector_funcs->mode_valid)
51 return priv->connector_funcs[i]->mode_valid(connector, mode); 59 return priv->connector_funcs->mode_valid(connector, mode);
52 60
53 return MODE_OK; 61 return MODE_OK;
54} 62}
55 63
56static int tilcdc_add_external_encoder(struct drm_device *dev, 64static int tilcdc_add_external_connector(struct drm_device *dev,
57 struct drm_connector *connector) 65 struct drm_connector *connector)
58{ 66{
59 struct tilcdc_drm_private *priv = dev->dev_private; 67 struct tilcdc_drm_private *priv = dev->dev_private;
60 struct drm_connector_helper_funcs *connector_funcs; 68 struct drm_connector_helper_funcs *connector_funcs;
61 69
62 priv->connectors[priv->num_connectors] = connector; 70 /* There should never be more than one connector */
63 priv->encoders[priv->num_encoders++] = connector->encoder; 71 if (WARN_ON(priv->external_connector))
64 72 return -EINVAL;
65 /* Only tda998x is supported at the moment. */
66 tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
67 tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
68 73
74 priv->external_connector = connector;
69 connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs), 75 connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
70 GFP_KERNEL); 76 GFP_KERNEL);
71 if (!connector_funcs) 77 if (!connector_funcs)
@@ -78,56 +84,177 @@ static int tilcdc_add_external_encoder(struct drm_device *dev,
78 * everything else but use our own mode_valid() (above). 84 * everything else but use our own mode_valid() (above).
79 */ 85 */
80 if (connector->helper_private) { 86 if (connector->helper_private) {
81 priv->connector_funcs[priv->num_connectors] = 87 priv->connector_funcs = connector->helper_private;
82 connector->helper_private; 88 *connector_funcs = *priv->connector_funcs;
83 *connector_funcs = *priv->connector_funcs[priv->num_connectors];
84 } else { 89 } else {
85 priv->connector_funcs[priv->num_connectors] = ERR_PTR(-ENOENT); 90 priv->connector_funcs = ERR_PTR(-ENOENT);
86 } 91 }
87 connector_funcs->mode_valid = tilcdc_external_mode_valid; 92 connector_funcs->mode_valid = tilcdc_external_mode_valid;
88 drm_connector_helper_add(connector, connector_funcs); 93 drm_connector_helper_add(connector, connector_funcs);
89 priv->num_connectors++;
90 94
91 dev_dbg(dev->dev, "External encoder '%s' connected\n", 95 dev_dbg(dev->dev, "External connector '%s' connected\n",
92 connector->encoder->name); 96 connector->name);
93 97
94 return 0; 98 return 0;
95} 99}
96 100
97int tilcdc_add_external_encoders(struct drm_device *dev) 101static
102struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
103 struct drm_encoder *encoder)
98{ 104{
99 struct tilcdc_drm_private *priv = dev->dev_private;
100 struct drm_connector *connector; 105 struct drm_connector *connector;
101 int num_internal_connectors = priv->num_connectors; 106 int i;
102 107
103 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 108 list_for_each_entry(connector, &ddev->mode_config.connector_list, head)
104 bool found = false; 109 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
105 int i, ret; 110 if (connector->encoder_ids[i] == encoder->base.id)
106 111 return connector;
107 for (i = 0; i < num_internal_connectors; i++) 112
108 if (connector == priv->connectors[i]) 113 dev_err(ddev->dev, "No connector found for %s encoder (id %d)\n",
109 found = true; 114 encoder->name, encoder->base.id);
110 if (!found) { 115
111 ret = tilcdc_add_external_encoder(dev, connector); 116 return NULL;
112 if (ret) 117}
113 return ret; 118
114 } 119int tilcdc_add_component_encoder(struct drm_device *ddev)
120{
121 struct tilcdc_drm_private *priv = ddev->dev_private;
122 struct drm_connector *connector;
123 struct drm_encoder *encoder;
124
125 list_for_each_entry(encoder, &ddev->mode_config.encoder_list, head)
126 if (encoder->possible_crtcs & (1 << priv->crtc->index))
127 break;
128
129 if (!encoder) {
130 dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__);
131 return -ENODEV;
115 } 132 }
116 return 0; 133
134 connector = tilcdc_encoder_find_connector(ddev, encoder);
135
136 if (!connector)
137 return -ENODEV;
138
139 /* Only tda998x is supported at the moment. */
140 tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
141 tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
142
143 return tilcdc_add_external_connector(ddev, connector);
117} 144}
118 145
119void tilcdc_remove_external_encoders(struct drm_device *dev) 146void tilcdc_remove_external_device(struct drm_device *dev)
120{ 147{
121 struct tilcdc_drm_private *priv = dev->dev_private; 148 struct tilcdc_drm_private *priv = dev->dev_private;
122 int i;
123 149
124 /* Restore the original helper functions, if any. */ 150 /* Restore the original helper functions, if any. */
125 for (i = 0; i < priv->num_connectors; i++) 151 if (IS_ERR(priv->connector_funcs))
126 if (IS_ERR(priv->connector_funcs[i])) 152 drm_connector_helper_add(priv->external_connector, NULL);
127 drm_connector_helper_add(priv->connectors[i], NULL); 153 else if (priv->connector_funcs)
128 else if (priv->connector_funcs[i]) 154 drm_connector_helper_add(priv->external_connector,
129 drm_connector_helper_add(priv->connectors[i], 155 priv->connector_funcs);
130 priv->connector_funcs[i]); 156}
157
158static const struct drm_encoder_funcs tilcdc_external_encoder_funcs = {
159 .destroy = drm_encoder_cleanup,
160};
161
162static
163int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
164{
165 struct tilcdc_drm_private *priv = ddev->dev_private;
166 struct drm_connector *connector;
167 int ret;
168
169 priv->external_encoder->possible_crtcs = BIT(0);
170 priv->external_encoder->bridge = bridge;
171 bridge->encoder = priv->external_encoder;
172
173 ret = drm_bridge_attach(ddev, bridge);
174 if (ret) {
175 dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret);
176 return ret;
177 }
178
179 tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default);
180
181 connector = tilcdc_encoder_find_connector(ddev, priv->external_encoder);
182 if (!connector)
183 return -ENODEV;
184
185 ret = tilcdc_add_external_connector(ddev, connector);
186
187 return ret;
188}
189
190static int tilcdc_node_has_port(struct device_node *dev_node)
191{
192 struct device_node *node;
193
194 node = of_get_child_by_name(dev_node, "ports");
195 if (!node)
196 node = of_get_child_by_name(dev_node, "port");
197 if (!node)
198 return 0;
199 of_node_put(node);
200
201 return 1;
202}
203
204static
205struct device_node *tilcdc_get_remote_node(struct device_node *node)
206{
207 struct device_node *ep;
208 struct device_node *parent;
209
210 if (!tilcdc_node_has_port(node))
211 return NULL;
212
213 ep = of_graph_get_next_endpoint(node, NULL);
214 if (!ep)
215 return NULL;
216
217 parent = of_graph_get_remote_port_parent(ep);
218 of_node_put(ep);
219
220 return parent;
221}
222
223int tilcdc_attach_external_device(struct drm_device *ddev)
224{
225 struct tilcdc_drm_private *priv = ddev->dev_private;
226 struct device_node *remote_node;
227 struct drm_bridge *bridge;
228 int ret;
229
230 remote_node = tilcdc_get_remote_node(ddev->dev->of_node);
231 if (!remote_node)
232 return 0;
233
234 bridge = of_drm_find_bridge(remote_node);
235 of_node_put(remote_node);
236 if (!bridge)
237 return -EPROBE_DEFER;
238
239 priv->external_encoder = devm_kzalloc(ddev->dev,
240 sizeof(*priv->external_encoder),
241 GFP_KERNEL);
242 if (!priv->external_encoder)
243 return -ENOMEM;
244
245 ret = drm_encoder_init(ddev, priv->external_encoder,
246 &tilcdc_external_encoder_funcs,
247 DRM_MODE_ENCODER_NONE, NULL);
248 if (ret) {
249 dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret);
250 return ret;
251 }
252
253 ret = tilcdc_attach_bridge(ddev, bridge);
254 if (ret)
255 drm_encoder_cleanup(priv->external_encoder);
256
257 return ret;
131} 258}
132 259
133static int dev_match_of(struct device *dev, void *data) 260static int dev_match_of(struct device *dev, void *data)
@@ -141,16 +268,10 @@ int tilcdc_get_external_components(struct device *dev,
141 struct device_node *node; 268 struct device_node *node;
142 struct device_node *ep = NULL; 269 struct device_node *ep = NULL;
143 int count = 0; 270 int count = 0;
271 int ret = 0;
144 272
145 /* Avoid error print by of_graph_get_next_endpoint() if there 273 if (!tilcdc_node_has_port(dev->of_node))
146 * is no ports present.
147 */
148 node = of_get_child_by_name(dev->of_node, "ports");
149 if (!node)
150 node = of_get_child_by_name(dev->of_node, "port");
151 if (!node)
152 return 0; 274 return 0;
153 of_node_put(node);
154 275
155 while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) { 276 while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
156 node = of_graph_get_remote_port_parent(ep); 277 node = of_graph_get_remote_port_parent(ep);
@@ -160,17 +281,20 @@ int tilcdc_get_external_components(struct device *dev,
160 } 281 }
161 282
162 dev_dbg(dev, "Subdevice node '%s' found\n", node->name); 283 dev_dbg(dev, "Subdevice node '%s' found\n", node->name);
163 if (match)
164 drm_of_component_match_add(dev, match, dev_match_of,
165 node);
166 of_node_put(node);
167 count++;
168 }
169 284
170 if (count > 1) { 285 if (of_device_is_compatible(node, "nxp,tda998x")) {
171 dev_err(dev, "Only one external encoder is supported\n"); 286 if (match)
172 return -EINVAL; 287 drm_of_component_match_add(dev, match,
288 dev_match_of, node);
289 ret = 1;
290 }
291
292 of_node_put(node);
293 if (count++ > 1) {
294 dev_err(dev, "Only one port is supported\n");
295 return -EINVAL;
296 }
173 } 297 }
174 298
175 return count; 299 return ret;
176} 300}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h
index c700e0c1623e..763d18f006c7 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h
@@ -18,8 +18,9 @@
18#ifndef __TILCDC_EXTERNAL_H__ 18#ifndef __TILCDC_EXTERNAL_H__
19#define __TILCDC_EXTERNAL_H__ 19#define __TILCDC_EXTERNAL_H__
20 20
21int tilcdc_add_external_encoders(struct drm_device *dev); 21int tilcdc_add_component_encoder(struct drm_device *dev);
22void tilcdc_remove_external_encoders(struct drm_device *dev); 22void tilcdc_remove_external_device(struct drm_device *dev);
23int tilcdc_get_external_components(struct device *dev, 23int tilcdc_get_external_components(struct device *dev,
24 struct component_match **match); 24 struct component_match **match);
25int tilcdc_attach_external_device(struct drm_device *ddev);
25#endif /* __TILCDC_SLAVE_H__ */ 26#endif /* __TILCDC_SLAVE_H__ */