kernel: bump 5.4 to 5.4.48
[oweals/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0275-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch
1 From 6402d9c21c9b144d528c3248607589db94ecbce0 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 3 Jul 2019 17:44:53 +0100
4 Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode
5
6 Allow custom HDMI modes to be specified from config.txt,
7 and these then override EDID parsing.
8
9 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
10 ---
11  drivers/gpu/drm/vc4/vc4_firmware_kms.c | 130 ++++++++++++++-----------
12  1 file changed, 75 insertions(+), 55 deletions(-)
13
14 --- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
15 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
16 @@ -1066,6 +1066,56 @@ vc4_fkms_connector_detect(struct drm_con
17         return connector_status_connected;
18  }
19  
20 +/* Queries the firmware to populate a drm_mode structure for this display */
21 +static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
22 +                               struct drm_display_mode *mode)
23 +{
24 +       struct vc4_dev *vc4 = fkms_connector->vc4_dev;
25 +       struct set_timings timings = { 0 };
26 +       int ret;
27 +
28 +       timings.display = fkms_connector->display_number;
29 +
30 +       ret = rpi_firmware_property(vc4->firmware,
31 +                                   RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
32 +                                   sizeof(timings));
33 +       if (ret || !timings.clock)
34 +               /* No mode returned - abort */
35 +               return -1;
36 +
37 +       /* Equivalent to DRM_MODE macro. */
38 +       memset(mode, 0, sizeof(*mode));
39 +       strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
40 +       mode->status = 0;
41 +       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
42 +       mode->clock = timings.clock;
43 +       mode->hdisplay = timings.hdisplay;
44 +       mode->hsync_start = timings.hsync_start;
45 +       mode->hsync_end = timings.hsync_end;
46 +       mode->htotal = timings.htotal;
47 +       mode->hskew = 0;
48 +       mode->vdisplay = timings.vdisplay;
49 +       mode->vsync_start = timings.vsync_start;
50 +       mode->vsync_end = timings.vsync_end;
51 +       mode->vtotal = timings.vtotal;
52 +       mode->vscan = timings.vscan;
53 +
54 +       if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
55 +               mode->flags |= DRM_MODE_FLAG_PHSYNC;
56 +       else
57 +               mode->flags |= DRM_MODE_FLAG_NHSYNC;
58 +
59 +       if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
60 +               mode->flags |= DRM_MODE_FLAG_PVSYNC;
61 +       else
62 +               mode->flags |= DRM_MODE_FLAG_NVSYNC;
63 +
64 +       if (timings.flags & TIMINGS_FLAGS_INTERLACE)
65 +               mode->flags |= DRM_MODE_FLAG_INTERLACE;
66 +
67 +       return 0;
68 +}
69 +
70  static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
71                                    size_t len)
72  {
73 @@ -1094,25 +1144,35 @@ static int vc4_fkms_connector_get_modes(
74                                         to_vc4_fkms_connector(connector);
75         struct drm_encoder *encoder = fkms_connector->encoder;
76         struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
77 -       int ret = 0;
78 +       struct drm_display_mode fw_mode;
79 +       struct drm_display_mode *mode;
80         struct edid *edid;
81 +       int num_modes;
82  
83 -       edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
84 -                              fkms_connector);
85 +       if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
86 +               drm_mode_debug_printmodeline(&fw_mode);
87 +               mode = drm_mode_duplicate(connector->dev,
88 +                                         &fw_mode);
89 +               drm_mode_probed_add(connector, mode);
90 +               num_modes = 1;  /* 1 mode */
91 +       } else {
92 +               edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
93 +                                      fkms_connector);
94  
95 -       /* FIXME: Can we do CEC?
96 -        * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
97 -        * if (!edid)
98 -        *      return -ENODEV;
99 -        */
100 -
101 -       vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
102 -
103 -       drm_connector_update_edid_property(connector, edid);
104 -       ret = drm_add_edid_modes(connector, edid);
105 -       kfree(edid);
106 +               /* FIXME: Can we do CEC?
107 +                * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
108 +                * if (!edid)
109 +                *      return -ENODEV;
110 +                */
111 +
112 +               vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
113 +
114 +               drm_connector_update_edid_property(connector, edid);
115 +               num_modes = drm_add_edid_modes(connector, edid);
116 +               kfree(edid);
117 +       }
118  
119 -       return ret;
120 +       return num_modes;
121  }
122  
123  /* This is the DSI panel resolution. Use this as a default should the firmware
124 @@ -1130,55 +1190,15 @@ static int vc4_fkms_lcd_connector_get_mo
125  {
126         struct vc4_fkms_connector *fkms_connector =
127                                         to_vc4_fkms_connector(connector);
128 -       struct vc4_dev *vc4 = fkms_connector->vc4_dev;
129         struct drm_display_mode *mode;
130 -       struct mailbox_set_mode mb = {
131 -               .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
132 -                         sizeof(struct set_timings), 0},
133 -               .timings = { .display = fkms_connector->display_number },
134 -       };
135         struct drm_display_mode fw_mode;
136 -       int ret = 0;
137 -
138 -       ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
139 -       if (!ret) {
140 -               /* Equivalent to DRM_MODE macro. */
141 -               memset(&fw_mode, 0, sizeof(fw_mode));
142 -               strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
143 -               fw_mode.status = 0;
144 -               fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
145 -               fw_mode.clock = mb.timings.clock;
146 -               fw_mode.hdisplay = mb.timings.hdisplay;
147 -               fw_mode.hsync_start = mb.timings.hsync_start;
148 -               fw_mode.hsync_end = mb.timings.hsync_end;
149 -               fw_mode.htotal = mb.timings.htotal;
150 -               fw_mode.hskew = 0;
151 -               fw_mode.vdisplay = mb.timings.vdisplay;
152 -               fw_mode.vsync_start = mb.timings.vsync_start;
153 -               fw_mode.vsync_end = mb.timings.vsync_end;
154 -               fw_mode.vtotal = mb.timings.vtotal;
155 -               fw_mode.vscan = mb.timings.vscan;
156 -               if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
157 -                       fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
158 -               else
159 -                       fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
160 -               if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
161 -                       fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
162 -               else
163 -                       fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
164 -               if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
165 -                       fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
166 -               else
167 -                       fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
168 -               if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
169 -                       fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
170  
171 +       if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
172                 mode = drm_mode_duplicate(connector->dev,
173                                           &fw_mode);
174 -       } else {
175 +       else
176                 mode = drm_mode_duplicate(connector->dev,
177                                           &lcd_mode);
178 -       }
179  
180         if (!mode) {
181                 DRM_ERROR("Failed to create a new display mode\n");