Skip to content

Commit c9840e0

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 63c8194 commit c9840e0

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

@@ -617,8 +613,12 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
617613
{
618614
struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
619615
struct vc4_vec *vec = vc4_vec_encoder->vec;
616+
struct drm_display_mode *adjusted_mode =
617+
&encoder->crtc->state->adjusted_mode;
620618
unsigned int tv_mode = vec->connector->state->tv.mode;
621619
int ret;
620+
long eff_clk_rate;
621+
u64 chroma_freq;
622622

623623
ret = pm_runtime_get_sync(&vec->pdev->dev);
624624
if (ret < 0) {
@@ -633,7 +633,7 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
633633
* The good news is, these 2 encoders cannot be enabled at the same
634634
* time, thus preventing incompatible rate requests.
635635
*/
636-
ret = clk_set_rate(vec->clock, 108000000);
636+
ret = clk_set_rate(vec->clock, 8000 * adjusted_mode->clock);
637637
if (ret) {
638638
DRM_ERROR("Failed to set clock rate: %d\n", ret);
639639
return;
@@ -645,6 +645,9 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
645645
return;
646646
}
647647

648+
eff_clk_rate = clk_get_rate(vec->clock);
649+
DRM_DEBUG_DRIVER("Effective clock rate: %ld\n", eff_clk_rate);
650+
648651
/* Reset the different blocks */
649652
VEC_WRITE(VEC_WSE_RESET, 1);
650653
VEC_WRITE(VEC_SOFT_RESET, 1);
@@ -668,23 +671,29 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
668671
VEC_WRITE(VEC_CONFIG2,
669672
VEC_CONFIG2_UV_DIG_DIS |
670673
VEC_CONFIG2_RGB_DIG_DIS |
671-
((encoder->crtc->state->adjusted_mode.flags &
672-
DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
674+
((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
675+
? 0 : VEC_CONFIG2_PROG_SCAN));
673676
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
674677
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
675678

676679
/* Mask all interrupts. */
677680
VEC_WRITE(VEC_MASK0, 0);
678681

679682
VEC_WRITE(VEC_CONFIG0, vc4_vec_tv_modes[tv_mode].config0);
680-
VEC_WRITE(VEC_CONFIG1, vc4_vec_tv_modes[tv_mode].config1);
681-
if (vc4_vec_tv_modes[tv_mode].custom_freq != 0) {
682-
VEC_WRITE(VEC_FREQ3_2,
683-
(vc4_vec_tv_modes[tv_mode].custom_freq >> 16) &
684-
0xffff);
685-
VEC_WRITE(VEC_FREQ1_0,
686-
vc4_vec_tv_modes[tv_mode].custom_freq & 0xffff);
687-
}
683+
VEC_WRITE(VEC_CONFIG1,
684+
VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
685+
686+
chroma_freq = vc4_vec_tv_modes[tv_mode].chroma_freq_millihz << 31;
687+
chroma_freq += (125ull * (u64)eff_clk_rate) >> 1; /* proper rounding */
688+
do_div(chroma_freq, eff_clk_rate);
689+
do_div(chroma_freq, 125);
690+
VEC_WRITE(VEC_FREQ3_2, (chroma_freq >> 16) & 0xffff);
691+
VEC_WRITE(VEC_FREQ1_0, chroma_freq & 0xffff);
692+
693+
/* SECAM Db frequency */
694+
chroma_freq = ((4250000000ull / 125) << 31) + eff_clk_rate / 2;
695+
do_div(chroma_freq, eff_clk_rate);
696+
VEC_WRITE(VEC_FCW_SECAM_B, chroma_freq);
688697

689698
VEC_WRITE(VEC_DAC_MISC,
690699
VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);

0 commit comments

Comments
 (0)