Skip to content

Commit 20ee335

Browse files
committed
linux/lakka/rpi: patch for scaled modes
ref: raspberrypi/linux#4636
1 parent fe371a0 commit 20ee335

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
From 234cfe71ba316c9666ecd501b7df1a4b5bdb7c03 Mon Sep 17 00:00:00 2001
2+
From: Mateusz Kwiatkowski <[email protected]>
3+
Date: Mon, 11 Oct 2021 23:34:25 +0200
4+
Subject: [PATCH 1/2] drm/vc4: Add vertically scaled progressive modes for VEC
5+
6+
The Raspberry Pi firmware, when configured to output progressive
7+
composite video, scales 720x480/720x576 framebuffer into a
8+
720x240/720x288 physical video mode.
9+
10+
This commit adds support for replicating such behavior, as this provides
11+
square-ish virtual pixels, and some userland software rely on this.
12+
13+
Signed-off-by: Mateusz Kwiatkowski <[email protected]>
14+
---
15+
drivers/gpu/drm/vc4/vc4_plane.c | 40 +++++++++++++++++++++
16+
drivers/gpu/drm/vc4/vc4_vec.c | 63 ++++++++++++++++++++++++++++++---
17+
2 files changed, 98 insertions(+), 5 deletions(-)
18+
19+
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
20+
index 7947cf47b6e13..96b60fb245982 100644
21+
--- a/drivers/gpu/drm/vc4/vc4_plane.c
22+
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
23+
@@ -334,6 +334,42 @@ static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
24+
return 0;
25+
}
26+
27+
+static int vc4_plane_scaling_adj(struct drm_plane_state *pstate)
28+
+{
29+
+ struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
30+
+ struct drm_crtc_state *crtc_state;
31+
+
32+
+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
33+
+ pstate->crtc);
34+
+
35+
+ if (crtc_state->mode.hdisplay != crtc_state->adjusted_mode.hdisplay) {
36+
+ vc4_pstate->crtc_x =
37+
+ DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
38+
+ crtc_state->adjusted_mode.hdisplay,
39+
+ crtc_state->mode.hdisplay);
40+
+ vc4_pstate->crtc_w =
41+
+ DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
42+
+ crtc_state->adjusted_mode.hdisplay,
43+
+ crtc_state->mode.hdisplay);
44+
+ }
45+
+
46+
+ if (crtc_state->mode.vdisplay != crtc_state->adjusted_mode.vdisplay) {
47+
+ vc4_pstate->crtc_y =
48+
+ DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
49+
+ crtc_state->adjusted_mode.vdisplay,
50+
+ crtc_state->mode.vdisplay);
51+
+ vc4_pstate->crtc_h =
52+
+ DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
53+
+ crtc_state->adjusted_mode.vdisplay,
54+
+ crtc_state->mode.vdisplay);
55+
+ }
56+
+
57+
+ if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
58+
+ return -EINVAL;
59+
+
60+
+ return 0;
61+
+}
62+
+
63+
static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
64+
{
65+
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
66+
@@ -378,6 +414,10 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
67+
if (ret)
68+
return ret;
69+
70+
+ ret = vc4_plane_scaling_adj(state);
71+
+ if (ret)
72+
+ return ret;
73+
+
74+
vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
75+
vc4_state->crtc_w);
76+
vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
77+
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
78+
index 255e5c6c48e04..14eb28c859eb4 100644
79+
--- a/drivers/gpu/drm/vc4/vc4_vec.c
80+
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
81+
@@ -253,6 +253,7 @@ enum vc4_vec_tv_mode_id {
82+
struct vc4_vec_tv_mode {
83+
const struct drm_display_mode *interlaced_mode;
84+
const struct drm_display_mode *progressive_mode;
85+
+ const struct drm_display_mode *scaled_progressive_mode;
86+
u32 config0;
87+
u32 config1;
88+
u32 custom_freq;
89+
@@ -298,6 +299,12 @@ static const struct drm_display_mode drm_mode_240p = {
90+
240, 240 + 3, 240 + 3 + 3, 262, 0, 0)
91+
};
92+
93+
+static const struct drm_display_mode drm_mode_scaled_480p = {
94+
+ DRM_MODE("720x480 (scaled)", DRM_MODE_TYPE_DRIVER, 2 * 13500,
95+
+ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
96+
+ 2 * 240, 2 * (240 + 3), 2 * (240 + 3 + 3), 2 * 262, 0, 0)
97+
+};
98+
+
99+
static const struct drm_display_mode drm_mode_576i = {
100+
DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
101+
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
102+
@@ -311,16 +318,24 @@ static const struct drm_display_mode drm_mode_288p = {
103+
288, 288 + 2, 288 + 2 + 3, 312, 0, 0)
104+
};
105+
106+
+static const struct drm_display_mode drm_mode_scaled_576p = {
107+
+ DRM_MODE("720x576 (scaled)", DRM_MODE_TYPE_DRIVER, 2 * 13500,
108+
+ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
109+
+ 2 * 288, 2 * (288 + 2), 2 * (288 + 2 + 3), 2 * 312, 0, 0)
110+
+};
111+
+
112+
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
113+
[VC4_VEC_TV_MODE_NTSC] = {
114+
.interlaced_mode = &drm_mode_480i,
115+
.progressive_mode = &drm_mode_240p,
116+
+ .scaled_progressive_mode = &drm_mode_scaled_480p,
117+
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
118+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
119+
},
120+
[VC4_VEC_TV_MODE_NTSC_J] = {
121+
.interlaced_mode = &drm_mode_480i,
122+
.progressive_mode = &drm_mode_240p,
123+
+ .scaled_progressive_mode = &drm_mode_scaled_480p,
124+
.config0 = VEC_CONFIG0_NTSC_STD,
125+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
126+
},
127+
@@ -328,6 +343,7 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
128+
/* NTSC with PAL chroma frequency */
129+
.interlaced_mode = &drm_mode_480i,
130+
.progressive_mode = &drm_mode_240p,
131+
+ .scaled_progressive_mode = &drm_mode_scaled_480p,
132+
.config0 = VEC_CONFIG0_NTSC_STD,
133+
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
134+
.custom_freq = 0x2a098acb,
135+
@@ -335,18 +351,21 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
136+
[VC4_VEC_TV_MODE_PAL] = {
137+
.interlaced_mode = &drm_mode_576i,
138+
.progressive_mode = &drm_mode_288p,
139+
+ .scaled_progressive_mode = &drm_mode_scaled_576p,
140+
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
141+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
142+
},
143+
[VC4_VEC_TV_MODE_PAL_M] = {
144+
.interlaced_mode = &drm_mode_480i,
145+
.progressive_mode = &drm_mode_240p,
146+
+ .scaled_progressive_mode = &drm_mode_scaled_480p,
147+
.config0 = VEC_CONFIG0_PAL_M_STD,
148+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
149+
},
150+
[VC4_VEC_TV_MODE_PAL_N] = {
151+
.interlaced_mode = &drm_mode_576i,
152+
.progressive_mode = &drm_mode_288p,
153+
+ .scaled_progressive_mode = &drm_mode_scaled_576p,
154+
.config0 = VEC_CONFIG0_PAL_N_STD,
155+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
156+
},
157+
@@ -354,6 +373,7 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
158+
/* PAL-M with chroma frequency of regular PAL */
159+
.interlaced_mode = &drm_mode_480i,
160+
.progressive_mode = &drm_mode_240p,
161+
+ .scaled_progressive_mode = &drm_mode_scaled_480p,
162+
.config0 = VEC_CONFIG0_PAL_M_STD,
163+
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
164+
.custom_freq = 0x2a098acb,
165+
@@ -361,6 +381,7 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
166+
[VC4_VEC_TV_MODE_SECAM] = {
167+
.interlaced_mode = &drm_mode_576i,
168+
.progressive_mode = &drm_mode_288p,
169+
+ .scaled_progressive_mode = &drm_mode_scaled_576p,
170+
.config0 = VEC_CONFIG0_SECAM_STD,
171+
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
172+
.custom_freq = 0x29c71c72,
173+
@@ -420,7 +441,9 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector)
174+
static int vc4_vec_connector_get_modes(struct drm_connector *connector)
175+
{
176+
struct drm_connector_state *state = connector->state;
177+
- struct drm_display_mode *interlaced_mode, *progressive_mode;
178+
+ struct drm_display_mode *interlaced_mode;
179+
+ struct drm_display_mode *progressive_mode;
180+
+ struct drm_display_mode *scaled_progressive_mode;
181+
182+
interlaced_mode =
183+
drm_mode_duplicate(connector->dev,
184+
@@ -428,24 +451,33 @@ static int vc4_vec_connector_get_modes(struct drm_connector *connector)
185+
progressive_mode =
186+
drm_mode_duplicate(connector->dev,
187+
vc4_vec_tv_modes[state->tv.mode].progressive_mode);
188+
- if (!interlaced_mode || !progressive_mode) {
189+
+ scaled_progressive_mode =
190+
+ drm_mode_duplicate(connector->dev,
191+
+ vc4_vec_tv_modes[state->tv.mode].scaled_progressive_mode);
192+
+ if (!interlaced_mode || !progressive_mode || !scaled_progressive_mode) {
193+
DRM_ERROR("Failed to create a new display mode\n");
194+
drm_mode_destroy(connector->dev, interlaced_mode);
195+
drm_mode_destroy(connector->dev, progressive_mode);
196+
+ drm_mode_destroy(connector->dev, scaled_progressive_mode);
197+
return -ENOMEM;
198+
}
199+
200+
if (connector->cmdline_mode.specified &&
201+
connector->cmdline_mode.refresh_specified &&
202+
- !connector->cmdline_mode.interlace)
203+
+ !connector->cmdline_mode.interlace) {
204+
/* progressive mode set at boot, let's make it preferred */
205+
- progressive_mode->type |= DRM_MODE_TYPE_PREFERRED;
206+
- else
207+
+ if (connector->cmdline_mode.yres > 300)
208+
+ scaled_progressive_mode->type |= DRM_MODE_TYPE_PREFERRED;
209+
+ else
210+
+ progressive_mode->type |= DRM_MODE_TYPE_PREFERRED;
211+
+ } else {
212+
/* otherwise, interlaced mode is preferred */
213+
interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED;
214+
+ }
215+
216+
drm_mode_probed_add(connector, interlaced_mode);
217+
drm_mode_probed_add(connector, progressive_mode);
218+
+ drm_mode_probed_add(connector, scaled_progressive_mode);
219+
220+
return 1;
221+
}
222+
@@ -628,6 +660,27 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
223+
const struct drm_display_mode *reference_mode =
224+
vc4_vec_tv_modes[conn_state->tv.mode].interlaced_mode;
225+
226+
+ if (!(crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) &&
227+
+ crtc_state->adjusted_mode.vtotal > 312) {
228+
+ /* vertically scaled progressive mode */
229+
+ if (crtc_state->adjusted_mode.crtc_vdisplay % 2 != 0 ||
230+
+ crtc_state->adjusted_mode.crtc_vsync_start % 2 != 0 ||
231+
+ crtc_state->adjusted_mode.crtc_vsync_end % 2 != 0 ||
232+
+ crtc_state->adjusted_mode.crtc_vtotal % 2 != 0)
233+
+ return -EINVAL;
234+
+
235+
+ crtc_state->adjusted_mode.clock /= 2;
236+
+ crtc_state->adjusted_mode.crtc_clock /= 2;
237+
+ crtc_state->adjusted_mode.vdisplay /= 2;
238+
+ crtc_state->adjusted_mode.crtc_vdisplay /= 2;
239+
+ crtc_state->adjusted_mode.vsync_start /= 2;
240+
+ crtc_state->adjusted_mode.crtc_vsync_start /= 2;
241+
+ crtc_state->adjusted_mode.vsync_end /= 2;
242+
+ crtc_state->adjusted_mode.crtc_vsync_end /= 2;
243+
+ crtc_state->adjusted_mode.vtotal /= 2;
244+
+ crtc_state->adjusted_mode.crtc_vtotal /= 2;
245+
+ }
246+
+
247+
if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
248+
crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
249+
crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 ||
250+
251+
From 3c08549f11d5fb031661d8b1d1b2325ea6153656 Mon Sep 17 00:00:00 2001
252+
From: Mateusz Kwiatkowski <[email protected]>
253+
Date: Tue, 12 Oct 2021 00:30:02 +0200
254+
Subject: [PATCH 2/2] drm/vc4: Add support for horizontally caled VEC modes
255+
256+
Composite output uses non-square pixels. By allowing horizontally scaled
257+
modes, we can simulate a different pixel clock and thus make it possible
258+
to simulate square pixels at either 4:3 or 16:9 target aspect ratio.
259+
260+
Signed-off-by: Mateusz Kwiatkowski <[email protected]>
261+
---
262+
drivers/gpu/drm/vc4/vc4_vec.c | 40 ++++++++++++++++++++++++++++++-----
263+
1 file changed, 35 insertions(+), 5 deletions(-)
264+
265+
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
266+
index 14eb28c859eb4..e60a5c1e01472 100644
267+
--- a/drivers/gpu/drm/vc4/vc4_vec.c
268+
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
269+
@@ -681,13 +681,43 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
270+
crtc_state->adjusted_mode.crtc_vtotal /= 2;
271+
}
272+
273+
- if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
274+
- crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
275+
- crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 ||
276+
- crtc_state->adjusted_mode.crtc_hsync_end -
277+
- crtc_state->adjusted_mode.crtc_hsync_start < 1)
278+
+ if (crtc_state->adjusted_mode.hdisplay % 4 != 0 ||
279+
+ crtc_state->adjusted_mode.hsync_end -
280+
+ crtc_state->adjusted_mode.hsync_start < 1)
281+
return -EINVAL;
282+
283+
+ crtc_state->adjusted_mode.hdisplay =
284+
+ DIV_ROUND_CLOSEST(crtc_state->adjusted_mode.hdisplay *
285+
+ reference_mode->clock,
286+
+ crtc_state->adjusted_mode.clock);
287+
+ crtc_state->adjusted_mode.hsync_start =
288+
+ DIV_ROUND_CLOSEST(crtc_state->adjusted_mode.hsync_start *
289+
+ reference_mode->clock,
290+
+ crtc_state->adjusted_mode.clock);
291+
+ crtc_state->adjusted_mode.hsync_end =
292+
+ DIV_ROUND_CLOSEST(crtc_state->adjusted_mode.hsync_end *
293+
+ reference_mode->clock,
294+
+ crtc_state->adjusted_mode.clock);
295+
+ crtc_state->adjusted_mode.htotal =
296+
+ DIV_ROUND_CLOSEST(crtc_state->adjusted_mode.htotal *
297+
+ reference_mode->clock,
298+
+ crtc_state->adjusted_mode.clock);
299+
+ crtc_state->adjusted_mode.clock = reference_mode->clock;
300+
+
301+
+ if (crtc_state->adjusted_mode.htotal != reference_mode->htotal)
302+
+ return -EINVAL;
303+
+
304+
+ if (crtc_state->adjusted_mode.hsync_end -
305+
+ crtc_state->adjusted_mode.hsync_start < 1)
306+
+ crtc_state->adjusted_mode.hsync_end =
307+
+ crtc_state->adjusted_mode.hsync_start + 1;
308+
+
309+
+ crtc_state->adjusted_mode.crtc_clock = crtc_state->adjusted_mode.clock;
310+
+ crtc_state->adjusted_mode.crtc_hdisplay = crtc_state->adjusted_mode.hdisplay;
311+
+ crtc_state->adjusted_mode.crtc_hsync_start = crtc_state->adjusted_mode.hsync_start;
312+
+ crtc_state->adjusted_mode.crtc_hsync_end = crtc_state->adjusted_mode.hsync_end;
313+
+ crtc_state->adjusted_mode.crtc_htotal = crtc_state->adjusted_mode.htotal;
314+
+
315+
switch (reference_mode->vtotal) {
316+
case 525:
317+
if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||

0 commit comments

Comments
 (0)