brcm2708: update to latest patches from RPi foundation
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.19 / 950-0710-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch
1 From d28d3bc6236baead38959d1901e439b746db921e 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 710/782] 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 | 142 ++++++++++++++-----------
12 1 file changed, 81 insertions(+), 61 deletions(-)
13
14 --- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
15 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
16 @@ -1035,6 +1035,58 @@ 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 + mode->base.type = DRM_MODE_OBJECT_MODE;
68 +
69 + return 0;
70 +}
71 +
72 static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
73 size_t len)
74 {
75 @@ -1063,30 +1115,40 @@ static int vc4_fkms_connector_get_modes(
76 to_vc4_fkms_connector(connector);
77 struct drm_encoder *encoder = fkms_connector->encoder;
78 struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
79 - int ret = 0;
80 + struct drm_display_mode fw_mode;
81 + struct drm_display_mode *mode;
82 struct edid *edid;
83 + int num_modes;
84
85 - edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
86 - fkms_connector);
87 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
88 + drm_mode_debug_printmodeline(&fw_mode);
89 + mode = drm_mode_duplicate(connector->dev,
90 + &fw_mode);
91 + drm_mode_probed_add(connector, mode);
92 + num_modes = 1; /* 1 mode */
93 + } else {
94 + edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
95 + fkms_connector);
96
97 - /* FIXME: Can we do CEC?
98 - * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
99 - * if (!edid)
100 - * return -ENODEV;
101 - */
102 -
103 - vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
104 -
105 - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
106 - vc4_encoder->rgb_range_selectable =
107 - drm_rgb_quant_range_selectable(edid);
108 + /* FIXME: Can we do CEC?
109 + * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
110 + * if (!edid)
111 + * return -ENODEV;
112 + */
113 +
114 + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
115 +
116 + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
117 + vc4_encoder->rgb_range_selectable =
118 + drm_rgb_quant_range_selectable(edid);
119 + }
120 +
121 + drm_connector_update_edid_property(connector, edid);
122 + num_modes = drm_add_edid_modes(connector, edid);
123 + kfree(edid);
124 }
125
126 - drm_connector_update_edid_property(connector, edid);
127 - ret = drm_add_edid_modes(connector, edid);
128 - kfree(edid);
129 -
130 - return ret;
131 + return num_modes;
132 }
133
134 /* This is the DSI panel resolution. Use this as a default should the firmware
135 @@ -1104,57 +1166,15 @@ static int vc4_fkms_lcd_connector_get_mo
136 {
137 struct vc4_fkms_connector *fkms_connector =
138 to_vc4_fkms_connector(connector);
139 - struct vc4_dev *vc4 = fkms_connector->vc4_dev;
140 struct drm_display_mode *mode;
141 - struct mailbox_set_mode mb = {
142 - .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
143 - sizeof(struct set_timings), 0},
144 - .timings = { .display = fkms_connector->display_number },
145 - };
146 struct drm_display_mode fw_mode;
147 - int ret = 0;
148 -
149 - ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
150 - if (!ret) {
151 - /* Equivalent to DRM_MODE macro. */
152 - memset(&fw_mode, 0, sizeof(fw_mode));
153 - strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
154 - fw_mode.status = 0;
155 - fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
156 - fw_mode.clock = mb.timings.clock;
157 - fw_mode.hdisplay = mb.timings.hdisplay;
158 - fw_mode.hsync_start = mb.timings.hsync_start;
159 - fw_mode.hsync_end = mb.timings.hsync_end;
160 - fw_mode.htotal = mb.timings.htotal;
161 - fw_mode.hskew = 0;
162 - fw_mode.vdisplay = mb.timings.vdisplay;
163 - fw_mode.vsync_start = mb.timings.vsync_start;
164 - fw_mode.vsync_end = mb.timings.vsync_end;
165 - fw_mode.vtotal = mb.timings.vtotal;
166 - fw_mode.vscan = mb.timings.vscan;
167 - if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
168 - fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
169 - else
170 - fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
171 - if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
172 - fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
173 - else
174 - fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
175 - if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
176 - fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
177 - else
178 - fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
179 - if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
180 - fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
181 -
182 - fw_mode.base.type = DRM_MODE_OBJECT_MODE;
183
184 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
185 mode = drm_mode_duplicate(connector->dev,
186 &fw_mode);
187 - } else {
188 + else
189 mode = drm_mode_duplicate(connector->dev,
190 &lcd_mode);
191 - }
192
193 if (!mode) {
194 DRM_ERROR("Failed to create a new display mode\n");