Skip to content

Commit 97cce17

Browse files
author
Mateusz Kwiatkowski
committed
drm/vc4: Make the VEC clock adjustable
Add support for pixel clocks other than the standard 13.5 MHz. Make the color subcarrier frequencies calculated relative to the actual clock so that they stay within spec. Signed-off-by: Mateusz Kwiatkowski <[email protected]>
1 parent 6eebd36 commit 97cce17

File tree

1 file changed

+33
-24
lines changed

1 file changed

+33
-24
lines changed

drivers/gpu/drm/vc4/vc4_vec.c

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ struct vc4_vec_tv_mode {
254254
const struct drm_display_mode *interlaced_mode;
255255
const struct drm_display_mode *progressive_mode;
256256
u32 config0;
257-
u32 config1;
258-
u32 custom_freq;
257+
u64 chroma_freq_millihz;
259258
};
260259

261260
static const struct debugfs_reg32 vec_regs[] = {
@@ -316,54 +315,51 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
316315
.interlaced_mode = &drm_mode_480i,
317316
.progressive_mode = &drm_mode_240p,
318317
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
319-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
318+
.chroma_freq_millihz = 3579545455ull,
320319
},
321320
[VC4_VEC_TV_MODE_NTSC_J] = {
322321
.interlaced_mode = &drm_mode_480i,
323322
.progressive_mode = &drm_mode_240p,
324323
.config0 = VEC_CONFIG0_NTSC_STD,
325-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
324+
.chroma_freq_millihz = 3579545455ull,
326325
},
327326
[VC4_VEC_TV_MODE_NTSC_443] = {
328327
/* NTSC with PAL chroma frequency */
329328
.interlaced_mode = &drm_mode_480i,
330329
.progressive_mode = &drm_mode_240p,
331330
.config0 = VEC_CONFIG0_NTSC_STD,
332-
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
333-
.custom_freq = 0x2a098acb,
331+
.chroma_freq_millihz = 4433618750ull,
334332
},
335333
[VC4_VEC_TV_MODE_PAL] = {
336334
.interlaced_mode = &drm_mode_576i,
337335
.progressive_mode = &drm_mode_288p,
338336
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
339-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
337+
.chroma_freq_millihz = 4433618750ull,
340338
},
341339
[VC4_VEC_TV_MODE_PAL_M] = {
342340
.interlaced_mode = &drm_mode_480i,
343341
.progressive_mode = &drm_mode_240p,
344342
.config0 = VEC_CONFIG0_PAL_M_STD,
345-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
343+
.chroma_freq_millihz = 3575611888ull,
346344
},
347345
[VC4_VEC_TV_MODE_PAL_N] = {
348346
.interlaced_mode = &drm_mode_576i,
349347
.progressive_mode = &drm_mode_288p,
350348
.config0 = VEC_CONFIG0_PAL_N_STD,
351-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
349+
.chroma_freq_millihz = 3582056250ull,
352350
},
353351
[VC4_VEC_TV_MODE_PAL60] = {
354352
/* PAL-M with chroma frequency of regular PAL */
355353
.interlaced_mode = &drm_mode_480i,
356354
.progressive_mode = &drm_mode_240p,
357355
.config0 = VEC_CONFIG0_PAL_M_STD,
358-
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
359-
.custom_freq = 0x2a098acb,
356+
.chroma_freq_millihz = 4433618750ull,
360357
},
361358
[VC4_VEC_TV_MODE_SECAM] = {
362359
.interlaced_mode = &drm_mode_576i,
363360
.progressive_mode = &drm_mode_288p,
364361
.config0 = VEC_CONFIG0_SECAM_STD,
365-
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
366-
.custom_freq = 0x29c71c72,
362+
.chroma_freq_millihz = 4406250000ull,
367363
},
368364
};
369365

@@ -546,8 +542,12 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
546542
{
547543
struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
548544
struct vc4_vec *vec = vc4_vec_encoder->vec;
545+
struct drm_display_mode *adjusted_mode =
546+
&encoder->crtc->state->adjusted_mode;
549547
unsigned int tv_mode = vec->connector->state->tv.mode;
550548
int ret;
549+
long eff_clk_rate;
550+
u64 chroma_freq;
551551

552552
ret = pm_runtime_get_sync(&vec->pdev->dev);
553553
if (ret < 0) {
@@ -562,7 +562,7 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
562562
* The good news is, these 2 encoders cannot be enabled at the same
563563
* time, thus preventing incompatible rate requests.
564564
*/
565-
ret = clk_set_rate(vec->clock, 108000000);
565+
ret = clk_set_rate(vec->clock, 8000 * adjusted_mode->clock);
566566
if (ret) {
567567
DRM_ERROR("Failed to set clock rate: %d\n", ret);
568568
return;
@@ -574,6 +574,9 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
574574
return;
575575
}
576576

577+
eff_clk_rate = clk_get_rate(vec->clock);
578+
DRM_DEBUG_DRIVER("Effective clock rate: %ld\n", eff_clk_rate);
579+
577580
/* Reset the different blocks */
578581
VEC_WRITE(VEC_WSE_RESET, 1);
579582
VEC_WRITE(VEC_SOFT_RESET, 1);
@@ -597,23 +600,29 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
597600
VEC_WRITE(VEC_CONFIG2,
598601
VEC_CONFIG2_UV_DIG_DIS |
599602
VEC_CONFIG2_RGB_DIG_DIS |
600-
((encoder->crtc->state->adjusted_mode.flags &
601-
DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
603+
((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
604+
? 0 : VEC_CONFIG2_PROG_SCAN));
602605
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
603606
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
604607

605608
/* Mask all interrupts. */
606609
VEC_WRITE(VEC_MASK0, 0);
607610

608611
VEC_WRITE(VEC_CONFIG0, vc4_vec_tv_modes[tv_mode].config0);
609-
VEC_WRITE(VEC_CONFIG1, vc4_vec_tv_modes[tv_mode].config1);
610-
if (vc4_vec_tv_modes[tv_mode].custom_freq != 0) {
611-
VEC_WRITE(VEC_FREQ3_2,
612-
(vc4_vec_tv_modes[tv_mode].custom_freq >> 16) &
613-
0xffff);
614-
VEC_WRITE(VEC_FREQ1_0,
615-
vc4_vec_tv_modes[tv_mode].custom_freq & 0xffff);
616-
}
612+
VEC_WRITE(VEC_CONFIG1,
613+
VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
614+
615+
chroma_freq = vc4_vec_tv_modes[tv_mode].chroma_freq_millihz << 31;
616+
chroma_freq += (125ull * (u64)eff_clk_rate) >> 1; /* proper rounding */
617+
do_div(chroma_freq, eff_clk_rate);
618+
do_div(chroma_freq, 125);
619+
VEC_WRITE(VEC_FREQ3_2, (chroma_freq >> 16) & 0xffff);
620+
VEC_WRITE(VEC_FREQ1_0, chroma_freq & 0xffff);
621+
622+
/* SECAM Db frequency */
623+
chroma_freq = ((4250000000ull / 125) << 31) + eff_clk_rate / 2;
624+
do_div(chroma_freq, eff_clk_rate);
625+
VEC_WRITE(VEC_FCW_SECAM_B, chroma_freq);
617626

618627
VEC_WRITE(VEC_DAC_MISC,
619628
VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);

0 commit comments

Comments
 (0)