72c5c2085d0004c3f0bb7983032818d91af9b6ab
[openwrt/staging/blocktrron.git] /
1 From ae200c4c1d2d0c9f827e7f73d00f00074e3a7a04 Mon Sep 17 00:00:00 2001
2 From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
3 Date: Thu, 15 Jul 2021 01:08:08 +0200
4 Subject: [PATCH] drm/vc4: Relax VEC modeline requirements and add
5 progressive mode support
6
7 Make vc4_vec_encoder_atomic_check() accept arbitrary modelines, as long
8 as they result in somewhat sane output from the VEC. The bounds have
9 been determined empirically. Additionally, add support for the
10 progressive 262-line and 312-line modes.
11
12 Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
13 ---
14 drivers/gpu/drm/vc4/vc4_crtc.c | 1 +
15 drivers/gpu/drm/vc4/vc4_vec.c | 97 ++++++++++++++++++++++++++++------
16 2 files changed, 83 insertions(+), 15 deletions(-)
17
18 --- a/drivers/gpu/drm/vc4/vc4_crtc.c
19 +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
20 @@ -401,6 +401,7 @@ static void vc4_crtc_config_pv(struct dr
21 CRTC_WRITE(PV_V_CONTROL,
22 PV_VCONTROL_CONTINUOUS |
23 (is_dsi ? PV_VCONTROL_DSI : 0));
24 + CRTC_WRITE(PV_VSYNCD_EVEN, 0);
25 }
26
27 if (is_dsi)
28 --- a/drivers/gpu/drm/vc4/vc4_vec.c
29 +++ b/drivers/gpu/drm/vc4/vc4_vec.c
30 @@ -423,18 +423,11 @@ static int vc4_vec_connector_atomic_chec
31 struct drm_connector_state *new_state =
32 drm_atomic_get_new_connector_state(state, conn);
33
34 - const struct vc4_vec_tv_mode *vec_mode =
35 - &vc4_vec_tv_modes[new_state->tv.mode];
36 -
37 - if (new_state->crtc) {
38 + if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) {
39 struct drm_crtc_state *crtc_state =
40 drm_atomic_get_new_crtc_state(state, new_state->crtc);
41
42 - if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
43 - return -EINVAL;
44 -
45 - if (old_state->tv.mode != new_state->tv.mode)
46 - crtc_state->mode_changed = true;
47 + crtc_state->mode_changed = true;
48 }
49
50 return 0;
51 @@ -559,7 +552,10 @@ static void vc4_vec_encoder_enable(struc
52 VEC_WRITE(VEC_CLMP0_START, 0xac);
53 VEC_WRITE(VEC_CLMP0_END, 0xec);
54 VEC_WRITE(VEC_CONFIG2,
55 - VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
56 + VEC_CONFIG2_UV_DIG_DIS |
57 + VEC_CONFIG2_RGB_DIG_DIS |
58 + ((encoder->crtc->state->adjusted_mode.flags &
59 + DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
60 VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
61 VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
62
63 @@ -582,17 +578,88 @@ static void vc4_vec_encoder_enable(struc
64 }
65
66
67 -static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
68 - const struct drm_display_mode *mode,
69 - struct drm_display_mode *adjusted_mode)
70 +static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
71 + struct drm_crtc_state *crtc_state,
72 + struct drm_connector_state *conn_state)
73 {
74 - return true;
75 + const struct drm_display_mode *reference_mode =
76 + vc4_vec_tv_modes[conn_state->tv.mode].mode;
77 +
78 + if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
79 + crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
80 + crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 ||
81 + crtc_state->adjusted_mode.crtc_hsync_end -
82 + crtc_state->adjusted_mode.crtc_hsync_start < 1)
83 + return -EINVAL;
84 +
85 + switch (reference_mode->vtotal) {
86 + case 525:
87 + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
88 + crtc_state->adjusted_mode.crtc_vdisplay > 253 ||
89 + crtc_state->adjusted_mode.crtc_vsync_start -
90 + crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
91 + crtc_state->adjusted_mode.crtc_vsync_end -
92 + crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
93 + crtc_state->adjusted_mode.crtc_vtotal -
94 + crtc_state->adjusted_mode.crtc_vsync_end < 4 ||
95 + crtc_state->adjusted_mode.crtc_vtotal > 262)
96 + return -EINVAL;
97 +
98 + if ((crtc_state->adjusted_mode.flags &
99 + DRM_MODE_FLAG_INTERLACE) &&
100 + (crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
101 + crtc_state->adjusted_mode.vsync_start % 2 != 1 ||
102 + crtc_state->adjusted_mode.vsync_end % 2 != 1 ||
103 + crtc_state->adjusted_mode.vtotal % 2 != 1))
104 + return -EINVAL;
105 +
106 + /* progressive mode is hard-wired to 262 total lines */
107 + if (!(crtc_state->adjusted_mode.flags &
108 + DRM_MODE_FLAG_INTERLACE) &&
109 + crtc_state->adjusted_mode.crtc_vtotal != 262)
110 + return -EINVAL;
111 +
112 + break;
113 +
114 + case 625:
115 + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
116 + crtc_state->adjusted_mode.crtc_vdisplay > 305 ||
117 + crtc_state->adjusted_mode.crtc_vsync_start -
118 + crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
119 + crtc_state->adjusted_mode.crtc_vsync_end -
120 + crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
121 + crtc_state->adjusted_mode.crtc_vtotal -
122 + crtc_state->adjusted_mode.crtc_vsync_end < 2 ||
123 + crtc_state->adjusted_mode.crtc_vtotal > 312)
124 + return -EINVAL;
125 +
126 + if ((crtc_state->adjusted_mode.flags &
127 + DRM_MODE_FLAG_INTERLACE) &&
128 + (crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
129 + crtc_state->adjusted_mode.vsync_start % 2 != 0 ||
130 + crtc_state->adjusted_mode.vsync_end % 2 != 0 ||
131 + crtc_state->adjusted_mode.vtotal % 2 != 1))
132 + return -EINVAL;
133 +
134 + /* progressive mode is hard-wired to 312 total lines */
135 + if (!(crtc_state->adjusted_mode.flags &
136 + DRM_MODE_FLAG_INTERLACE) &&
137 + crtc_state->adjusted_mode.crtc_vtotal != 312)
138 + return -EINVAL;
139 +
140 + break;
141 +
142 + default:
143 + return -EINVAL;
144 + }
145 +
146 + return 0;
147 }
148
149 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
150 .disable = vc4_vec_encoder_disable,
151 .enable = vc4_vec_encoder_enable,
152 - .mode_fixup = vc4_vec_encoder_mode_fixup,
153 + .atomic_check = vc4_vec_encoder_atomic_check,
154 };
155
156 static const struct vc4_vec_variant bcm2835_vec_variant = {