1
2
3
4
5
6
7#include <drm/drm_atomic_helper.h>
8#include <drm/drm_bridge.h>
9#include <drm/drm_connector.h>
10#include <drm/drm_encoder.h>
11#include <drm/drm_modeset_helper_vtables.h>
12#include <drm/drm_of.h>
13#include <drm/drm_panel.h>
14#include <drm/drm_print.h>
15#include <drm/drm_probe_helper.h>
16
17struct panel_bridge {
18 struct drm_bridge bridge;
19 struct drm_connector connector;
20 struct drm_panel *panel;
21 u32 connector_type;
22};
23
24static inline struct panel_bridge *
25drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
26{
27 return container_of(bridge, struct panel_bridge, bridge);
28}
29
30static inline struct panel_bridge *
31drm_connector_to_panel_bridge(struct drm_connector *connector)
32{
33 return container_of(connector, struct panel_bridge, connector);
34}
35
36static int panel_bridge_connector_get_modes(struct drm_connector *connector)
37{
38 struct panel_bridge *panel_bridge =
39 drm_connector_to_panel_bridge(connector);
40
41 return drm_panel_get_modes(panel_bridge->panel, connector);
42}
43
44static const struct drm_connector_helper_funcs
45panel_bridge_connector_helper_funcs = {
46 .get_modes = panel_bridge_connector_get_modes,
47};
48
49static const struct drm_connector_funcs panel_bridge_connector_funcs = {
50 .reset = drm_atomic_helper_connector_reset,
51 .fill_modes = drm_helper_probe_single_connector_modes,
52 .destroy = drm_connector_cleanup,
53 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
54 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
55};
56
57static int panel_bridge_attach(struct drm_bridge *bridge,
58 enum drm_bridge_attach_flags flags)
59{
60 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
61 struct drm_connector *connector = &panel_bridge->connector;
62 int ret;
63
64 if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
65 return 0;
66
67 if (!bridge->encoder) {
68 DRM_ERROR("Missing encoder\n");
69 return -ENODEV;
70 }
71
72 drm_connector_helper_add(connector,
73 &panel_bridge_connector_helper_funcs);
74
75 ret = drm_connector_init(bridge->dev, connector,
76 &panel_bridge_connector_funcs,
77 panel_bridge->connector_type);
78 if (ret) {
79 DRM_ERROR("Failed to initialize connector\n");
80 return ret;
81 }
82
83 drm_connector_attach_encoder(&panel_bridge->connector,
84 bridge->encoder);
85
86 return 0;
87}
88
89static void panel_bridge_detach(struct drm_bridge *bridge)
90{
91 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
92 struct drm_connector *connector = &panel_bridge->connector;
93
94
95
96
97
98
99
100
101 if (connector->dev)
102 drm_connector_cleanup(connector);
103}
104
105static void panel_bridge_pre_enable(struct drm_bridge *bridge)
106{
107 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
108
109 drm_panel_prepare(panel_bridge->panel);
110}
111
112static void panel_bridge_enable(struct drm_bridge *bridge)
113{
114 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
115
116 drm_panel_enable(panel_bridge->panel);
117}
118
119static void panel_bridge_disable(struct drm_bridge *bridge)
120{
121 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
122
123 drm_panel_disable(panel_bridge->panel);
124}
125
126static void panel_bridge_post_disable(struct drm_bridge *bridge)
127{
128 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
129
130 drm_panel_unprepare(panel_bridge->panel);
131}
132
133static int panel_bridge_get_modes(struct drm_bridge *bridge,
134 struct drm_connector *connector)
135{
136 struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
137
138 return drm_panel_get_modes(panel_bridge->panel, connector);
139}
140
141static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
142 .attach = panel_bridge_attach,
143 .detach = panel_bridge_detach,
144 .pre_enable = panel_bridge_pre_enable,
145 .enable = panel_bridge_enable,
146 .disable = panel_bridge_disable,
147 .post_disable = panel_bridge_post_disable,
148 .get_modes = panel_bridge_get_modes,
149 .atomic_reset = drm_atomic_helper_bridge_reset,
150 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
151 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
152 .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
153};
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
181{
182 if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
183 return ERR_PTR(-EINVAL);
184
185 return drm_panel_bridge_add_typed(panel, panel->connector_type);
186}
187EXPORT_SYMBOL(drm_panel_bridge_add);
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
203 u32 connector_type)
204{
205 struct panel_bridge *panel_bridge;
206
207 if (!panel)
208 return ERR_PTR(-EINVAL);
209
210 panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
211 GFP_KERNEL);
212 if (!panel_bridge)
213 return ERR_PTR(-ENOMEM);
214
215 panel_bridge->connector_type = connector_type;
216 panel_bridge->panel = panel;
217
218 panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
219#ifdef CONFIG_OF
220 panel_bridge->bridge.of_node = panel->dev->of_node;
221#endif
222 panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
223 panel_bridge->bridge.type = connector_type;
224
225 drm_bridge_add(&panel_bridge->bridge);
226
227 return &panel_bridge->bridge;
228}
229EXPORT_SYMBOL(drm_panel_bridge_add_typed);
230
231
232
233
234
235
236
237void drm_panel_bridge_remove(struct drm_bridge *bridge)
238{
239 struct panel_bridge *panel_bridge;
240
241 if (!bridge)
242 return;
243
244 if (bridge->funcs != &panel_bridge_bridge_funcs)
245 return;
246
247 panel_bridge = drm_bridge_to_panel_bridge(bridge);
248
249 drm_bridge_remove(bridge);
250 devm_kfree(panel_bridge->panel->dev, bridge);
251}
252EXPORT_SYMBOL(drm_panel_bridge_remove);
253
254static void devm_drm_panel_bridge_release(struct device *dev, void *res)
255{
256 struct drm_bridge **bridge = res;
257
258 drm_panel_bridge_remove(*bridge);
259}
260
261
262
263
264
265
266
267
268
269
270struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
271 struct drm_panel *panel)
272{
273 if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
274 return ERR_PTR(-EINVAL);
275
276 return devm_drm_panel_bridge_add_typed(dev, panel,
277 panel->connector_type);
278}
279EXPORT_SYMBOL(devm_drm_panel_bridge_add);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
296 struct drm_panel *panel,
297 u32 connector_type)
298{
299 struct drm_bridge **ptr, *bridge;
300
301 ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
302 GFP_KERNEL);
303 if (!ptr)
304 return ERR_PTR(-ENOMEM);
305
306 bridge = drm_panel_bridge_add_typed(panel, connector_type);
307 if (!IS_ERR(bridge)) {
308 *ptr = bridge;
309 devres_add(dev, ptr);
310 } else {
311 devres_free(ptr);
312 }
313
314 return bridge;
315}
316EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
317
318
319
320
321
322
323
324
325
326
327struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
328{
329 struct panel_bridge *panel_bridge;
330
331 panel_bridge = drm_bridge_to_panel_bridge(bridge);
332
333 return &panel_bridge->connector;
334}
335EXPORT_SYMBOL(drm_panel_bridge_connector);
336
337#ifdef CONFIG_OF
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
353 struct device_node *np,
354 u32 port, u32 endpoint)
355{
356 struct drm_bridge *bridge;
357 struct drm_panel *panel;
358 int ret;
359
360 ret = drm_of_find_panel_or_bridge(np, port, endpoint,
361 &panel, &bridge);
362 if (ret)
363 return ERR_PTR(ret);
364
365 if (panel)
366 bridge = devm_drm_panel_bridge_add(dev, panel);
367
368 return bridge;
369}
370EXPORT_SYMBOL(devm_drm_of_get_bridge);
371#endif
372