Skip to content

Commit 30ac8b8

Browse files
drm: rp1: Use tv_mode from the command line and fix for Linux 6.6
Use the standard enum drm_connector_tv_mode instead of a private enum and switch from the legacy to the standard tv_mode property. Remove the module parameter "tv_norm". Instead, get tv_mode from the command line and make this the connector's default TV mode. Don't restrict the choice of modes based on tv_mode, but interpret nonstandard combinations as NTSC or PAL, depending on resolution. Thus the default tv_mode=NTSC effectively means "Auto". Tweak the advertised horizontal timings for 625/50 to match Rec.601 Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent 3bcc388 commit 30ac8b8

File tree

3 files changed

+63
-110
lines changed

3 files changed

+63
-110
lines changed

drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c

Lines changed: 48 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -48,52 +48,6 @@
4848

4949
#include "rp1_vec.h"
5050

51-
/*
52-
* Default TV standard parameter; it may be overridden by the OF
53-
* property "tv_norm" (which should be one of the strings below).
54-
*
55-
* The default (empty string) supports various 60Hz and 50Hz modes,
56-
* and will automatically select NTSC[-M] or PAL[-BDGHIKL]; the two
57-
* "fake" 60Hz standards NTSC-443 and PAL60 also support 50Hz PAL.
58-
* Other values will restrict the set of video modes offered.
59-
*
60-
* Finally, the DRM connector property "mode" (which is an integer)
61-
* can be used to override this value, but it does not prevent the
62-
* selection of an inapplicable video mode.
63-
*/
64-
65-
static char *rp1vec_tv_norm_str;
66-
module_param_named(tv_norm, rp1vec_tv_norm_str, charp, 0600);
67-
MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
68-
"\t\tSupported: NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N,\n"
69-
"\t\t\tPAL60.\n"
70-
"\t\tDefault: empty string: infer PAL for a 50 Hz mode,\n"
71-
"\t\t\tNTSC otherwise");
72-
73-
const char * const rp1vec_tvstd_names[] = {
74-
[RP1VEC_TVSTD_NTSC] = "NTSC",
75-
[RP1VEC_TVSTD_NTSC_J] = "NTSC-J",
76-
[RP1VEC_TVSTD_NTSC_443] = "NTSC-443",
77-
[RP1VEC_TVSTD_PAL] = "PAL",
78-
[RP1VEC_TVSTD_PAL_M] = "PAL-M",
79-
[RP1VEC_TVSTD_PAL_N] = "PAL-N",
80-
[RP1VEC_TVSTD_PAL60] = "PAL60",
81-
[RP1VEC_TVSTD_DEFAULT] = "",
82-
};
83-
84-
static int rp1vec_parse_tv_norm(const char *str)
85-
{
86-
int i;
87-
88-
if (str && *str) {
89-
for (i = 0; i < ARRAY_SIZE(rp1vec_tvstd_names); ++i) {
90-
if (strcasecmp(str, rp1vec_tvstd_names[i]) == 0)
91-
return i;
92-
}
93-
}
94-
return RP1VEC_TVSTD_DEFAULT;
95-
}
96-
9751
static void rp1vec_pipe_update(struct drm_simple_display_pipe *pipe,
9852
struct drm_plane_state *old_state)
9953
{
@@ -143,7 +97,7 @@ static void rp1vec_pipe_update(struct drm_simple_display_pipe *pipe,
14397

14498
static void rp1vec_pipe_enable(struct drm_simple_display_pipe *pipe,
14599
struct drm_crtc_state *crtc_state,
146-
struct drm_plane_state *plane_state)
100+
struct drm_plane_state *plane_state)
147101
{
148102
struct rp1_vec *vec = pipe->crtc.dev->dev_private;
149103

@@ -219,48 +173,64 @@ static const struct drm_display_mode rp1vec_modes[4] = {
219173
},
220174
{ /* Full size 625/50i with Rec.601 pixel rate */
221175
DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
222-
720, 720 + 20, 720 + 20 + 64, 864, 0,
176+
720, 720 + 12, 720 + 12 + 64, 864, 0,
223177
576, 576 + 5, 576 + 5 + 5, 625, 0,
224178
DRM_MODE_FLAG_INTERLACE)
225179
},
226180
{ /* Cropped and squashed, for square(ish) pixels */
227181
DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429,
228-
704, 704 + 80, 704 + 80 + 72, 987, 0,
182+
704, 704 + 72, 704 + 72 + 72, 987, 0,
229183
512, 512 + 37, 512 + 37 + 5, 625, 0,
230184
DRM_MODE_FLAG_INTERLACE)
231185
}
232186
};
233187

