da25e90f12de0515166b6572ecf24fe188303f71
[openwrt/staging/linusw.git] /
1 From 4e81411f2a7fa068a49c34c87b692ba99801041b Mon Sep 17 00:00:00 2001
2 From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
3 Date: Tue, 16 Apr 2024 17:30:32 +0100
4 Subject: [PATCH 1055/1085] drm: rp1: vec: Support more video modes in the RP1
5 VEC driver
6
7 Support a wider range of pixel clock rates. The driver will round
8 pixclock up to 108MHz/n but tries to honour the desired image width
9 and position (of the centre of the display relative to HSYNC_STARTs).
10 This adds complexity but removes the need for separate 13.5MHz and
11 15.428MHz modes.
12
13 Support "fake" double-rate progressive modes (in which only every
14 2nd scanline is displayed). To work around aspect ratio issues.
15
16 Add Monochrome TV mode support. Add "vintage" modes (544x380i for
17 System A; 848x738i for System E) when configured for Monochrome.
18
19 Add a way to create a "custom" display mode from a module parameter.
20
21 Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
22 ---
23 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 236 +++++---
24 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h | 19 +-
25 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 674 ++++++++++++-----------
26 3 files changed, 544 insertions(+), 385 deletions(-)
27
28 --- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
29 +++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
30 @@ -48,6 +48,63 @@
31
32 #include "rp1_vec.h"
33
34 +/*
35 + * Linux doesn't make it easy to create custom video modes for the console
36 + * with non-CVT timings; so add a module parameter for it. The format is:
37 + * "<pclk>,<hact>,<hfp>,<hsync>,<hbp>,<vact>,<vfp>,<vsync>,<vbp>[,i]"
38 + * (where each comma may be replaced by any sequence of punctuation).
39 + * pclk should be 108000/n for 5 <= n <= 16 (twice this for "fake" modes).
40 + */
41 +
42 +static char *rp1vec_cmode_str;
43 +module_param_named(cmode, rp1vec_cmode_str, charp, 0600);
44 +MODULE_PARM_DESC(cmode, "Custom video mode:\n"
45 + "\t\t<pclk>,<hact>,<hfp>,<hsync>,<hbp>,<vact>,<vfp>,<vsync>,<vbp>[,i]\n");
46 +
47 +static struct drm_display_mode *rp1vec_parse_custom_mode(struct drm_device *dev)
48 +{
49 + char const *p = rp1vec_cmode_str;
50 + struct drm_display_mode *mode;
51 + unsigned int n, vals[9];
52 +
53 + if (!p)
54 + return NULL;
55 +
56 + for (n = 0; n < 9; n++) {
57 + unsigned int v = 0;
58 +
59 + if (!isdigit(*p))
60 + return NULL;
61 + do {
62 + v = 10u * v + (*p - '0');
63 + } while (isdigit(*++p));
64 +
65 + vals[n] = v;
66 + while (ispunct(*p))
67 + p++;
68 + }
69 +
70 + mode = drm_mode_create(dev);
71 + if (!mode)
72 + return NULL;
73 +
74 + mode->clock = vals[0];
75 + mode->hdisplay = vals[1];
76 + mode->hsync_start = mode->hdisplay + vals[2];
77 + mode->hsync_end = mode->hsync_start + vals[3];
78 + mode->htotal = mode->hsync_end + vals[4];
79 + mode->vdisplay = vals[5];
80 + mode->vsync_start = mode->vdisplay + vals[6];
81 + mode->vsync_end = mode->vsync_start + vals[7];
82 + mode->vtotal = mode->vsync_end + vals[8];
83 + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
84 + mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC;
85 + if (strchr(p, 'i'))
86 + mode->flags |= DRM_MODE_FLAG_INTERLACE;
87 +
88 + return mode;
89 +}
90 +
91 static void rp1vec_pipe_update(struct drm_simple_display_pipe *pipe,
92 struct drm_plane_state *old_state)
93 {
94 @@ -158,63 +215,143 @@ static void rp1vec_connector_destroy(str
95 drm_connector_cleanup(connector);
96 }
97
98 -static const struct drm_display_mode rp1vec_modes[4] = {
99 +/*
100 + * Check the mode roughly matches something we can generate.
101 + * The choice of hardware TV mode depends on total lines and frame rate.
102 + * Within each hardware mode, allow pixel clock, image size and offsets
103 + * to vary, up to a maximum horizontal active period and line count.
104 + * Don't check sync timings here: the HW driver will sanitize them.
105 + */
106 +
107 +static enum drm_mode_status rp1vec_mode_valid(struct drm_device *dev,
108 + const struct drm_display_mode *mode)
109 +{
110 + int prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
111 + int fake_31khz = prog && mode->vtotal >= 500;
112 + int vtotal_2fld = mode->vtotal << (prog && !fake_31khz);
113 + int vdisplay_2fld = mode->vdisplay << (prog && !fake_31khz);
114 + int real_clock = mode->clock >> fake_31khz;
115 +
116 + /* Check pixel clock is in the permitted range */
117 + if (real_clock < 6750)
118 + return MODE_CLOCK_LOW;
119 + else if (real_clock > 21600)
120 + return MODE_CLOCK_HIGH;
121 +
122 + /* Try to match against the 525-line 60Hz mode (System M) */
123 + if (vtotal_2fld >= 524 && vtotal_2fld <= 526 && vdisplay_2fld <= 486 &&
124 + mode->htotal * vtotal_2fld > 32 * real_clock &&
125 + mode->htotal * vtotal_2fld < 34 * real_clock &&
126 + 37 * mode->hdisplay <= 2 * real_clock) /* 54us */
127 + return MODE_OK;
128 +
129 + /* All other supported TV Systems (625-, 405-, 819-line) are 50Hz */
130 + if (mode->htotal * vtotal_2fld > 39 * real_clock &&
131 + mode->htotal * vtotal_2fld < 41 * real_clock) {
132 + if (vtotal_2fld >= 624 && vtotal_2fld <= 626 && vdisplay_2fld <= 576 &&
133 + 37 * mode->hdisplay <= 2 * real_clock) /* 54us */
134 + return MODE_OK;
135 +
136 + if (vtotal_2fld == 405 && vdisplay_2fld <= 380 &&
137 + 49 * mode->hdisplay <= 4 * real_clock) /* 81.6us */
138 + return MODE_OK;
139 +
140 + if (vtotal_2fld == 819 && vdisplay_2fld <= 738 &&
141 + 25 * mode->hdisplay <= real_clock) /* 40us */
142 + return MODE_OK;
143 + }
144 +
145 + return MODE_BAD;
146 +}
147 +
148 +static const struct drm_display_mode rp1vec_modes[6] = {
149 { /* Full size 525/60i with Rec.601 pixel rate */
150 DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
151 720, 720 + 16, 720 + 16 + 64, 858, 0,
152 480, 480 + 6, 480 + 6 + 6, 525, 0,
153 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
154 DRM_MODE_FLAG_INTERLACE)
155 },
156 { /* Cropped and horizontally squashed to be TV-safe */
157 DRM_MODE("704x432i", DRM_MODE_TYPE_DRIVER, 15429,
158 704, 704 + 76, 704 + 76 + 72, 980, 0,
159 432, 432 + 30, 432 + 30 + 6, 525, 0,
160 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
161 DRM_MODE_FLAG_INTERLACE)
162 },
163 { /* Full size 625/50i with Rec.601 pixel rate */
164 DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
165 720, 720 + 12, 720 + 12 + 64, 864, 0,
166 576, 576 + 5, 576 + 5 + 5, 625, 0,
167 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
168 DRM_MODE_FLAG_INTERLACE)
169 },
170 { /* Cropped and squashed, for square(ish) pixels */
171 DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429,
172 704, 704 + 72, 704 + 72 + 72, 987, 0,
173 512, 512 + 37, 512 + 37 + 5, 625, 0,
174 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
175 + DRM_MODE_FLAG_INTERLACE)
176 + },
177 + { /* System A (405 lines) */
178 + DRM_MODE("544x380i", DRM_MODE_TYPE_DRIVER, 6750,
179 + 544, 544 + 12, 544 + 12 + 60, 667, 0,
180 + 380, 380 + 0, 380 + 0 + 8, 405, 0,
181 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
182 + DRM_MODE_FLAG_INTERLACE)
183 + },
184 + { /* System E (819 lines) */
185 + DRM_MODE("848x738i", DRM_MODE_TYPE_DRIVER, 21600,
186 + 848, 848 + 12, 848 + 12 + 54, 1055, 0,
187 + 738, 738 + 6, 738 + 6 + 1, 819, 0,
188 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
189 DRM_MODE_FLAG_INTERLACE)
190 }
191 };
192
193 /*
194 - * Advertise standard and preferred video modes.
195 + * Advertise a custom mode, if specified; then those from the table above.
196 + * From each interlaced mode above, derive a half-height progressive one.
197 *
198 - * From each interlaced mode in the table above, derive a progressive one.
199 + * This driver always supports all 525-line and 625-line standard modes
200 + * regardless of connector's tv_mode; non-standard combinations generally
201 + * default to PAL[-BDGHIK] or NTSC[-M] (with a special case for "PAL60").
202 *
203 - * This driver always supports all 50Hz and 60Hz video modes, regardless
204 - * of connector's tv_mode; nonstandard combinations generally default
205 - * to PAL[-BDGHIKL] or NTSC[-M] depending on resolution and field-rate
206 - * (except that "PAL" with 525/60 will be implemented as "PAL60").
207 - * However, the preferred mode will depend on the default TV mode.
208 + * The "vintage" standards (System A, System E) are advertised only when
209 + * the default tv_mode was DRM_MODE_TV_MODE_MONOCHROME, and only interlaced.
210 */
211
212 static int rp1vec_connector_get_modes(struct drm_connector *connector)
213 {
214 - u64 val;
215 - int i, prog, n = 0;
216 - bool prefer625 = false;
217 + u64 tvstd;
218 + int i, prog, limit, n = 0, preferred_lines = 525;
219 + struct drm_display_mode *mode;
220
221 if (!drm_object_property_get_default_value(&connector->base,
222 connector->dev->mode_config.tv_mode_property,
223 - &val))
224 - prefer625 = (val == DRM_MODE_TV_MODE_PAL ||
225 - val == DRM_MODE_TV_MODE_PAL_N ||
226 - val == DRM_MODE_TV_MODE_SECAM);
227 + &tvstd))
228 + preferred_lines = (tvstd == DRM_MODE_TV_MODE_PAL ||
229 + tvstd == DRM_MODE_TV_MODE_PAL_N ||
230 + tvstd >= DRM_MODE_TV_MODE_SECAM) ? 625 : 525;
231 +
232 + mode = rp1vec_parse_custom_mode(connector->dev);
233 + if (mode) {
234 + if (rp1vec_mode_valid(connector->dev, mode) == 0) {
235 + drm_mode_set_name(mode);
236 + drm_mode_probed_add(connector, mode);
237 + n++;
238 + preferred_lines = 0;
239 + } else {
240 + drm_mode_destroy(connector->dev, mode);
241 + }
242 + }
243
244 - for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) {
245 + limit = (tvstd < DRM_MODE_TV_MODE_MONOCHROME) ? 4 : ARRAY_SIZE(rp1vec_modes);
246 + for (i = 0; i < limit; i++) {
247 for (prog = 0; prog < 2; prog++) {
248 - struct drm_display_mode *mode =
249 - drm_mode_duplicate(connector->dev,
250 - &rp1vec_modes[i]);
251 + mode = drm_mode_duplicate(connector->dev, &rp1vec_modes[i]);
252 + if (!mode)
253 + return n;
254
255 if (prog) {
256 mode->flags &= ~DRM_MODE_FLAG_INTERLACE;
257 @@ -222,15 +359,15 @@ static int rp1vec_connector_get_modes(st
258 mode->vsync_start >>= 1;
259 mode->vsync_end >>= 1;
260 mode->vtotal >>= 1;
261 - }
262 -
263 - if (mode->hdisplay == 704 &&
264 - mode->vtotal == (prefer625 ? 625 : 525))
265 + } else if (mode->hdisplay == 704 && mode->vtotal == preferred_lines) {
266 mode->type |= DRM_MODE_TYPE_PREFERRED;
267 -
268 + }
269 drm_mode_set_name(mode);
270 drm_mode_probed_add(connector, mode);
271 n++;
272 +
273 + if (mode->vtotal == 405 || mode->vtotal == 819)
274 + break; /* Don't offer progressive for Systems A, E */
275 }
276 }
277
278 @@ -260,49 +397,6 @@ static int rp1vec_connector_atomic_check
279 return 0;
280 }
281
282 -static enum drm_mode_status rp1vec_mode_valid(struct drm_device *dev,
283 - const struct drm_display_mode *mode)
284 -{
285 - /*
286 - * Check the mode roughly matches something we can generate.
287 - * The hardware driver is very prescriptive about pixel clocks,
288 - * line and frame durations, but we'll tolerate rounding errors.
289 - * Within each hardware mode, allow image size and position to vary
290 - * (to fine-tune overscan correction or emulate retro devices).
291 - * Don't check sync timings here: the HW driver will sanitize them.
292 - */
293 -
294 - int prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
295 - int vtotal_full = mode->vtotal << prog;
296 - int vdisplay_full = mode->vdisplay << prog;
297 -
298 - /* Reject very small frames */
299 - if (vtotal_full < 256 || mode->hdisplay < 256)
300 - return MODE_BAD;
301 -
302 - /* Check lines, frame period (ms) and vertical size limit */
303 - if (vtotal_full >= 524 && vtotal_full <= 526 &&
304 - mode->htotal * vtotal_full > 33 * mode->clock &&
305 - mode->htotal * vtotal_full < 34 * mode->clock &&
306 - vdisplay_full <= 480)
307 - goto vgood;
308 - if (vtotal_full >= 624 && vtotal_full <= 626 &&
309 - mode->htotal * vtotal_full > 39 * mode->clock &&
310 - mode->htotal * vtotal_full < 41 * mode->clock &&
311 - vdisplay_full <= 576)
312 - goto vgood;
313 - return MODE_BAD;
314 -
315 -vgood:
316 - /* Check pixel rate (kHz) and horizontal size limit */
317 - if (mode->clock == 13500 && mode->hdisplay <= 720)
318 - return MODE_OK;
319 - if (mode->clock >= 15428 && mode->clock <= 15429 &&
320 - mode->hdisplay <= 800)
321 - return MODE_OK;
322 - return MODE_BAD;
323 -}
324 -
325 static const struct drm_connector_helper_funcs rp1vec_connector_helper_funcs = {
326 .get_modes = rp1vec_connector_get_modes,
327 .atomic_check = rp1vec_connector_atomic_check,
328 @@ -410,10 +504,12 @@ static int rp1vec_platform_probe(struct
329 vec->drm.dev_private = vec;
330 platform_set_drvdata(pdev, &vec->drm);
331
332 - vec->drm.mode_config.max_width = 800;
333 - vec->drm.mode_config.max_height = 576;
334 + vec->drm.mode_config.min_width = 256;
335 + vec->drm.mode_config.min_height = 128;
336 + vec->drm.mode_config.max_width = 848; /* for System E */
337 + vec->drm.mode_config.max_height = 738; /* for System E */
338 vec->drm.mode_config.preferred_depth = 32;
339 - vec->drm.mode_config.prefer_shadow = 0;
340 + vec->drm.mode_config.prefer_shadow = 0;
341 vec->drm.mode_config.quirk_addfb_prefer_host_byte_order = true;
342 vec->drm.mode_config.funcs = &rp1vec_mode_funcs;
343 drm_vblank_init(&vec->drm, 1);
344 --- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h
345 +++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h
346 @@ -21,12 +21,15 @@
347 #define RP1VEC_NUM_HW_BLOCKS 2
348
349 #define RP1VEC_SUPPORTED_TV_MODES \
350 - (BIT(DRM_MODE_TV_MODE_NTSC) | \
351 + (BIT(DRM_MODE_TV_MODE_NTSC) | \
352 BIT(DRM_MODE_TV_MODE_NTSC_443) | \
353 - BIT(DRM_MODE_TV_MODE_NTSC_J) | \
354 - BIT(DRM_MODE_TV_MODE_PAL) | \
355 - BIT(DRM_MODE_TV_MODE_PAL_M) | \
356 - BIT(DRM_MODE_TV_MODE_PAL_N))
357 + BIT(DRM_MODE_TV_MODE_NTSC_J) | \
358 + BIT(DRM_MODE_TV_MODE_PAL) | \
359 + BIT(DRM_MODE_TV_MODE_PAL_M) | \
360 + BIT(DRM_MODE_TV_MODE_PAL_N) | \
361 + BIT(DRM_MODE_TV_MODE_MONOCHROME))
362 +
363 +#define RP1VEC_VDAC_KHZ 108000
364
365 /* ---------------------------------------------------------------------- */
366
367 @@ -45,7 +48,7 @@ struct rp1_vec {
368 /* Block (VCC, CFG) base addresses, and current state */
369 void __iomem *hw_base[RP1VEC_NUM_HW_BLOCKS];
370 u32 cur_fmt;
371 - bool vec_running, pipe_enabled;
372 + bool fake_31khz, vec_running, pipe_enabled;
373 struct completion finished;
374 };
375
376 @@ -54,8 +57,8 @@ struct rp1_vec {
377
378 void rp1vec_hw_setup(struct rp1_vec *vec,
379 u32 in_format,
380 - struct drm_display_mode const *mode,
381 - int tvstd);
382 + struct drm_display_mode const *mode,
383 + int tvstd);
384 void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stride);
385 void rp1vec_hw_stop(struct rp1_vec *vec);
386 int rp1vec_hw_busy(struct rp1_vec *vec);
387 --- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
388 +++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
389 @@ -18,11 +18,18 @@
390 #include "rp1_vec.h"
391 #include "vec_regs.h"
392
393 -#define BITS(field, val) (((val) << (field ## _LSB)) & (field ## _BITS))
394 -
395 +#define BITS(field, val) (((val) << (field ## _LSB)) & (field ## _BITS))
396 #define VEC_WRITE(reg, val) writel((val), vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET))
397 #define VEC_READ(reg) readl(vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET))
398
399 +static void rp1vec_write_regs(struct rp1_vec *vec, u32 offset, u32 const *vals, u32 num)
400 +{
401 + while (num--) {
402 + writel(*vals++, vec->hw_base[RP1VEC_HW_BLOCK_VEC] + offset);
403 + offset += 4;
404 + }
405 +}
406 +
407 int rp1vec_hw_busy(struct rp1_vec *vec)
408 {
409 /* Read the undocumented "pline_busy" flag */
410 @@ -46,32 +53,32 @@ static const struct rp1vec_ipixfmt my_fo
411 {
412 .format = DRM_FORMAT_XRGB8888,
413 .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc),
414 - .shift = SHIFT_RGB(23, 15, 7),
415 - .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3),
416 + .shift = SHIFT_RGB(23, 15, 7),
417 + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3),
418 },
419 {
420 .format = DRM_FORMAT_XBGR8888,
421 .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc),
422 - .shift = SHIFT_RGB(7, 15, 23),
423 - .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3),
424 + .shift = SHIFT_RGB(7, 15, 23),
425 + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3),
426 },
427 {
428 .format = DRM_FORMAT_RGB888,
429 .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc),
430 - .shift = SHIFT_RGB(23, 15, 7),
431 - .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2),
432 + .shift = SHIFT_RGB(23, 15, 7),
433 + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2),
434 },
435 {
436 .format = DRM_FORMAT_BGR888,
437 .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc),
438 - .shift = SHIFT_RGB(7, 15, 23),
439 - .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2),
440 + .shift = SHIFT_RGB(7, 15, 23),
441 + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2),
442 },
443 {
444 .format = DRM_FORMAT_RGB565,
445 .mask = MASK_RGB(0x3e0, 0x3f0, 0x3e0),
446 - .shift = SHIFT_RGB(15, 10, 4),
447 - .rgbsz = BITS(VEC_RGBSZ_SCALE_R, 5) |
448 + .shift = SHIFT_RGB(15, 10, 4),
449 + .rgbsz = BITS(VEC_RGBSZ_SCALE_R, 5) |
450 BITS(VEC_RGBSZ_SCALE_G, 6) |
451 BITS(VEC_RGBSZ_SCALE_B, 5) |
452 BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 1),
453 @@ -79,301 +86,338 @@ static const struct rp1vec_ipixfmt my_fo
454 };
455
456 /*
457 - * Hardware mode descriptions (@ 108 MHz clock rate).
458 - * These rely largely on "canned" register settings.
459 + * Hardware mode descriptions (@ 108 MHz VDAC clock)
460 + * See "vec_regs.h" for further descriptions of these registers and fields.
461 + * Driver should adjust some values for other TV standards and for pixel rate,
462 + * and must ensure that ((de_end - de_bgn) % rate) == 0.
463 */
464
465 struct rp1vec_hwmode {
466 - u16 total_cols; /* max active columns incl. padding and windowing */
467 - u16 rows_per_field; /* active lines per field (including partial ones) */
468 - u16 ref_hfp; /* nominal (hsync_start - hdisplay) when max width */
469 - u16 ref_vfp; /* nominal (vsync_start - vdisplay) when max height */
470 - bool interlaced; /* set for interlaced */
471 - bool first_field_odd; /* set for interlaced and 30fps */
472 - u32 yuv_scaling; /* three 10-bit fields {Y, U, V} in 2.8 format */
473 - u32 back_end_regs[28]; /* All registers 0x80 .. 0xEC */
474 + u16 max_rows_per_field; /* active lines per field (including partial ones) */
475 + u16 ref_vfp; /* nominal (vsync_start - vdisplay) when max height */
476 + bool interlaced; /* set for interlaced */
477 + bool first_field_odd; /* depends confusingly on line numbering convention */
478 + s16 scale_v; /* V scale in 2.8 format (for power-of-2 CIC rates) */
479 + s16 scale_u; /* U scale in 2.8 format (for power-of-2 CIC rates) */
480 + u16 scale_y; /* Y scale in 2.8 format (for power-of-2 CIC rates) */
481 + u16 de_end; /* end of horizontal Data Active period at 108MHz */
482 + u16 de_bgn; /* start of horizontal Data Active period */
483 + u16 half_lines_per_field; /* number of half lines per field */
484 + s16 pedestal; /* pedestal (1024 = 100IRE) including FIR overshoot */
485 + u16 scale_luma; /* back end luma scaling in 1.15 format wrt DAC FSD */
486 + u16 scale_sync; /* back end sync scaling / blanking level as above */
487 + u32 scale_burst_chroma; /* back end { burst, chroma } scaling */
488 + u32 misc; /* Contents of the "EC" register except rate,shift */
489 + u64 nco_freq; /* colour carrier frequency * (2**64) / 108MHz */
490 + u32 timing_regs[14]; /* other back end registers 0x84 .. 0xB8 */
491 };
492
493 -/* { NTSC, PAL, PAL-M } x { progressive, interlaced } x { 13.5 MHz, 15.428571 MHz } */
494 -static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
495 +/* { NTSC, PAL, PAL-M } x { progressive, interlaced } */
496 +static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
497 {
498 /* NTSC */
499 {
500 - {
501 - .total_cols = 724,
502 - .rows_per_field = 240,
503 - .ref_hfp = 12,
504 - .ref_vfp = 2,
505 - .interlaced = false,
506 - .first_field_odd = false,
507 - .yuv_scaling = 0x1071d0cf,
508 - .back_end_regs = {
509 - 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c,
510 - 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011,
511 - 0x000a0106, 0x00000000, 0x00000000, 0x00000000,
512 - 0x00000000, 0x00170106, 0x00000000, 0x004c020e,
513 - 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561,
514 - 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000,
515 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ec,
516 - },
517 - }, {
518 - .total_cols = 815,
519 - .rows_per_field = 240,
520 - .ref_hfp = 16,
521 - .ref_vfp = 2,
522 - .interlaced = false,
523 - .first_field_odd = false,
524 - .yuv_scaling = 0x1c131962,
525 - .back_end_regs = {
526 - 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c,
527 - 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011,
528 - 0x000a0106, 0x00000000, 0x00000000, 0x00000000,
529 - 0x00000000, 0x00170106, 0x00000000, 0x004c020e,
530 - 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561,
531 - 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000,
532 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ac,
533 - },
534 + .max_rows_per_field = 240,
535 + .ref_vfp = 2,
536 + .interlaced = false,
537 + .first_field_odd = false,
538 + .scale_v = 0x0cf,
539 + .scale_u = 0x074,
540 + .scale_y = 0x107,
541 + .de_end = 0x1a4f,
542 + .de_bgn = 0x038f,
543 + .half_lines_per_field = 524, /* also works with 526/2 lines */
544 + .pedestal = 0x04c,
545 + .scale_luma = 0x8c9a,
546 + .scale_sync = 0x3851,
547 + .scale_burst_chroma = 0x11195561,
548 + .misc = 0x00090c00, /* 5-tap FIR, SEQ_EN, 4 fld sync */
549 + .nco_freq = 0x087c1f07c1f07c1f,
550 + .timing_regs = {
551 + 0x03e10cc6, 0x0d6801fb, 0x023d034c, 0x00f80b6d,
552 + 0x00000005, 0x0006000b, 0x000c0011, 0x000a0106,
553 + 0x00000000, 0x00000000, 0x00000000, 0x00000000,
554 + 0x00170106, 0x00000000
555 },
556 }, {
557 - {
558 - .total_cols = 724,
559 - .rows_per_field = 243,
560 - .ref_hfp = 12,
561 - .ref_vfp = 3,
562 - .interlaced = true,
563 - .first_field_odd = true,
564 - .yuv_scaling = 0x1071d0cf,
565 - .back_end_regs = {
566 - 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c,
567 - 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011,
568 - 0x000a0107, 0x0111020d, 0x00000000, 0x00000000,
569 - 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d,
570 - 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561,
571 - 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000,
572 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dee,
573 - },
574 - }, {
575 - .total_cols = 815,
576 - .rows_per_field = 243,
577 - .ref_hfp = 16,
578 - .ref_vfp = 3,
579 - .interlaced = true,
580 - .first_field_odd = true,
581 - .yuv_scaling = 0x1c131962,
582 - .back_end_regs = {
583 - 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c,
584 - 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011,
585 - 0x000a0107, 0x0111020d, 0x00000000, 0x00000000,
586 - 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d,
587 - 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561,
588 - 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000,
589 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dae,
590 - },
591 + .max_rows_per_field = 243,
592 + .ref_vfp = 3,
593 + .interlaced = true,
594 + .first_field_odd = true,
595 + .scale_v = 0x0cf,
596 + .scale_u = 0x074,
597 + .scale_y = 0x107,
598 + .de_end = 0x1a4f,
599 + .de_bgn = 0x038f,
600 + .half_lines_per_field = 525,
601 + .pedestal = 0x04c,
602 + .scale_luma = 0x8c9a,
603 + .scale_sync = 0x3851,
604 + .scale_burst_chroma = 0x11195561,
605 + .misc = 0x00094c02, /* 5-tap FIR, SEQ_EN, 2 flds, 4 fld sync, ilace */
606 + .nco_freq = 0x087c1f07c1f07c1f,
607 + .timing_regs = {
608 + 0x03e10cc6, 0x0d6801fb, 0x023d034c, 0x00f80b6d,
609 + 0x00000005, 0x0006000b, 0x000c0011, 0x000a0107,
610 + 0x0111020d, 0x00000000, 0x00000000, 0x011c020d,
611 + 0x00150106, 0x0107011b,
612 },
613 },
614 }, {
615 /* PAL */
616 {
617 - {
618 - .total_cols = 724,
619 - .rows_per_field = 288,
620 - .ref_hfp = 16,
621 - .ref_vfp = 2,
622 - .interlaced = false,
623 - .first_field_odd = false,
624 - .yuv_scaling = 0x11c1f8e0,
625 - .back_end_regs = {
626 - 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f,
627 - 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009,
628 - 0x00070135, 0x00000000, 0x00000000, 0x00000000,
629 - 0x00000000, 0x00170136, 0x00000000, 0x000a0270,
630 - 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5,
631 - 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000,
632 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed,
633 - },
634 - }, {
635 - .total_cols = 804,
636 - .rows_per_field = 288,
637 - .ref_hfp = 24,
638 - .ref_vfp = 2,
639 - .interlaced = false,
640 - .first_field_odd = false,
641 - .yuv_scaling = 0x1e635d7f,
642 - .back_end_regs = {
643 - 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f,
644 - 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009,
645 - 0x00070135, 0x00000000, 0x00000000, 0x00000000,
646 - 0x00000000, 0x00170136, 0x00000000, 0x000a0270,
647 - 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5,
648 - 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000,
649 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad,
650 - },
651 + .max_rows_per_field = 288,
652 + .ref_vfp = 2,
653 + .interlaced = false,
654 + .first_field_odd = false,
655 + .scale_v = 0x0e0,
656 + .scale_u = 0x07e,
657 + .scale_y = 0x11c,
658 + .de_end = 0x1ab6,
659 + .de_bgn = 0x03f6,
660 + .half_lines_per_field = 624,
661 + .pedestal = 0x00a, /* nonzero for max FIR overshoot after CIC */
662 + .scale_luma = 0x89d8,
663 + .scale_sync = 0x3c00,
664 + .scale_burst_chroma = 0x0caf53b5,
665 + .misc = 0x00091c01, /* 5-tap FIR, SEQ_EN, 8 fld sync, PAL */
666 + .nco_freq = 0x0a8262b2cc48c1d1,
667 + .timing_regs = {
668 + 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84,
669 + 0x026c0270, 0x00000004, 0x00050009, 0x00070135,
670 + 0x00000000, 0x00000000, 0x00000000, 0x00000000,
671 + 0x00170136, 0x00000000,
672 },
673 }, {
674 - {
675 - .total_cols = 724,
676 - .rows_per_field = 288,
677 - .ref_hfp = 16,
678 - .ref_vfp = 5,
679 - .interlaced = true,
680 - .first_field_odd = false,
681 - .yuv_scaling = 0x11c1f8e0,
682 - .back_end_regs = {
683 - 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f,
684 - 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009,
685 - 0x00070135, 0x013f026d, 0x00060136, 0x0140026e,
686 - 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271,
687 - 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5,
688 - 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000,
689 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef,
690 - },
691 - }, {
692 - .total_cols = 804,
693 - .rows_per_field = 288,
694 - .ref_hfp = 24,
695 - .ref_vfp = 5,
696 - .interlaced = true,
697 - .first_field_odd = false,
698 - .yuv_scaling = 0x1e635d7f,
699 - .back_end_regs = {
700 - 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f,
701 - 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009,
702 - 0x00070135, 0x013f026d, 0x00060136, 0x0140026e,
703 - 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271,
704 - 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5,
705 - 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000,
706 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf,
707 - },
708 + .max_rows_per_field = 288,
709 + .ref_vfp = 5,
710 + .interlaced = true,
711 + .first_field_odd = false,
712 + .scale_v = 0x0e0,
713 + .scale_u = 0x07e,
714 + .scale_y = 0x11c,
715 + .de_end = 0x1ab6,
716 + .de_bgn = 0x03f6,
717 + .half_lines_per_field = 625,
718 + .pedestal = 0x00a,
719 + .scale_luma = 0x89d8,
720 + .scale_sync = 0x3c00,
721 + .scale_burst_chroma = 0x0caf53b5,
722 + .misc = 0x0009dc03, /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace, PAL */
723 + .nco_freq = 0x0a8262b2cc48c1d1,
724 + .timing_regs = {
725 + 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84,
726 + 0x026c0270, 0x00000004, 0x00050009, 0x00070135,
727 + 0x013f026d, 0x00060136, 0x0140026e, 0x0150026e,
728 + 0x00180136, 0x026f0017,
729 },
730 },
731 }, {
732 /* PAL-M */
733 {
734 - {
735 - .total_cols = 724,
736 - .rows_per_field = 240,
737 - .ref_hfp = 12,
738 - .ref_vfp = 2,
739 - .interlaced = false,
740 - .first_field_odd = false,
741 - .yuv_scaling = 0x11c1f8e0,
742 - .back_end_regs = {
743 - 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c,
744 - 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011,
745 - 0x000a0106, 0x00000000, 0x00000000, 0x00000000,
746 - 0x00000000, 0x00170106, 0x00000000, 0x000a020c,
747 - 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5,
748 - 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000,
749 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed,
750 - },
751 - }, {
752 - .total_cols = 815,
753 - .rows_per_field = 240,
754 - .ref_hfp = 16,
755 - .ref_vfp = 2,
756 - .interlaced = false,
757 - .first_field_odd = false,
758 - .yuv_scaling = 0x1e635d7f,
759 - .back_end_regs = {
760 - 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c,
761 - 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011,
762 - 0x000a0106, 0x00000000, 0x00000000, 0x00000000,
763 - 0x00000000, 0x00170106, 0x00000000, 0x000a020c,
764 - 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5,
765 - 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000,
766 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad,
767 - },
768 + .max_rows_per_field = 240,
769 + .ref_vfp = 2,
770 + .interlaced = false,
771 + .first_field_odd = false,
772 + .scale_v = 0x0e0,
773 + .scale_u = 0x07e,
774 + .scale_y = 0x11c,
775 + .de_end = 0x1a4f,
776 + .de_bgn = 0x038f,
777 + .half_lines_per_field = 524,
778 + .pedestal = 0x00a,
779 + .scale_luma = 0x89d8,
780 + .scale_sync = 0x3851,
781 + .scale_burst_chroma = 0x0d5c53b5,
782 + .misc = 0x00091c01, /* 5-tap FIR, SEQ_EN, 8 fld sync PAL */
783 + .nco_freq = 0x0879bbf8d6d33ea8,
784 + .timing_regs = {
785 + 0x03e10cc6, 0x0d6801fb, 0x023c034c, 0x00f80b6e,
786 + 0x00000005, 0x0006000b, 0x000c0011, 0x000a0106,
787 + 0x00000000, 0x00000000, 0x00000000, 0x00000000,
788 + 0x00170106, 0x00000000,
789 },
790 }, {
791 - {
792 - .total_cols = 724,
793 - .rows_per_field = 243,
794 - .ref_hfp = 12,
795 - .ref_vfp = 3,
796 - .interlaced = true,
797 - .first_field_odd = true,
798 - .yuv_scaling = 0x11c1f8e0,
799 - .back_end_regs = {
800 - 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c,
801 - 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b,
802 - 0x00090103, 0x010f0209, 0x00080102, 0x010e020a,
803 - 0x0119020a, 0x00120103, 0x01040118, 0x000a020d,
804 - 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5,
805 - 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000,
806 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef,
807 - },
808 - }, {
809 - .total_cols = 815,
810 - .rows_per_field = 243,
811 - .ref_hfp = 16,
812 - .ref_vfp = 3,
813 - .interlaced = true,
814 - .first_field_odd = true,
815 - .yuv_scaling = 0x1e635d7f,
816 - .back_end_regs = {
817 - 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c,
818 - 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b,
819 - 0x00090103, 0x010f0209, 0x00080102, 0x010e020a,
820 - 0x0119020a, 0x00120103, 0x01040118, 0x000a020d,
821 - 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5,
822 - 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000,
823 - 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf,
824 - },
825 + .max_rows_per_field = 243,
826 + .ref_vfp = 3,
827 + .interlaced = true,
828 + .first_field_odd = true,
829 + .scale_v = 0x0e0,
830 + .scale_u = 0x07e,
831 + .scale_y = 0x11c,
832 + .de_end = 0x1a4f,
833 + .de_bgn = 0x038f,
834 + .half_lines_per_field = 525,
835 + .pedestal = 0x00a,
836 + .scale_luma = 0x89d8,
837 + .scale_sync = 0x3851,
838 + .scale_burst_chroma = 0x0d5c53b5,
839 + .misc = 0x0009dc03, /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace, PAL */
840 + .nco_freq = 0x0879bbf8d6d33ea8,
841 + .timing_regs = {
842 + 0x03e10cc6, 0x0d6801fb, 0x023c034c, 0x00f80b6e,
843 + 0x00140019, 0x00000005, 0x0006000b, 0x00090103,
844 + 0x010f0209, 0x00080102, 0x010e020a, 0x0119020a,
845 + 0x00120103, 0x01040118,
846 },
847 },
848 },
849 };
850
851 +/* System A, System E */
852 +static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
853 + {
854 + .max_rows_per_field = 190,
855 + .ref_vfp = 0,
856 + .interlaced = true,
857 + .first_field_odd = true,
858 + .scale_v = 0,
859 + .scale_u = 0,
860 + .scale_y = 0x11c,
861 + .de_end = 0x2920,
862 + .de_bgn = 0x06a0,
863 + .half_lines_per_field = 405,
864 + .pedestal = 0x00a,
865 + .scale_luma = 0x89d8,
866 + .scale_sync = 0x3c00,
867 + .scale_burst_chroma = 0,
868 + .misc = 0x00084002, /* 5-tap FIR, 2 fields, interlace */
869 + .nco_freq = 0,
870 + .timing_regs = {
871 + 0x06f01430, 0x14d503cc, 0x00000000, 0x000010de,
872 + 0x00000000, 0x00000007, 0x00000000, 0x00000000,
873 + 0x00000000, 0x00000000, 0x00000000, 0x00d90195,
874 + 0x000e00ca, 0x00cb00d8,
875 + },
876 + }, {
877 + .max_rows_per_field = 369,
878 + .ref_vfp = 6,
879 + .interlaced = true,
880 + .first_field_odd = true,
881 + .scale_v = 0,
882 + .scale_u = 0,
883 + .scale_y = 0x11c,
884 + .de_end = 0x145f,
885 + .de_bgn = 0x03a7,
886 + .half_lines_per_field = 819,
887 + .pedestal = 0x0010,
888 + .scale_luma = 0x89d8,
889 + .scale_sync = 0x3b13,
890 + .scale_burst_chroma = 0,
891 + .misc = 0x00084002, /* 5-tap FIR, 2 fields, interlace */
892 + .nco_freq = 0,
893 + .timing_regs = {
894 + 0x03c10a08, 0x0a4d0114, 0x00000000, 0x000008a6,
895 + 0x00000000, 0x00000000, 0x00000000, 0x00000000,
896 + 0x00000000, 0x00000000, 0x00000000, 0x01c10330,
897 + 0x00270196, 0x019701c0,
898 + },
899 + },
900 +};
901 +
902 +static const u32 rp1vec_fir_regs[4] = {
903 + 0x00000000, 0x0be20200, 0x20f0f800, 0x265c7f00,
904 +};
905 +
906 +/*
907 + * Correction for the 4th order CIC filter's gain of (rate ** 4)
908 + * expressed as a right-shift and a reciprocal scale factor (Q12).
909 + * These arrays are indexed by [rate - 4] where 4 <= rate <= 16.
910 + */
911 +
912 +static const int rp1vec_scale_table[13] = {
913 + 4096, 6711, 6473, 6988,
914 + 4096, 5114, 6711, 4584,
915 + 6473, 4699, 6988, 5302,
916 + 4096
917 +};
918 +
919 +static const u32 rp1vec_rate_shift_table[13] = {
920 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 3) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 7),
921 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 4) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 9),
922 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 5) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 10),
923 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 6) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 11),
924 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 7) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 11),
925 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 8) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 12),
926 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 9) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 13),
927 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 10) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 13),
928 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 11) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 14),
929 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 12) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 14),
930 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 13) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 15),
931 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 14) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 15),
932 + BITS(VEC_DAC_EC_INTERP_RATE_MINUS1, 15) | BITS(VEC_DAC_EC_INTERP_SHIFT_MINUS1, 15),
933 +};
934 +
935 void rp1vec_hw_setup(struct rp1_vec *vec,
936 u32 in_format,
937 struct drm_display_mode const *mode,
938 int tvstd)
939 {
940 - unsigned int i, mode_family, mode_ilaced, mode_narrow;
941 + int i, mode_family, w, h;
942 const struct rp1vec_hwmode *hwm;
943 - int w, h, hpad, vpad;
944 + int wmax, hpad_r, vpad_b, rate, ref_2mid, usr_2mid;
945 + u32 misc;
946
947 - /* Pick the appropriate "base" mode, which we may modify */
948 - mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
949 - if (mode->vtotal >= 272 * (1 + mode_ilaced))
950 + /* Input pixel format conversion */
951 + for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
952 + if (my_formats[i].format == in_format)
953 + break;
954 + }
955 + if (i >= ARRAY_SIZE(my_formats)) {
956 + dev_err(&vec->pdev->dev, "%s: bad input format\n", __func__);
957 + i = 0;
958 + }
959 + VEC_WRITE(VEC_IMASK, my_formats[i].mask);
960 + VEC_WRITE(VEC_SHIFT, my_formats[i].shift);
961 + VEC_WRITE(VEC_RGBSZ, my_formats[i].rgbsz);
962 +
963 + /* Pick an appropriate "base" mode, which we may modify.
964 + * Note that this driver supports a limited selection of video modes.
965 + * (A complete TV mode cannot be directly inferred from a DRM display mode:
966 + * features such as chroma burst sequence, half-lines and equalizing pulses
967 + * would be under-specified, and timings prone to rounding errors.)
968 + */
969 + if (mode->vtotal == 405 || mode->vtotal == 819) {
970 + /* Systems A and E (interlaced only) */
971 + vec->fake_31khz = false;
972 mode_family = 1;
973 - else if (tvstd == DRM_MODE_TV_MODE_PAL_M || tvstd == DRM_MODE_TV_MODE_PAL)
974 - mode_family = 2;
975 - else
976 - mode_family = 0;
977 - mode_narrow = (mode->clock >= 14336);
978 - hwm = &rp1vec_hwmodes[mode_family][mode_ilaced][mode_narrow];
979 - dev_info(&vec->pdev->dev,
980 - "%s: in_fmt=\'%c%c%c%c\' mode=%dx%d%s [%d%d%d] tvstd=%d",
981 - __func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24,
982 - mode->hdisplay, mode->vdisplay, (mode_ilaced) ? "i" : "",
983 - mode_family, mode_ilaced, mode_narrow, tvstd);
984 -
985 - w = mode->hdisplay;
986 - h = mode->vdisplay >> mode_ilaced;
987 - if (w > hwm->total_cols)
988 - w = hwm->total_cols;
989 - if (h > hwm->rows_per_field)
990 - h = hwm->rows_per_field;
991 + hwm = &rp1vec_vintage_modes[(mode->vtotal == 819) ? 1 : 0];
992 + } else {
993 + /* 525- and 625-line modes, with half-height and "fake" progressive variants */
994 + vec->fake_31khz = mode->vtotal >= 500 && !(mode->flags & DRM_MODE_FLAG_INTERLACE);
995 + h = (mode->vtotal >= 500) ? (mode->vtotal >> 1) : mode->vtotal;
996 + if (h >= 272)
997 + mode_family = 1; /* PAL-625 */
998 + else if (tvstd == DRM_MODE_TV_MODE_PAL_M || tvstd == DRM_MODE_TV_MODE_PAL)
999 + mode_family = 2; /* PAL-525 */
1000 + else
1001 + mode_family = 0; /* NTSC-525 */
1002 + hwm = &rp1vec_hwmodes[mode_family][(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0];
1003 + }
1004
1005 /*
1006 - * Add padding so a framebuffer with the given dimensions and
1007 - * [hv]sync_start can be displayed in the chosen hardware mode.
1008 - *
1009 - * |<----- mode->hsync_start ----->|
1010 - * |<------ w ------>| |
1011 - * | | >|--|< ref_hfp
1012 - * |<- hpad ->|
1013 - * |<------------ total_cols ----------->|
1014 - * ________FRAMEBUFFERCONTENTS__________
1015 - * ' `--\____/-<\/\/\>-'
1016 + * Choose the upsampling rate (to 108MHz) in the range 4..16.
1017 + * Clip dimensions to the limits of the chosen hardware mode, then add
1018 + * padding as required, making some attempt to respect the DRM mode's
1019 + * display position (relative to H and V sync start). Note that "wmax"
1020 + * should be wider than the horizontal active region, to avoid boundary
1021 + * artifacts (e.g. wmax = 728, w = 720, active ~= 704 in Rec.601 modes).
1022 */
1023 - hpad = max(0, mode->hsync_start - hwm->ref_hfp - w);
1024 - hpad = min(hpad, hwm->total_cols - w);
1025 - vpad = max(0, ((mode->vsync_start - hwm->ref_vfp) >> mode_ilaced) - h);
1026 - vpad = min(vpad, hwm->rows_per_field - h);
1027 + i = (vec->fake_31khz) ? (mode->clock >> 1) : mode->clock;
1028 + rate = (i < (RP1VEC_VDAC_KHZ / 16)) ? 16 : max(4, (RP1VEC_VDAC_KHZ + 256) / i);
1029 + wmax = min((hwm->de_end - hwm->de_bgn) / rate, 1020);
1030 + w = min(mode->hdisplay, wmax);
1031 + ref_2mid = (hwm->de_bgn + hwm->de_end) / rate + 4; /* + 4 for FIR delay */
1032 + usr_2mid = (2 * (mode->htotal - mode->hsync_start) + w) * 2 * (hwm->timing_regs[1] >> 16) /
1033 + (rate * mode->htotal);
1034 + hpad_r = (wmax - w + ref_2mid - usr_2mid) >> 1;
1035 + hpad_r = min(max(0, hpad_r), wmax - w);
1036 + h = mode->vdisplay >> (hwm->interlaced || vec->fake_31khz);
1037 + h = min(h, 0 + hwm->max_rows_per_field);
1038 + vpad_b = ((mode->vsync_start - hwm->ref_vfp) >> (hwm->interlaced || vec->fake_31khz)) - h;
1039 + vpad_b = min(max(0, vpad_b), hwm->max_rows_per_field - h);
1040
1041 - /* Configure the hardware */
1042 + /* Configure the hardware "front end" (in the sysclock domain) */
1043 VEC_WRITE(VEC_APB_TIMEOUT, 0x38);
1044 VEC_WRITE(VEC_QOS,
1045 BITS(VEC_QOS_DQOS, 0x0) |
1046 @@ -384,66 +428,78 @@ void rp1vec_hw_setup(struct rp1_vec *vec
1047 VEC_WRITE(VEC_DMA_AREA,
1048 BITS(VEC_DMA_AREA_COLS_MINUS1, w - 1) |
1049 BITS(VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1, h - 1));
1050 - VEC_WRITE(VEC_YUV_SCALING, hwm->yuv_scaling);
1051 + VEC_WRITE(VEC_YUV_SCALING,
1052 + BITS(VEC_YUV_SCALING_U10_SCALE_Y,
1053 + (hwm->scale_y * rp1vec_scale_table[rate - 4] + 2048) >> 12) |
1054 + BITS(VEC_YUV_SCALING_S10_SCALE_U,
1055 + (hwm->scale_u * rp1vec_scale_table[rate - 4] + 2048) >> 12) |
1056 + BITS(VEC_YUV_SCALING_S10_SCALE_V,
1057 + (hwm->scale_v * rp1vec_scale_table[rate - 4] + 2048) >> 12));
1058 VEC_WRITE(VEC_BACK_PORCH,
1059 - BITS(VEC_BACK_PORCH_HBP_MINUS1, hwm->total_cols - w - hpad - 1) |
1060 - BITS(VEC_BACK_PORCH_VBP_MINUS1, hwm->rows_per_field - h - vpad - 1));
1061 + BITS(VEC_BACK_PORCH_HBP_MINUS1, wmax - w - hpad_r - 1) |
1062 + BITS(VEC_BACK_PORCH_VBP_MINUS1, hwm->max_rows_per_field - h - vpad_b - 1));
1063 VEC_WRITE(VEC_FRONT_PORCH,
1064 - BITS(VEC_FRONT_PORCH_HFP_MINUS1, hpad - 1) |
1065 - BITS(VEC_FRONT_PORCH_VFP_MINUS1, vpad - 1));
1066 + BITS(VEC_FRONT_PORCH_HFP_MINUS1, hpad_r - 1) |
1067 + BITS(VEC_FRONT_PORCH_VFP_MINUS1, vpad_b - 1));
1068 VEC_WRITE(VEC_MODE,
1069 - BITS(VEC_MODE_HIGH_WATER, 0xE0) |
1070 - BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15)) |
1071 - BITS(VEC_MODE_VFP_EN, (vpad > 0)) |
1072 - BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h + vpad)) |
1073 - BITS(VEC_MODE_HFP_EN, (hpad > 0)) |
1074 - BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w + hpad)) |
1075 - BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) |
1076 + BITS(VEC_MODE_HIGH_WATER, 0xE0) |
1077 + BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15)) |
1078 + BITS(VEC_MODE_VFP_EN, (vpad_b > 0)) |
1079 + BITS(VEC_MODE_VBP_EN, (hwm->max_rows_per_field > h + vpad_b)) |
1080 + BITS(VEC_MODE_HFP_EN, (hpad_r > 0)) |
1081 + BITS(VEC_MODE_HBP_EN, (wmax > w + hpad_r)) |
1082 + BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) |
1083 BITS(VEC_MODE_FIRST_FIELD_ODD, hwm->first_field_odd));
1084 - for (i = 0; i < ARRAY_SIZE(hwm->back_end_regs); ++i) {
1085 - writel(hwm->back_end_regs[i],
1086 - vec->hw_base[RP1VEC_HW_BLOCK_VEC] + 0x80 + 4 * i);
1087 - }
1088
1089 - /* Apply modifications */
1090 + /* Configure the hardware "back end" (in the VDAC clock domain) */
1091 + VEC_WRITE(VEC_DAC_80,
1092 + BITS(VEC_DAC_80_U14_DE_BGN, hwm->de_bgn) |
1093 + BITS(VEC_DAC_80_U14_DE_END, hwm->de_bgn + wmax * rate));
1094 + rp1vec_write_regs(vec, 0x84, hwm->timing_regs, ARRAY_SIZE(hwm->timing_regs));
1095 + VEC_WRITE(VEC_DAC_C0, 0x0); /* DAC control/status -- not wired up in RP1 */
1096 + VEC_WRITE(VEC_DAC_C4, 0x007bffff); /* DAC control -- not wired up in RP1 */
1097 + misc = hwm->half_lines_per_field;
1098 + if (misc == 524 && (mode->vtotal >> vec->fake_31khz) == 263)
1099 + misc += 2;
1100 if (tvstd == DRM_MODE_TV_MODE_NTSC_J && mode_family == 0) {
1101 - /* Reduce pedestal (not quite to zero, for FIR overshoot); increase gain */
1102 + /* NTSC-J modification: reduce pedestal and increase gain */
1103 VEC_WRITE(VEC_DAC_BC,
1104 - BITS(VEC_DAC_BC_S11_PEDESTAL, 10) |
1105 - (hwm->back_end_regs[(0xBC - 0x80) / 4] & ~VEC_DAC_BC_S11_PEDESTAL_BITS));
1106 + BITS(VEC_DAC_BC_U11_HALF_LINES_PER_FIELD, misc) |
1107 + BITS(VEC_DAC_BC_S11_PEDESTAL, 0x00a));
1108 VEC_WRITE(VEC_DAC_C8,
1109 BITS(VEC_DAC_C8_U16_SCALE_LUMA, 0x9400) |
1110 - (hwm->back_end_regs[(0xC8 - 0x80) / 4] &
1111 - ~VEC_DAC_C8_U16_SCALE_LUMA_BITS));
1112 - } else if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL) &&
1113 - mode_family != 1) {
1114 + BITS(VEC_DAC_C8_U16_SCALE_SYNC, hwm->scale_sync));
1115 + } else {
1116 + VEC_WRITE(VEC_DAC_BC,
1117 + BITS(VEC_DAC_BC_U11_HALF_LINES_PER_FIELD, misc) |
1118 + BITS(VEC_DAC_BC_S11_PEDESTAL, hwm->pedestal));
1119 + VEC_WRITE(VEC_DAC_C8,
1120 + BITS(VEC_DAC_C8_U16_SCALE_LUMA, hwm->scale_luma) |
1121 + BITS(VEC_DAC_C8_U16_SCALE_SYNC, hwm->scale_sync));
1122 + }
1123 + VEC_WRITE(VEC_DAC_CC, (tvstd >= DRM_MODE_TV_MODE_SECAM) ? 0 : hwm->scale_burst_chroma);
1124 + VEC_WRITE(VEC_DAC_D0, 0x02000000); /* ADC offsets -- not needed in RP1? */
1125 + misc = hwm->misc;
1126 + if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL) &&
1127 + mode_family != 1) {
1128 /* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */
1129 VEC_WRITE(VEC_DAC_D4, 0xcc48c1d1);
1130 VEC_WRITE(VEC_DAC_D8, 0x0a8262b2);
1131 - VEC_WRITE(VEC_DAC_EC,
1132 - hwm->back_end_regs[(0xEC - 0x80) / 4] & ~VEC_DAC_EC_SEQ_EN_BITS);
1133 + misc &= ~VEC_DAC_EC_SEQ_EN_BITS;
1134 } else if (tvstd == DRM_MODE_TV_MODE_PAL_N && mode_family == 1) {
1135 /* Change colour carrier frequency to 3582056.25 Hz */
1136 VEC_WRITE(VEC_DAC_D4, 0x9ce075f7);
1137 VEC_WRITE(VEC_DAC_D8, 0x087da511);
1138 + } else {
1139 + VEC_WRITE(VEC_DAC_D4, (u32)(hwm->nco_freq));
1140 + VEC_WRITE(VEC_DAC_D8, (u32)(hwm->nco_freq >> 32));
1141 }
1142 + VEC_WRITE(VEC_DAC_EC, misc | rp1vec_rate_shift_table[rate - 4]);
1143 + rp1vec_write_regs(vec, 0xDC, rp1vec_fir_regs, ARRAY_SIZE(rp1vec_fir_regs));
1144
1145 - /* Input pixel format conversion */
1146 - for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
1147 - if (my_formats[i].format == in_format)
1148 - break;
1149 - }
1150 - if (i >= ARRAY_SIZE(my_formats)) {
1151 - dev_err(&vec->pdev->dev, "%s: bad input format\n", __func__);
1152 - i = 0;
1153 - }
1154 - VEC_WRITE(VEC_IMASK, my_formats[i].mask);
1155 - VEC_WRITE(VEC_SHIFT, my_formats[i].shift);
1156 - VEC_WRITE(VEC_RGBSZ, my_formats[i].rgbsz);
1157 -
1158 - VEC_WRITE(VEC_IRQ_FLAGS, 0xffffffff);
1159 + /* Set up interrupts and initialise VEC. It will start on the next rp1vec_hw_update() */
1160 + VEC_WRITE(VEC_IRQ_FLAGS, 0xFFFFFFFFu);
1161 rp1vec_hw_vblank_ctrl(vec, 1);
1162 -
1163 i = rp1vec_hw_busy(vec);
1164 if (i)
1165 dev_warn(&vec->pdev->dev,
1166 @@ -464,6 +520,10 @@ void rp1vec_hw_update(struct rp1_vec *ve
1167 */
1168 u64 a = addr + offset;
1169
1170 + if (vec->fake_31khz) {
1171 + a += stride;
1172 + stride *= 2;
1173 + }
1174 VEC_WRITE(VEC_DMA_STRIDE, stride);
1175 VEC_WRITE(VEC_DMA_ADDR_H, a >> 32);
1176 VEC_WRITE(VEC_DMA_ADDR_L, a & 0xFFFFFFFFu);