1 From 51fdd3f58bffdab48078bf1659efabbd977c7f16 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 26 Mar 2021 17:06:36 +0000
4 Subject: [PATCH] drm/panel-simple: Add a timing for the Raspberry Pi 7" panel
6 The Raspberry Pi 7" 800x480 panel uses a Toshiba TC358762 DSI
7 to DPI bridge chip, so there is a requirement for the timings
8 to be specified for the end panel. Add such a definition.
10 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12 drm/panel-simple: Populate bpc when using panel-dpi
14 panel-dpi doesn't know the bit depth, so in the same way that
15 DPI is guessed for the connector type, guess that it'll be 8bpc.
17 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
19 drm/panel-simple: Allow the bus format to be read from DT for panel-dpi
21 The "panel-dpi" compatible string configures panel from device tree,
22 but it doesn't provide any way of configuring the bus format (colour
23 representation), nor does it populate it.
25 Add a DT parameter "bus-format" that allows the MEDIA_BUS_FMT_xxx value
26 to be specified from device tree.
28 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
30 drm/panel: simple: add Geekworm MZP280 Panel
32 Add support for the Geekworm MZP280 Panel
34 Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
35 Acked-by: Maxime Ripard <maxime@cerno.tech>
37 drm/panel: simple: Add Innolux AT056tN53V1 5.6" VGA
39 Add support for the Innolux AT056tN53V1 5.6" VGA (640x480) TFT LCD
42 Signed-off-by: Joerg Quinten <aBUGSworstnightmare@gmail.com>
43 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
45 drm/panel: simple: Alter the timing for the Pi 7" DSI display
47 vc4 has always fixed up the timing, so the values defined have
48 never actually appeared on the wire.
49 The display appears to want a slightly longer HFP, so extend
50 the timings and recompute the clock to give the same frame rate.
52 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
54 drm/panel: add panel-dsi
56 Equivalent to panel-dpi for configuring a simple DSI panel with
57 device tree side timings and bus settings.
58 Motiviation is the same as for panel-dpi of wanting to support
59 new simple panels without needing to patch the kernel.
61 Signed-off-by: Timon Skerutsch <kernel@diodes-delight.com>
63 drm/panel-simple: Remove custom handling of orientation
65 The framework now handles reading orientation from DT, therefore
66 remove the custom get_orientation hook from panel-simple.
68 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
70 drm/panel-simple: Fix 7inch panel mode for misalignment
72 The 7inch panel is one line off the screen both horizontally
75 Alter the panel mode to correct this.
77 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
79 drm/panel-simple: Increase pixel clock on Pi 7inch panel
81 The Toshiba bridge is very fussy and doesn't like the CM3
82 output when being told to produce a 27.777MHz pixel clock, which
83 is an almost perfect match to the DSI link integer divider.
85 Increasing to 30MHz will switch the DSI link from 333MHz to 400MHz
86 and makes the bridge happy with the same video timing as works
88 (Pi4 will be using a link frequency of 375MHz due to a 3GHz
91 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
93 .../bindings/display/panel/panel-simple.yaml | 2 +
94 .../media/v4l/subdev-formats.rst | 111 ++++++++
95 drivers/gpu/drm/panel/panel-simple.c | 237 ++++++++++++++++--
96 3 files changed, 328 insertions(+), 22 deletions(-)
98 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
99 +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
100 @@ -154,6 +154,8 @@ properties:
102 # Innolux AT043TN24 4.3" WQVGA TFT LCD panel
104 + # Innolux AT056tN53V1 5.6" VGA (640x480) TFT LCD panel
105 + - innolux,at056tn53v1
106 # Innolux AT070TN92 7.0" WQVGA TFT LCD panel
108 # Innolux G070ACE-L01 7" WVGA (800x480) TFT LCD panel
109 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst
110 +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst
111 @@ -625,6 +625,43 @@ The following tables list existing packe
115 + * .. _MEDIA_BUS_FMT_RGB565_1X24_CPADHI:
117 + - MEDIA_BUS_FMT_RGB565_1X24_CPADHI
152 * .. _MEDIA-BUS-FMT-BGR565-2X8-BE:
154 - MEDIA_BUS_FMT_BGR565_2X8_BE
155 @@ -913,6 +950,43 @@ The following tables list existing packe
159 + * .. _MEDIA-BUS-FMT-BGR666-1X18:
161 + - MEDIA_BUS_FMT-BGR666_1X18
196 * .. _MEDIA-BUS-FMT-RGB666-1X18:
198 - MEDIA_BUS_FMT_RGB666_1X18
199 @@ -1096,6 +1170,43 @@ The following tables list existing packe
203 + * .. _MEDIA-BUS-FMT-BGR666-1X24_CPADHI:
205 + - MEDIA_BUS_FMT_BGR666_1X24_CPADHI
240 * .. _MEDIA-BUS-FMT-RGB666-1X24_CPADHI:
242 - MEDIA_BUS_FMT_RGB666_1X24_CPADHI
243 --- a/drivers/gpu/drm/panel/panel-simple.c
244 +++ b/drivers/gpu/drm/panel/panel-simple.c
245 @@ -151,8 +151,6 @@ struct panel_simple {
246 const struct drm_edid *drm_edid;
248 struct drm_display_mode override_mode;
250 - enum drm_panel_orientation orientation;
253 static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
254 @@ -387,12 +385,6 @@ static int panel_simple_get_modes(struct
255 /* add hard-coded panel modes */
256 num += panel_simple_get_non_edid_modes(p, connector);
259 - * TODO: Remove once all drm drivers call
260 - * drm_connector_set_orientation_from_panel()
262 - drm_connector_set_panel_orientation(connector, p->orientation);
267 @@ -413,20 +405,12 @@ static int panel_simple_get_timings(stru
268 return p->desc->num_timings;
271 -static enum drm_panel_orientation panel_simple_get_orientation(struct drm_panel *panel)
273 - struct panel_simple *p = to_panel_simple(panel);
275 - return p->orientation;
278 static const struct drm_panel_funcs panel_simple_funcs = {
279 .disable = panel_simple_disable,
280 .unprepare = panel_simple_unprepare,
281 .prepare = panel_simple_prepare,
282 .enable = panel_simple_enable,
283 .get_modes = panel_simple_get_modes,
284 - .get_orientation = panel_simple_get_orientation,
285 .get_timings = panel_simple_get_timings,
288 @@ -463,6 +447,7 @@ static int panel_dpi_probe(struct device
290 of_property_read_u32(np, "width-mm", &desc->size.width);
291 of_property_read_u32(np, "height-mm", &desc->size.height);
292 + of_property_read_u32(np, "bus-format", &desc->bus_format);
294 /* Extract bus_flags from display_timing */
296 @@ -472,6 +457,8 @@ static int panel_dpi_probe(struct device
298 /* We do not know the connector for the DT node, so guess it */
299 desc->connector_type = DRM_MODE_CONNECTOR_DPI;
300 + /* Likewise for the bit depth. */
305 @@ -595,12 +582,6 @@ static int panel_simple_probe(struct dev
306 return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
307 "failed to request GPIO\n");
309 - err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
311 - dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
315 ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
317 panel->ddc = of_find_i2c_adapter_by_node(ddc);
318 @@ -2262,6 +2243,32 @@ static const struct panel_desc friendlya
322 +static const struct drm_display_mode geekworm_mzp280_mode = {
325 + .hsync_start = 480 + 41,
326 + .hsync_end = 480 + 41 + 20,
327 + .htotal = 480 + 41 + 20 + 60,
329 + .vsync_start = 640 + 5,
330 + .vsync_end = 640 + 5 + 10,
331 + .vtotal = 640 + 5 + 10 + 10,
332 + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
335 +static const struct panel_desc geekworm_mzp280 = {
336 + .modes = &geekworm_mzp280_mode,
343 + .bus_format = MEDIA_BUS_FMT_RGB565_1X24_CPADHI,
344 + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
345 + .connector_type = DRM_MODE_CONNECTOR_DPI,
348 static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
351 @@ -2442,6 +2449,38 @@ static const struct panel_desc innolux_a
352 .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
355 +static const struct display_timing innolux_at056tn53v1_timing = {
356 + .pixelclock = { 39700000, 39700000, 39700000},
357 + .hactive = { 640, 640, 640 },
358 + .hfront_porch = { 16, 16, 16 },
359 + .hback_porch = { 134, 134, 134 },
360 + .hsync_len = { 10, 10, 10},
361 + .vactive = { 480, 480, 480 },
362 + .vfront_porch = { 32, 32, 32},
363 + .vback_porch = { 11, 11, 11 },
364 + .vsync_len = { 2, 2, 2 },
365 + .flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC,
368 +static const struct panel_desc innolux_at056tn53v1 = {
369 + .timings = &innolux_at056tn53v1_timing,
382 + .bus_format = MEDIA_BUS_FMT_BGR666_1X24_CPADHI,
383 + .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
384 + .connector_type = DRM_MODE_CONNECTOR_DPI,
387 static const struct drm_display_mode innolux_at070tn92_mode = {
390 @@ -3855,6 +3894,31 @@ static const struct panel_desc rocktech_
391 .connector_type = DRM_MODE_CONNECTOR_DPI,
394 +static const struct drm_display_mode raspberrypi_7inch_mode = {
397 + .hsync_start = 800 + 131,
398 + .hsync_end = 800 + 131 + 2,
399 + .htotal = 800 + 131 + 2 + 45,
401 + .vsync_start = 480 + 7,
402 + .vsync_end = 480 + 7 + 2,
403 + .vtotal = 480 + 7 + 2 + 22,
404 + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
407 +static const struct panel_desc raspberrypi_7inch = {
408 + .modes = &raspberrypi_7inch_mode,
415 + .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
416 + .connector_type = DRM_MODE_CONNECTOR_DSI,
419 static const struct display_timing rocktech_rk070er9427_timing = {
420 .pixelclock = { 26400000, 33300000, 46800000 },
421 .hactive = { 800, 800, 800 },
422 @@ -4799,6 +4863,9 @@ static const struct of_device_id platfor
423 .compatible = "friendlyarm,hd702e",
424 .data = &friendlyarm_hd702e,
426 + .compatible = "geekworm,mzp280",
427 + .data = &geekworm_mzp280,
429 .compatible = "giantplus,gpg482739qs5",
430 .data = &giantplus_gpg482739qs5
432 @@ -4820,6 +4887,9 @@ static const struct of_device_id platfor
433 .compatible = "innolux,at043tn24",
434 .data = &innolux_at043tn24,
436 + .compatible = "innolux,at056tn53v1",
437 + .data = &innolux_at056tn53v1,
439 .compatible = "innolux,at070tn92",
440 .data = &innolux_at070tn92,
442 @@ -4979,6 +5049,9 @@ static const struct of_device_id platfor
443 .compatible = "rocktech,rk043fn48h",
444 .data = &rocktech_rk043fn48h,
446 + .compatible = "raspberrypi,7inch-dsi",
447 + .data = &raspberrypi_7inch,
449 .compatible = "rocktech,rk070er9427",
450 .data = &rocktech_rk070er9427,
452 @@ -5335,6 +5408,9 @@ static const struct panel_desc_dsi osd10
456 +// for panels using generic panel-dsi binding
457 +static struct panel_desc_dsi panel_dsi;
459 static const struct of_device_id dsi_of_match[] = {
461 .compatible = "auo,b080uan01",
462 @@ -5358,20 +5434,137 @@ static const struct of_device_id dsi_of_
463 .compatible = "osddisplays,osd101t2045-53ts",
464 .data = &osd101t2045_53ts
466 + /* Must be the last entry */
467 + .compatible = "panel-dsi",
468 + .data = &panel_dsi,
473 MODULE_DEVICE_TABLE(of, dsi_of_match);
476 +/* Checks for DSI panel definition in device-tree, analog to panel_dpi */
477 +static int panel_dsi_dt_probe(struct device *dev,
478 + struct panel_desc_dsi *desc_dsi)
480 + struct panel_desc *desc;
481 + struct display_timing *timing;
482 + const struct device_node *np;
483 + const char *dsi_color_format;
484 + const char *dsi_mode_flags;
485 + struct property *prop;
486 + int dsi_lanes, ret;
490 + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
494 + timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL);
498 + ret = of_get_display_timing(np, "panel-timing", timing);
500 + dev_err(dev, "%pOF: no panel-timing node found for \"panel-dsi\" binding\n",
505 + desc->timings = timing;
506 + desc->num_timings = 1;
508 + of_property_read_u32(np, "width-mm", &desc->size.width);
509 + of_property_read_u32(np, "height-mm", &desc->size.height);
511 + dsi_lanes = drm_of_get_data_lanes_count_ep(np, 0, 0, 1, 4);
513 + if (dsi_lanes < 0) {
514 + dev_err(dev, "%pOF: no or too many data-lanes defined", np);
518 + desc_dsi->lanes = dsi_lanes;
520 + of_property_read_string(np, "dsi-color-format", &dsi_color_format);
521 + if (!strcmp(dsi_color_format, "RGB888")) {
522 + desc_dsi->format = MIPI_DSI_FMT_RGB888;
524 + } else if (!strcmp(dsi_color_format, "RGB565")) {
525 + desc_dsi->format = MIPI_DSI_FMT_RGB565;
527 + } else if (!strcmp(dsi_color_format, "RGB666")) {
528 + desc_dsi->format = MIPI_DSI_FMT_RGB666;
530 + } else if (!strcmp(dsi_color_format, "RGB666_PACKED")) {
531 + desc_dsi->format = MIPI_DSI_FMT_RGB666_PACKED;
534 + dev_err(dev, "%pOF: no valid dsi-color-format defined", np);
539 + of_property_for_each_string(np, "mode", prop, dsi_mode_flags) {
540 + if (!strcmp(dsi_mode_flags, "MODE_VIDEO"))
541 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO;
542 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_BURST"))
543 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_BURST;
544 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_SYNC_PULSE"))
545 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
546 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_AUTO_VERT"))
547 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_AUTO_VERT;
548 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_HSE"))
549 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_HSE;
550 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HFP"))
551 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HFP;
552 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HBP"))
553 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HBP;
554 + else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HSA"))
555 + desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HSA;
556 + else if (!strcmp(dsi_mode_flags, "MODE_VSYNC_FLUSH"))
557 + desc_dsi->flags |= MIPI_DSI_MODE_VSYNC_FLUSH;
558 + else if (!strcmp(dsi_mode_flags, "MODE_NO_EOT_PACKET"))
559 + desc_dsi->flags |= MIPI_DSI_MODE_NO_EOT_PACKET;
560 + else if (!strcmp(dsi_mode_flags, "CLOCK_NON_CONTINUOUS"))
561 + desc_dsi->flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
562 + else if (!strcmp(dsi_mode_flags, "MODE_LPM"))
563 + desc_dsi->flags |= MIPI_DSI_MODE_LPM;
564 + else if (!strcmp(dsi_mode_flags, "HS_PKT_END_ALIGNED"))
565 + desc_dsi->flags |= MIPI_DSI_HS_PKT_END_ALIGNED;
568 + desc->connector_type = DRM_MODE_CONNECTOR_DSI;
569 + desc_dsi->desc = *desc;
574 static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
576 const struct panel_desc_dsi *desc;
577 + struct panel_desc_dsi *dt_desc;
580 desc = of_device_get_match_data(&dsi->dev);
584 + if (desc == &panel_dsi) {
585 + /* Handle the generic panel-dsi binding */
586 + dt_desc = devm_kzalloc(&dsi->dev, sizeof(*dt_desc), GFP_KERNEL);
590 + err = panel_dsi_dt_probe(&dsi->dev, dt_desc);
597 err = panel_simple_probe(&dsi->dev, &desc->desc);