hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/gpu/drm/drm_panel.c
....@@ -21,11 +21,13 @@
2121 * DEALINGS IN THE SOFTWARE.
2222 */
2323
24
+#include <linux/backlight.h>
2425 #include <linux/err.h>
2526 #include <linux/module.h>
2627
2728 #include <drm/drm_crtc.h>
2829 #include <drm/drm_panel.h>
30
+#include <drm/drm_print.h>
2931
3032 static DEFINE_MUTEX(panel_lock);
3133 static LIST_HEAD(panel_list);
....@@ -36,19 +38,29 @@
3638 * The DRM panel helpers allow drivers to register panel objects with a
3739 * central registry and provide functions to retrieve those panels in display
3840 * drivers.
41
+ *
42
+ * For easy integration into drivers using the &drm_bridge infrastructure please
43
+ * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
3944 */
4045
4146 /**
4247 * drm_panel_init - initialize a panel
4348 * @panel: DRM panel
49
+ * @dev: parent device of the panel
50
+ * @funcs: panel operations
51
+ * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to
52
+ * the panel interface
4453 *
45
- * Sets up internal fields of the panel so that it can subsequently be added
46
- * to the registry.
54
+ * Initialize the panel structure for subsequent registration with
55
+ * drm_panel_add().
4756 */
48
-void drm_panel_init(struct drm_panel *panel)
57
+void drm_panel_init(struct drm_panel *panel, struct device *dev,
58
+ const struct drm_panel_funcs *funcs, int connector_type)
4959 {
5060 INIT_LIST_HEAD(&panel->list);
51
- BLOCKING_INIT_NOTIFIER_HEAD(&panel->nh);
61
+ panel->dev = dev;
62
+ panel->funcs = funcs;
63
+ panel->connector_type = connector_type;
5264 }
5365 EXPORT_SYMBOL(drm_panel_init);
5466
....@@ -58,16 +70,12 @@
5870 *
5971 * Add a panel to the global registry so that it can be looked up by display
6072 * drivers.
61
- *
62
- * Return: 0 on success or a negative error code on failure.
6373 */
64
-int drm_panel_add(struct drm_panel *panel)
74
+void drm_panel_add(struct drm_panel *panel)
6575 {
6676 mutex_lock(&panel_lock);
6777 list_add_tail(&panel->list, &panel_list);
6878 mutex_unlock(&panel_lock);
69
-
70
- return 0;
7179 }
7280 EXPORT_SYMBOL(drm_panel_add);
7381
....@@ -86,52 +94,134 @@
8694 EXPORT_SYMBOL(drm_panel_remove);
8795
8896 /**
89
- * drm_panel_attach - attach a panel to a connector
97
+ * drm_panel_prepare - power on a panel
98
+ * @panel: DRM panel
99
+ *
100
+ * Calling this function will enable power and deassert any reset signals to
101
+ * the panel. After this has completed it is possible to communicate with any
102
+ * integrated circuitry via a command bus.
103
+ *
104
+ * Return: 0 on success or a negative error code on failure.
105
+ */
106
+int drm_panel_prepare(struct drm_panel *panel)
107
+{
108
+ if (!panel)
109
+ return -EINVAL;
110
+
111
+ if (panel->funcs && panel->funcs->prepare)
112
+ return panel->funcs->prepare(panel);
113
+
114
+ return 0;
115
+}
116
+EXPORT_SYMBOL(drm_panel_prepare);
117
+
118
+/**
119
+ * drm_panel_unprepare - power off a panel
120
+ * @panel: DRM panel
121
+ *
122
+ * Calling this function will completely power off a panel (assert the panel's
123
+ * reset, turn off power supplies, ...). After this function has completed, it
124
+ * is usually no longer possible to communicate with the panel until another
125
+ * call to drm_panel_prepare().
126
+ *
127
+ * Return: 0 on success or a negative error code on failure.
128
+ */
129
+int drm_panel_unprepare(struct drm_panel *panel)
130
+{
131
+ if (!panel)
132
+ return -EINVAL;
133
+
134
+ if (panel->funcs && panel->funcs->unprepare)
135
+ return panel->funcs->unprepare(panel);
136
+
137
+ return 0;
138
+}
139
+EXPORT_SYMBOL(drm_panel_unprepare);
140
+
141
+/**
142
+ * drm_panel_enable - enable a panel
143
+ * @panel: DRM panel
144
+ *
145
+ * Calling this function will cause the panel display drivers to be turned on
146
+ * and the backlight to be enabled. Content will be visible on screen after
147
+ * this call completes.
148
+ *
149
+ * Return: 0 on success or a negative error code on failure.
150
+ */
151
+int drm_panel_enable(struct drm_panel *panel)
152
+{
153
+ int ret;
154
+
155
+ if (!panel)
156
+ return -EINVAL;
157
+
158
+ if (panel->funcs && panel->funcs->enable) {
159
+ ret = panel->funcs->enable(panel);
160
+ if (ret < 0)
161
+ return ret;
162
+ }
163
+
164
+ ret = backlight_enable(panel->backlight);
165
+ if (ret < 0)
166
+ DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
167
+ ret);
168
+
169
+ return 0;
170
+}
171
+EXPORT_SYMBOL(drm_panel_enable);
172
+
173
+/**
174
+ * drm_panel_disable - disable a panel
175
+ * @panel: DRM panel
176
+ *
177
+ * This will typically turn off the panel's backlight or disable the display
178
+ * drivers. For smart panels it should still be possible to communicate with
179
+ * the integrated circuitry via any command bus after this call.
180
+ *
181
+ * Return: 0 on success or a negative error code on failure.
182
+ */
183
+int drm_panel_disable(struct drm_panel *panel)
184
+{
185
+ int ret;
186
+
187
+ if (!panel)
188
+ return -EINVAL;
189
+
190
+ ret = backlight_disable(panel->backlight);
191
+ if (ret < 0)
192
+ DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
193
+ ret);
194
+
195
+ if (panel->funcs && panel->funcs->disable)
196
+ return panel->funcs->disable(panel);
197
+
198
+ return 0;
199
+}
200
+EXPORT_SYMBOL(drm_panel_disable);
201
+
202
+/**
203
+ * drm_panel_get_modes - probe the available display modes of a panel
90204 * @panel: DRM panel
91205 * @connector: DRM connector
92206 *
93
- * After obtaining a pointer to a DRM panel a display driver calls this
94
- * function to attach a panel to a connector.
207
+ * The modes probed from the panel are automatically added to the connector
208
+ * that the panel is attached to.
95209 *
96
- * An error is returned if the panel is already attached to another connector.
97
- *
98
- * When unloading, the driver should detach from the panel by calling
99
- * drm_panel_detach().
100
- *
101
- * Return: 0 on success or a negative error code on failure.
210
+ * Return: The number of modes available from the panel on success or a
211
+ * negative error code on failure.
102212 */
103
-int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
213
+int drm_panel_get_modes(struct drm_panel *panel,
214
+ struct drm_connector *connector)
104215 {
105
- if (panel->connector)
106
- return -EBUSY;
216
+ if (!panel)
217
+ return -EINVAL;
107218
108
- panel->connector = connector;
109
- panel->drm = connector->dev;
219
+ if (panel->funcs && panel->funcs->get_modes)
220
+ return panel->funcs->get_modes(panel, connector);
110221
111
- return 0;
222
+ return -EOPNOTSUPP;
112223 }
113
-EXPORT_SYMBOL(drm_panel_attach);
114
-
115
-/**
116
- * drm_panel_detach - detach a panel from a connector
117
- * @panel: DRM panel
118
- *
119
- * Detaches a panel from the connector it is attached to. If a panel is not
120
- * attached to any connector this is effectively a no-op.
121
- *
122
- * This function should not be called by the panel device itself. It
123
- * is only for the drm device that called drm_panel_attach().
124
- *
125
- * Return: 0 on success or a negative error code on failure.
126
- */
127
-int drm_panel_detach(struct drm_panel *panel)
128
-{
129
- panel->connector = NULL;
130
- panel->drm = NULL;
131
-
132
- return 0;
133
-}
134
-EXPORT_SYMBOL(drm_panel_detach);
224
+EXPORT_SYMBOL(drm_panel_get_modes);
135225
136226 #ifdef CONFIG_OF
137227 /**
....@@ -143,7 +233,9 @@
143233 *
144234 * Return: A pointer to the panel registered for the specified device tree
145235 * node or an ERR_PTR() if no panel matching the device tree node can be found.
236
+ *
146237 * Possible error codes returned by this function:
238
+ *
147239 * - EPROBE_DEFER: the panel device has not been probed yet, and the caller
148240 * should retry later
149241 * - ENODEV: the device is not available (status != "okay" or "ok")
....@@ -168,28 +260,89 @@
168260 return ERR_PTR(-EPROBE_DEFER);
169261 }
170262 EXPORT_SYMBOL(of_drm_find_panel);
263
+
264
+/**
265
+ * of_drm_get_panel_orientation - look up the orientation of the panel through
266
+ * the "rotation" binding from a device tree node
267
+ * @np: device tree node of the panel
268
+ * @orientation: orientation enum to be filled in
269
+ *
270
+ * Looks up the rotation of a panel in the device tree. The orientation of the
271
+ * panel is expressed as a property name "rotation" in the device tree. The
272
+ * rotation in the device tree is counter clockwise.
273
+ *
274
+ * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
275
+ * rotation property doesn't exist. Return a negative error code on failure.
276
+ */
277
+int of_drm_get_panel_orientation(const struct device_node *np,
278
+ enum drm_panel_orientation *orientation)
279
+{
280
+ int rotation, ret;
281
+
282
+ ret = of_property_read_u32(np, "rotation", &rotation);
283
+ if (ret == -EINVAL) {
284
+ /* Don't return an error if there's no rotation property. */
285
+ *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
286
+ return 0;
287
+ }
288
+
289
+ if (ret < 0)
290
+ return ret;
291
+
292
+ if (rotation == 0)
293
+ *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
294
+ else if (rotation == 90)
295
+ *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
296
+ else if (rotation == 180)
297
+ *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
298
+ else if (rotation == 270)
299
+ *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
300
+ else
301
+ return -EINVAL;
302
+
303
+ return 0;
304
+}
305
+EXPORT_SYMBOL(of_drm_get_panel_orientation);
171306 #endif
172307
173
-int drm_panel_notifier_register(struct drm_panel *panel,
174
- struct notifier_block *nb)
308
+#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
309
+/**
310
+ * drm_panel_of_backlight - use backlight device node for backlight
311
+ * @panel: DRM panel
312
+ *
313
+ * Use this function to enable backlight handling if your panel
314
+ * uses device tree and has a backlight phandle.
315
+ *
316
+ * When the panel is enabled backlight will be enabled after a
317
+ * successful call to &drm_panel_funcs.enable()
318
+ *
319
+ * When the panel is disabled backlight will be disabled before the
320
+ * call to &drm_panel_funcs.disable().
321
+ *
322
+ * A typical implementation for a panel driver supporting device tree
323
+ * will call this function at probe time. Backlight will then be handled
324
+ * transparently without requiring any intervention from the driver.
325
+ * drm_panel_of_backlight() must be called after the call to drm_panel_init().
326
+ *
327
+ * Return: 0 on success or a negative error code on failure.
328
+ */
329
+int drm_panel_of_backlight(struct drm_panel *panel)
175330 {
176
- return blocking_notifier_chain_register(&panel->nh, nb);
177
-}
178
-EXPORT_SYMBOL_GPL(drm_panel_notifier_register);
331
+ struct backlight_device *backlight;
179332
180
-int drm_panel_notifier_unregister(struct drm_panel *panel,
181
- struct notifier_block *nb)
182
-{
183
- return blocking_notifier_chain_unregister(&panel->nh, nb);
184
-}
185
-EXPORT_SYMBOL_GPL(drm_panel_notifier_unregister);
333
+ if (!panel || !panel->dev)
334
+ return -EINVAL;
186335
187
-int drm_panel_notifier_call_chain(struct drm_panel *panel,
188
- unsigned long val, void *v)
189
-{
190
- return blocking_notifier_call_chain(&panel->nh, val, v);
336
+ backlight = devm_of_find_backlight(panel->dev);
337
+
338
+ if (IS_ERR(backlight))
339
+ return PTR_ERR(backlight);
340
+
341
+ panel->backlight = backlight;
342
+ return 0;
191343 }
192
-EXPORT_SYMBOL_GPL(drm_panel_notifier_call_chain);
344
+EXPORT_SYMBOL(drm_panel_of_backlight);
345
+#endif
193346
194347 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
195348 MODULE_DESCRIPTION("DRM panel infrastructure");