OSDN Git Service

Merge tag 'drm-next-2022-03-24' of git://anongit.freedesktop.org/drm/drm
[uclinux-h8/linux.git] / drivers / gpu / drm / tiny / panel-mipi-dbi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * DRM driver for MIPI DBI compatible display panels
4  *
5  * Copyright 2022 Noralf Trønnes
6  */
7
8 #include <linux/backlight.h>
9 #include <linux/delay.h>
10 #include <linux/firmware.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/module.h>
13 #include <linux/property.h>
14 #include <linux/regulator/consumer.h>
15 #include <linux/spi/spi.h>
16
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_drv.h>
19 #include <drm/drm_fb_helper.h>
20 #include <drm/drm_gem_atomic_helper.h>
21 #include <drm/drm_gem_cma_helper.h>
22 #include <drm/drm_managed.h>
23 #include <drm/drm_mipi_dbi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_modeset_helper.h>
26
27 #include <video/mipi_display.h>
28
29 static const u8 panel_mipi_dbi_magic[15] = { 'M', 'I', 'P', 'I', ' ', 'D', 'B', 'I',
30                                              0, 0, 0, 0, 0, 0, 0 };
31
32 /*
33  * The display controller configuration is stored in a firmware file.
34  * The Device Tree 'compatible' property value with a '.bin' suffix is passed
35  * to request_firmware() to fetch this file.
36  */
37 struct panel_mipi_dbi_config {
38         /* Magic string: panel_mipi_dbi_magic */
39         u8 magic[15];
40
41         /* Config file format version */
42         u8 file_format_version;
43
44         /*
45          * MIPI commands to execute when the display pipeline is enabled.
46          * This is used to configure the display controller.
47          *
48          * The commands are stored in a byte array with the format:
49          *     command, num_parameters, [ parameter, ...], command, ...
50          *
51          * Some commands require a pause before the next command can be received.
52          * Inserting a delay in the command sequence is done by using the NOP command with one
53          * parameter: delay in miliseconds (the No Operation command is part of the MIPI Display
54          * Command Set where it has no parameters).
55          *
56          * Example:
57          *     command 0x11
58          *     sleep 120ms
59          *     command 0xb1 parameters 0x01, 0x2c, 0x2d
60          *     command 0x29
61          *
62          * Byte sequence:
63          *     0x11 0x00
64          *     0x00 0x01 0x78
65          *     0xb1 0x03 0x01 0x2c 0x2d
66          *     0x29 0x00
67          */
68         u8 commands[];
69 };
70
71 struct panel_mipi_dbi_commands {
72         const u8 *buf;
73         size_t len;
74 };
75
76 static struct panel_mipi_dbi_commands *
77 panel_mipi_dbi_check_commands(struct device *dev, const struct firmware *fw)
78 {
79         const struct panel_mipi_dbi_config *config = (struct panel_mipi_dbi_config *)fw->data;
80         struct panel_mipi_dbi_commands *commands;
81         size_t size = fw->size, commands_len;
82         unsigned int i = 0;
83
84         if (size < sizeof(*config) + 2) { /* At least 1 command */
85                 dev_err(dev, "config: file size=%zu is too small\n", size);
86                 return ERR_PTR(-EINVAL);
87         }
88
89         if (memcmp(config->magic, panel_mipi_dbi_magic, sizeof(config->magic))) {
90                 dev_err(dev, "config: Bad magic: %15ph\n", config->magic);
91                 return ERR_PTR(-EINVAL);
92         }
93
94         if (config->file_format_version != 1) {
95                 dev_err(dev, "config: version=%u is not supported\n", config->file_format_version);
96                 return ERR_PTR(-EINVAL);
97         }
98
99         drm_dev_dbg(dev, DRM_UT_DRIVER, "size=%zu version=%u\n", size, config->file_format_version);
100
101         commands_len = size - sizeof(*config);
102
103         while ((i + 1) < commands_len) {
104                 u8 command = config->commands[i++];
105                 u8 num_parameters = config->commands[i++];
106                 const u8 *parameters = &config->commands[i];
107
108                 i += num_parameters;
109                 if (i > commands_len) {
110                         dev_err(dev, "config: command=0x%02x num_parameters=%u overflows\n",
111                                 command, num_parameters);
112                         return ERR_PTR(-EINVAL);
113                 }
114
115                 if (command == 0x00 && num_parameters == 1)
116                         drm_dev_dbg(dev, DRM_UT_DRIVER, "sleep %ums\n", parameters[0]);
117                 else
118                         drm_dev_dbg(dev, DRM_UT_DRIVER, "command %02x %*ph\n",
119                                     command, num_parameters, parameters);
120         }
121
122         if (i != commands_len) {
123                 dev_err(dev, "config: malformed command array\n");
124                 return ERR_PTR(-EINVAL);
125         }
126
127         commands = devm_kzalloc(dev, sizeof(*commands), GFP_KERNEL);
128         if (!commands)
129                 return ERR_PTR(-ENOMEM);
130
131         commands->len = commands_len;
132         commands->buf = devm_kmemdup(dev, config->commands, commands->len, GFP_KERNEL);
133         if (!commands->buf)
134                 return ERR_PTR(-ENOMEM);
135
136         return commands;
137 }
138
139 static struct panel_mipi_dbi_commands *panel_mipi_dbi_commands_from_fw(struct device *dev)
140 {
141         struct panel_mipi_dbi_commands *commands;
142         const struct firmware *fw;
143         const char *compatible;
144         char fw_name[40];
145         int ret;
146
147         ret = of_property_read_string_index(dev->of_node, "compatible", 0, &compatible);
148         if (ret)
149                 return ERR_PTR(ret);
150
151         snprintf(fw_name, sizeof(fw_name), "%s.bin", compatible);
152         ret = request_firmware(&fw, fw_name, dev);
153         if (ret) {
154                 dev_err(dev, "No config file found for compatible '%s' (error=%d)\n",
155                         compatible, ret);
156
157                 return ERR_PTR(ret);
158         }
159
160         commands = panel_mipi_dbi_check_commands(dev, fw);
161         release_firmware(fw);
162
163         return commands;
164 }
165
166 static void panel_mipi_dbi_commands_execute(struct mipi_dbi *dbi,
167                                             struct panel_mipi_dbi_commands *commands)
168 {
169         unsigned int i = 0;
170
171         if (!commands)
172                 return;
173
174         while (i < commands->len) {
175                 u8 command = commands->buf[i++];
176                 u8 num_parameters = commands->buf[i++];
177                 const u8 *parameters = &commands->buf[i];
178
179                 if (command == 0x00 && num_parameters == 1)
180                         msleep(parameters[0]);
181                 else if (num_parameters)
182                         mipi_dbi_command_stackbuf(dbi, command, parameters, num_parameters);
183                 else
184                         mipi_dbi_command(dbi, command);
185
186                 i += num_parameters;
187         }
188 }
189
190 static void panel_mipi_dbi_enable(struct drm_simple_display_pipe *pipe,
191                                   struct drm_crtc_state *crtc_state,
192                                   struct drm_plane_state *plane_state)
193 {
194         struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
195         struct mipi_dbi *dbi = &dbidev->dbi;
196         int ret, idx;
197
198         if (!drm_dev_enter(pipe->crtc.dev, &idx))
199                 return;
200
201         drm_dbg(pipe->crtc.dev, "\n");
202
203         ret = mipi_dbi_poweron_conditional_reset(dbidev);
204         if (ret < 0)
205                 goto out_exit;
206         if (!ret)
207                 panel_mipi_dbi_commands_execute(dbi, dbidev->driver_private);
208
209         mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
210 out_exit:
211         drm_dev_exit(idx);
212 }
213
214 static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = {
215         .enable = panel_mipi_dbi_enable,
216         .disable = mipi_dbi_pipe_disable,
217         .update = mipi_dbi_pipe_update,
218 };
219
220 DEFINE_DRM_GEM_CMA_FOPS(panel_mipi_dbi_fops);
221
222 static const struct drm_driver panel_mipi_dbi_driver = {
223         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
224         .fops                   = &panel_mipi_dbi_fops,
225         DRM_GEM_CMA_DRIVER_OPS_VMAP,
226         .debugfs_init           = mipi_dbi_debugfs_init,
227         .name                   = "panel-mipi-dbi",
228         .desc                   = "MIPI DBI compatible display panel",
229         .date                   = "20220103",
230         .major                  = 1,
231         .minor                  = 0,
232 };
233
234 static int panel_mipi_dbi_get_mode(struct mipi_dbi_dev *dbidev, struct drm_display_mode *mode)
235 {
236         struct device *dev = dbidev->drm.dev;
237         u16 hback_porch, vback_porch;
238         int ret;
239
240         ret = of_get_drm_panel_display_mode(dev->of_node, mode, NULL);
241         if (ret) {
242                 dev_err(dev, "%pOF: failed to get panel-timing (error=%d)\n", dev->of_node, ret);
243                 return ret;
244         }
245
246         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
247
248         hback_porch = mode->htotal - mode->hsync_end;
249         vback_porch = mode->vtotal - mode->vsync_end;
250
251         /*
252          * Make sure width and height are set and that only back porch and
253          * pixelclock are set in the other timing values. Also check that
254          * width and height don't exceed the 16-bit value specified by MIPI DCS.
255          */
256         if (!mode->hdisplay || !mode->vdisplay || mode->flags ||
257             mode->hsync_end > mode->hdisplay || (hback_porch + mode->hdisplay) > 0xffff ||
258             mode->vsync_end > mode->vdisplay || (vback_porch + mode->vdisplay) > 0xffff) {
259                 dev_err(dev, "%pOF: panel-timing out of bounds\n", dev->of_node);
260                 return -EINVAL;
261         }
262
263         /* The driver doesn't use the pixel clock but it is mandatory so fake one if not set */
264         if (!mode->clock)
265                 mode->clock = mode->htotal * mode->vtotal * 60 / 1000;
266
267         dbidev->top_offset = vback_porch;
268         dbidev->left_offset = hback_porch;
269
270         return 0;
271 }
272
273 static int panel_mipi_dbi_spi_probe(struct spi_device *spi)
274 {
275         struct device *dev = &spi->dev;
276         struct drm_display_mode mode;
277         struct mipi_dbi_dev *dbidev;
278         struct drm_device *drm;
279         struct mipi_dbi *dbi;
280         struct gpio_desc *dc;
281         int ret;
282
283         dbidev = devm_drm_dev_alloc(dev, &panel_mipi_dbi_driver, struct mipi_dbi_dev, drm);
284         if (IS_ERR(dbidev))
285                 return PTR_ERR(dbidev);
286
287         dbi = &dbidev->dbi;
288         drm = &dbidev->drm;
289
290         ret = panel_mipi_dbi_get_mode(dbidev, &mode);
291         if (ret)
292                 return ret;
293
294         dbidev->regulator = devm_regulator_get(dev, "power");
295         if (IS_ERR(dbidev->regulator))
296                 return dev_err_probe(dev, PTR_ERR(dbidev->regulator),
297                                      "Failed to get regulator 'power'\n");
298
299         dbidev->backlight = devm_of_find_backlight(dev);
300         if (IS_ERR(dbidev->backlight))
301                 return dev_err_probe(dev, PTR_ERR(dbidev->backlight), "Failed to get backlight\n");
302
303         dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
304         if (IS_ERR(dbi->reset))
305                 return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
306
307         dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
308         if (IS_ERR(dc))
309                 return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
310
311         ret = mipi_dbi_spi_init(spi, dbi, dc);
312         if (ret)
313                 return ret;
314
315         if (device_property_present(dev, "write-only"))
316                 dbi->read_commands = NULL;
317
318         dbidev->driver_private = panel_mipi_dbi_commands_from_fw(dev);
319         if (IS_ERR(dbidev->driver_private))
320                 return PTR_ERR(dbidev->driver_private);
321
322         ret = mipi_dbi_dev_init(dbidev, &panel_mipi_dbi_pipe_funcs, &mode, 0);
323         if (ret)
324                 return ret;
325
326         drm_mode_config_reset(drm);
327
328         ret = drm_dev_register(drm, 0);
329         if (ret)
330                 return ret;
331
332         spi_set_drvdata(spi, drm);
333
334         drm_fbdev_generic_setup(drm, 0);
335
336         return 0;
337 }
338
339 static void panel_mipi_dbi_spi_remove(struct spi_device *spi)
340 {
341         struct drm_device *drm = spi_get_drvdata(spi);
342
343         drm_dev_unplug(drm);
344         drm_atomic_helper_shutdown(drm);
345 }
346
347 static void panel_mipi_dbi_spi_shutdown(struct spi_device *spi)
348 {
349         drm_atomic_helper_shutdown(spi_get_drvdata(spi));
350 }
351
352 static int __maybe_unused panel_mipi_dbi_pm_suspend(struct device *dev)
353 {
354         return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
355 }
356
357 static int __maybe_unused panel_mipi_dbi_pm_resume(struct device *dev)
358 {
359         drm_mode_config_helper_resume(dev_get_drvdata(dev));
360
361         return 0;
362 }
363
364 static const struct dev_pm_ops panel_mipi_dbi_pm_ops = {
365         SET_SYSTEM_SLEEP_PM_OPS(panel_mipi_dbi_pm_suspend, panel_mipi_dbi_pm_resume)
366 };
367
368 static const struct of_device_id panel_mipi_dbi_spi_of_match[] = {
369         { .compatible = "panel-mipi-dbi-spi" },
370         {},
371 };
372 MODULE_DEVICE_TABLE(of, panel_mipi_dbi_spi_of_match);
373
374 static const struct spi_device_id panel_mipi_dbi_spi_id[] = {
375         { "panel-mipi-dbi-spi", 0 },
376         { },
377 };
378 MODULE_DEVICE_TABLE(spi, panel_mipi_dbi_spi_id);
379
380 static struct spi_driver panel_mipi_dbi_spi_driver = {
381         .driver = {
382                 .name = "panel-mipi-dbi-spi",
383                 .owner = THIS_MODULE,
384                 .of_match_table = panel_mipi_dbi_spi_of_match,
385                 .pm = &panel_mipi_dbi_pm_ops,
386         },
387         .id_table = panel_mipi_dbi_spi_id,
388         .probe = panel_mipi_dbi_spi_probe,
389         .remove = panel_mipi_dbi_spi_remove,
390         .shutdown = panel_mipi_dbi_spi_shutdown,
391 };
392 module_spi_driver(panel_mipi_dbi_spi_driver);
393
394 MODULE_DESCRIPTION("MIPI DBI compatible display panel driver");
395 MODULE_AUTHOR("Noralf Trønnes");
396 MODULE_LICENSE("GPL");