188+
/*
189+
* Advertise standard and preferred video modes.
190+
*
191+
* From each interlaced mode in the table above, derive a progressive one.
192+
*
193+
* This driver always supports all 50Hz and 60Hz video modes, regardless
194+
* of connector's tv_mode; nonstandard combinations generally default
195+
* to PAL[-BDGHIKL] or NTSC[-M] depending on resolution and field-rate
196+
* (except that "PAL" with 525/60 will be implemented as "PAL60").
197+
* However, the preferred mode will depend on the default TV mode.
198+
*/
199+
234200
static int rp1vec_connector_get_modes(struct drm_connector *connector)
235201
{
236-
struct rp1_vec *vec = container_of(connector, struct rp1_vec, connector);
237-
bool ok525 = RP1VEC_TVSTD_SUPPORT_525(vec->tv_norm);
238-
bool ok625 = RP1VEC_TVSTD_SUPPORT_625(vec->tv_norm);
202+
u64 val;
239203
int i, prog, n = 0;
204+
bool prefer625 = false;
205+
206+
if (!drm_object_property_get_default_value(&connector->base,
207+
connector->dev->mode_config.tv_mode_property,
208+
&val))
209+
prefer625 = (val == DRM_MODE_TV_MODE_PAL ||
210+
val == DRM_MODE_TV_MODE_PAL_N ||
211+
val == DRM_MODE_TV_MODE_SECAM);
240212

241213
for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) {
242-
if ((rp1vec_modes[i].vtotal == 625) ? ok625 : ok525) {
243-
for (prog = 0; prog < 2; prog++) {
244-
struct drm_display_mode *mode =
245-
drm_mode_duplicate(connector->dev,
246-
&rp1vec_modes[i]);
247-
248-
if (prog) {
249-
mode->flags &= ~DRM_MODE_FLAG_INTERLACE;
250-
mode->vdisplay >>= 1;
251-
mode->vsync_start >>= 1;
252-
mode->vsync_end >>= 1;
253-
mode->vtotal >>= 1;
254-
}
255-
256-
if (mode->hdisplay == 704 &&
257-
mode->vtotal == ((ok525) ? 525 : 625))
258-
mode->type |= DRM_MODE_TYPE_PREFERRED;
259-
260-
drm_mode_set_name(mode);
261-
drm_mode_probed_add(connector, mode);
262-
n++;
214+
for (prog = 0; prog < 2; prog++) {
215+
struct drm_display_mode *mode =
216+
drm_mode_duplicate(connector->dev,
217+
&rp1vec_modes[i]);
218+
219+
if (prog) {
220+
mode->flags &= ~DRM_MODE_FLAG_INTERLACE;
221+
mode->vdisplay >>= 1;
222+
mode->vsync_start >>= 1;
223+
mode->vsync_end >>= 1;
224+
mode->vtotal >>= 1;
263225
}
226+
227+
if (mode->hdisplay == 704 &&
228+
mode->vtotal == (prefer625 ? 625 : 525))
229+
mode->type |= DRM_MODE_TYPE_PREFERRED;
230+
231+
drm_mode_set_name(mode);
232+
drm_mode_probed_add(connector, mode);
233+
n++;
264234
}
265235
}
266236

@@ -269,11 +239,8 @@ static int rp1vec_connector_get_modes(struct drm_connector *connector)
269239

270240
static void rp1vec_connector_reset(struct drm_connector *connector)
271241
{
272-
struct rp1_vec *vec = container_of(connector, struct rp1_vec, connector);
273-
274242
drm_atomic_helper_connector_reset(connector);
275-
if (connector->state)
276-
connector->state->tv.mode = vec->tv_norm;
243+
drm_atomic_helper_connector_tv_reset(connector);
277244
}
278245

279246
static int rp1vec_connector_atomic_check(struct drm_connector *conn,
@@ -396,7 +363,6 @@ static int rp1vec_platform_probe(struct platform_device *pdev)
396363
struct device *dev = &pdev->dev;
397364
struct drm_device *drm;
398365
struct rp1_vec *vec;
399-
const char *str;
400366
int i, ret;
401367

402368
dev_info(dev, __func__);
@@ -419,10 +385,6 @@ static int rp1vec_platform_probe(struct platform_device *pdev)
419385
drm->dev_private = vec;
420386
platform_set_drvdata(pdev, drm);
421387

422-
str = rp1vec_tv_norm_str;
423-
of_property_read_string(dev->of_node, "tv_norm", &str);
424-
vec->tv_norm = rp1vec_parse_tv_norm(str);
425-
426388
for (i = 0; i < RP1VEC_NUM_HW_BLOCKS; i++) {
427389
vec->hw_base[i] =
428390
devm_ioremap_resource(dev,
@@ -463,9 +425,7 @@ static int rp1vec_platform_probe(struct platform_device *pdev)
463425
drm->mode_config.funcs = &rp1vec_mode_funcs;
464426
drm_vblank_init(drm, 1);
465427

466-
ret = drm_mode_create_tv_properties_legacy(drm,
467-
ARRAY_SIZE(rp1vec_tvstd_names),
468-
rp1vec_tvstd_names);
428+
ret = drm_mode_create_tv_properties(drm, RP1VEC_SUPPORTED_TV_MODES);
469429
if (ret)
470430
goto err_free_drm;
471431

@@ -479,7 +439,9 @@ static int rp1vec_platform_probe(struct platform_device *pdev)
479439

480440
drm_object_attach_property(&vec->connector.base,
481441
drm->mode_config.tv_mode_property,
482-
vec->tv_norm);
442+
(vec->connector.cmdline_mode.tv_mode_specified) ?
443+
vec->connector.cmdline_mode.tv_mode :
444+
DRM_MODE_TV_MODE_NTSC);
483445

484446
ret = drm_simple_display_pipe_init(drm,
485447
&vec->pipe,

drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,13 @@
2020
#define RP1VEC_HW_BLOCK_CFG 1
2121
#define RP1VEC_NUM_HW_BLOCKS 2
2222

23-
enum {
24-
RP1VEC_TVSTD_NTSC = 0, /* +525 => NTSC 625 => PAL */
25-
RP1VEC_TVSTD_NTSC_J, /* +525 => NTSC-J 625 => PAL */
26-
RP1VEC_TVSTD_NTSC_443, /* +525 => NTSC-443 +625 => PAL */
27-
RP1VEC_TVSTD_PAL, /* 525 => NTSC +625 => PAL */
28-
RP1VEC_TVSTD_PAL_M, /* +525 => PAL-M 625 => PAL */
29-
RP1VEC_TVSTD_PAL_N, /* 525 => NTSC +625 => PAL-N */
30-
RP1VEC_TVSTD_PAL60, /* +525 => PAL60 +625 => PAL */
31-
RP1VEC_TVSTD_DEFAULT, /* +525 => NTSC +625 => PAL */
32-
};
33-
34-
/* Which standards support which modes? Those marked with + above */
35-
#define RP1VEC_TVSTD_SUPPORT_525(n) ((0xD7 >> (n)) & 1)
36-
#define RP1VEC_TVSTD_SUPPORT_625(n) ((0xEC >> (n)) & 1)
23+
#define RP1VEC_SUPPORTED_TV_MODES \
24+
(BIT(DRM_MODE_TV_MODE_NTSC) | \
25+
BIT(DRM_MODE_TV_MODE_NTSC_443) | \
26+
BIT(DRM_MODE_TV_MODE_NTSC_J) | \
27+
BIT(DRM_MODE_TV_MODE_PAL) | \
28+
BIT(DRM_MODE_TV_MODE_PAL_M) | \
29+
BIT(DRM_MODE_TV_MODE_PAL_N))
3730

3831
/* ---------------------------------------------------------------------- */
3932

@@ -52,13 +45,10 @@ struct rp1_vec {
5245
/* Block (VCC, CFG) base addresses, and current state */
5346
void __iomem *hw_base[RP1VEC_NUM_HW_BLOCKS];
5447
u32 cur_fmt;
55-
int tv_norm;
5648
bool vec_running, pipe_enabled;
5749
struct completion finished;
5850
};
5951

60-
extern const char * const rp1vec_tvstd_names[];
61-
6252
/* ---------------------------------------------------------------------- */
6353
/* Functions to control the VEC/DMA block */
6454

drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,16 +337,17 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
337337
mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
338338
if (mode->vtotal >= 272 * (1 + mode_ilaced))
339339
mode_family = 1;
340+
else if (tvstd == DRM_MODE_TV_MODE_PAL_M || tvstd == DRM_MODE_TV_MODE_PAL)
341+
mode_family = 2;
340342
else
341-
mode_family = (tvstd == RP1VEC_TVSTD_PAL_M || tvstd == RP1VEC_TVSTD_PAL60) ? 2 : 0;
343+
mode_family = 0;
342344
mode_narrow = (mode->clock >= 14336);
343345
hwm = &rp1vec_hwmodes[mode_family][mode_ilaced][mode_narrow];
344346
dev_info(&vec->pdev->dev,
345-
"%s: in_fmt=\'%c%c%c%c\' mode=%dx%d%s [%d%d%d] tvstd=%d (%s)",
347+
"%s: in_fmt=\'%c%c%c%c\' mode=%dx%d%s [%d%d%d] tvstd=%d",
346348
__func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24,
347349
mode->hdisplay, mode->vdisplay, (mode_ilaced) ? "i" : "",
348-
mode_family, mode_ilaced, mode_narrow,
349-
tvstd, rp1vec_tvstd_names[tvstd]);
350+
mode_family, mode_ilaced, mode_narrow, tvstd);
350351

351352
w = mode->hdisplay;
352353
h = mode->vdisplay >> mode_ilaced;
@@ -405,7 +406,7 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
405406
}
406407

407408
/* Apply modifications */
408-
if (tvstd == RP1VEC_TVSTD_NTSC_J && mode_family == 0) {
409+
if (tvstd == DRM_MODE_TV_MODE_NTSC_J && mode_family == 0) {
409410
/* Reduce pedestal (not quite to zero, for FIR overshoot); increase gain */
410411
VEC_WRITE(VEC_DAC_BC,
411412
BITS(VEC_DAC_BC_S11_PEDESTAL, 10) |
@@ -414,14 +415,14 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
414415
BITS(VEC_DAC_C8_U16_SCALE_LUMA, 0x9400) |
415416
(hwm->back_end_regs[(0xC8 - 0x80) / 4] &
416417
~VEC_DAC_C8_U16_SCALE_LUMA_BITS));
417-
} else if ((tvstd == RP1VEC_TVSTD_NTSC_443 || tvstd == RP1VEC_TVSTD_PAL60) &&
418+
} else if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL) &&
418419
mode_family != 1) {
419420
/* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */
420421
VEC_WRITE(VEC_DAC_D4, 0xcc48c1d1);
421422
VEC_WRITE(VEC_DAC_D8, 0x0a8262b2);
422423
VEC_WRITE(VEC_DAC_EC,
423424
hwm->back_end_regs[(0xEC - 0x80) / 4] & ~VEC_DAC_EC_SEQ_EN_BITS);
424-
} else if (tvstd == RP1VEC_TVSTD_PAL_N && mode_family == 1) {
425+
} else if (tvstd == DRM_MODE_TV_MODE_PAL_N && mode_family == 1) {
425426
/* Change colour carrier frequency to 3582056.25 Hz */
426427
VEC_WRITE(VEC_DAC_D4, 0x9ce075f7);
427428
VEC_WRITE(VEC_DAC_D8, 0x087da511);

0 commit comments

Comments
 (0)