Commit 55d81aa5 authored by Andy Walls's avatar Andy Walls Committed by Mauro Carvalho Chehab

V4L/DVB (9937): cx18: Use a consistent crystal value for computing all PLL parameters

Use a consistent crystal value of 28.636360 MHz for computing all PLL
parameters so clocks don't have relative error due to assumed crystal
value mismatches.  Also aimed to have all PLLs run their VOCs at close to
400 MHz to minimze the error of these PLLs as frequency synthesizers. Also
set the VDCLK and AIMCLK PLLs to sane values before the APU and CPU firmware
are loaded.  Also fixed I2S Master clock dividers.

Many thanks to Mike Bradley and Jeff Campbell for reporting this problem and
suggesting the solution, researching and experimenting, and performing
extensive testing to support their suggested solution.
Reported-by: default avatarJeff Campbell <jac1dlists@gmail.com>
Reported-by: default avatarMike Bradley <mike.bradley@incanetworks.com>
Signed-off-by: default avatarAndy Walls <awalls@radix.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 57e24b62
...@@ -31,27 +31,67 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -31,27 +31,67 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000) if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL; return -EINVAL;
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ /*
cx18_av_write(cx, 0x127, 0x50); * The PLL parameters are based on the external crystal frequency that
* would ideally be:
*
* NTSC Color subcarrier freq * 8 =
* 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
*
* The accidents of history and rationale that explain from where this
* combination of magic numbers originate can be found in:
*
* [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
* the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
*
* [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
* NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
*
* As Mike Bradley has rightly pointed out, it's not the exact crystal
* frequency that matters, only that all parts of the driver and
* firmware are using the same value (close to the ideal value).
*
* Since I have a strong suspicion that, if the firmware ever assumes a
* crystal value at all, it will assume 28.636360 MHz, the crystal
* freq used in calculations in this driver will be:
*
* xtal_freq = 28.636360 MHz
*
* an error of less than 0.13 ppm which is way, way better than any off
* the shelf crystal will have for accuracy anyway.
*
* Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
*
* Many thanks to Jeff Campbell and Mike Bradley for their extensive
* investigation, experimentation, testing, and suggested solutions of
* of audio/video sync problems with SVideo and CVBS captures.
*/
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
switch (freq) { switch (freq) {
case 32000: case 32000:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x1408040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
*/
cx18_av_write4(cx, 0x108, 0x200d040f);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL_FRAC */ /* AUX_PLL Fraction = 0x176740c */
/* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */ /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x012a0863); cx18_av_write4(cx, 0x110, 0x0176740c);
/* src3/4/6_ctl */ /* src3/4/6_ctl */
/* 0x1.f77f = (4 * 15734.26) / 32000 */ /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
cx18_av_write4(cx, 0x900, 0x0801f77f); cx18_av_write4(cx, 0x900, 0x0801f77f);
cx18_av_write4(cx, 0x904, 0x0801f77f); cx18_av_write4(cx, 0x904, 0x0801f77f);
cx18_av_write4(cx, 0x90c, 0x0801f77f); cx18_av_write4(cx, 0x90c, 0x0801f77f);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
cx18_av_write(cx, 0x127, 0x54); cx18_av_write(cx, 0x127, 0x60);
/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11202fff); cx18_av_write4(cx, 0x12c, 0x11202fff);
...@@ -65,19 +105,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -65,19 +105,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break; break;
case 44100: case 44100:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x1009040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
*/
cx18_av_write4(cx, 0x108, 0x180e040f);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL_FRAC */ /* AUX_PLL Fraction = 0x062a1f2 */
/* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */ /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x00ec6bce); cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src3/4/6_ctl */ /* src3/4/6_ctl */
/* 0x1.6d59 = (4 * 15734.26) / 44100 */ /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
cx18_av_write4(cx, 0x900, 0x08016d59); cx18_av_write4(cx, 0x900, 0x08016d59);
cx18_av_write4(cx, 0x904, 0x08016d59); cx18_av_write4(cx, 0x904, 0x08016d59);
cx18_av_write4(cx, 0x90c, 0x08016d59); cx18_av_write4(cx, 0x90c, 0x08016d59);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
cx18_av_write(cx, 0x127, 0x58);
/* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x112092ff); cx18_av_write4(cx, 0x12c, 0x112092ff);
...@@ -90,19 +140,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -90,19 +140,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break; break;
case 48000: case 48000:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x100a040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
*/
cx18_av_write4(cx, 0x108, 0x160e040f);
/* AUX_PLL_FRAC */ /* VID_PLL Fraction = 0x2be2fe */
/* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x110, 0x0098d6dd); cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x005227ad);
/* src3/4/6_ctl */ /* src3/4/6_ctl */
/* 0x1.4faa = (4 * 15734.26) / 48000 */ /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
cx18_av_write4(cx, 0x900, 0x08014faa); cx18_av_write4(cx, 0x900, 0x08014faa);
cx18_av_write4(cx, 0x904, 0x08014faa); cx18_av_write4(cx, 0x904, 0x08014faa);
cx18_av_write4(cx, 0x90c, 0x08014faa); cx18_av_write4(cx, 0x90c, 0x08014faa);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, 0x127, 0x56);
/* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11205fff); cx18_av_write4(cx, 0x12c, 0x11205fff);
...@@ -117,12 +177,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -117,12 +177,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
} else { } else {
switch (freq) { switch (freq) {
case 32000: case 32000:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x1e08040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
*/
cx18_av_write4(cx, 0x108, 0x300d040f);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL_FRAC */ /* AUX_PLL Fraction = 0x176740c */
/* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */ /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x012a0863); cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */ /* src1_ctl */
/* 0x1.0000 = 32000/32000 */ /* 0x1.0000 = 32000/32000 */
...@@ -134,8 +201,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -134,8 +201,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08020000); cx18_av_write4(cx, 0x904, 0x08020000);
cx18_av_write4(cx, 0x90c, 0x08020000); cx18_av_write4(cx, 0x90c, 0x08020000);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
cx18_av_write(cx, 0x127, 0x54); cx18_av_write(cx, 0x127, 0x70);
/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11201fff); cx18_av_write4(cx, 0x12c, 0x11201fff);
...@@ -149,12 +216,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -149,12 +216,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break; break;
case 44100: case 44100:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x1809040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
*/
cx18_av_write4(cx, 0x108, 0x240e040f);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL_FRAC */ /* AUX_PLL Fraction = 0x062a1f2 */
/* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */ /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x00ec6bce); cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src1_ctl */ /* src1_ctl */
/* 0x1.60cd = 44100/32000 */ /* 0x1.60cd = 44100/32000 */
...@@ -166,6 +240,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -166,6 +240,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08017385); cx18_av_write4(cx, 0x904, 0x08017385);
cx18_av_write4(cx, 0x90c, 0x08017385); cx18_av_write4(cx, 0x90c, 0x08017385);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
cx18_av_write(cx, 0x127, 0x64);
/* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x112061ff); cx18_av_write4(cx, 0x12c, 0x112061ff);
...@@ -178,12 +255,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -178,12 +255,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break; break;
case 48000: case 48000:
/* VID_PLL and AUX_PLL */ /*
cx18_av_write4(cx, 0x108, 0x180a040f); * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
* AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
*/
cx18_av_write4(cx, 0x108, 0x200d040f);
/* AUX_PLL_FRAC */ /* VID_PLL Fraction = 0x2be2fe */
/* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
cx18_av_write4(cx, 0x110, 0x0098d6dd); cx18_av_write4(cx, 0x10c, 0x002be2fe);
/* AUX_PLL Fraction = 0x176740c */
/* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */ /* src1_ctl */
/* 0x1.8000 = 48000/32000 */ /* 0x1.8000 = 48000/32000 */
...@@ -195,6 +279,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) ...@@ -195,6 +279,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08015555); cx18_av_write4(cx, 0x904, 0x08015555);
cx18_av_write4(cx, 0x90c, 0x08015555); cx18_av_write4(cx, 0x90c, 0x08015555);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
cx18_av_write(cx, 0x127, 0x60);
/* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11203fff); cx18_av_write4(cx, 0x12c, 0x11203fff);
......
...@@ -271,7 +271,7 @@ void cx18_av_std_setup(struct cx18 *cx) ...@@ -271,7 +271,7 @@ void cx18_av_std_setup(struct cx18 *cx)
if (pll_post) { if (pll_post) {
int fin, fsc, pll; int fin, fsc, pll;
pll = (28636364L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
pll /= pll_post; pll /= pll_post;
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000); pll / 1000000, pll % 1000000);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "cx18-irq.h" #include "cx18-irq.h"
#include "cx18-firmware.h" #include "cx18-firmware.h"
#include "cx18-cards.h" #include "cx18-cards.h"
#include "cx18-av-core.h"
#include <linux/firmware.h> #include <linux/firmware.h>
#define CX18_PROC_SOFT_RESET 0xc70010 #define CX18_PROC_SOFT_RESET 0xc70010
...@@ -224,7 +225,45 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) ...@@ -224,7 +225,45 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
0x00000000, 0x00020002); 0x00000000, 0x00020002);
/* The fast clock is at 200/245 MHz */ /*
* The PLL parameters are based on the external crystal frequency that
* would ideally be:
*
* NTSC Color subcarrier freq * 8 =
* 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
*
* The accidents of history and rationale that explain from where this
* combination of magic numbers originate can be found in:
*
* [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
* the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
*
* [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
* NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
*
* As Mike Bradley has rightly pointed out, it's not the exact crystal
* frequency that matters, only that all parts of the driver and
* firmware are using the same value (close to the ideal value).
*
* Since I have a strong suspicion that, if the firmware ever assumes a
* crystal value at all, it will assume 28.636360 MHz, the crystal
* freq used in calculations in this driver will be:
*
* xtal_freq = 28.636360 MHz
*
* an error of less than 0.13 ppm which is way, way better than any off
* the shelf crystal will have for accuracy anyway.
*
* Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
*
* Many thanks to Jeff Campbell and Mike Bradley for their extensive
* investigation, experimentation, testing, and suggested solutions of
* of audio/video sync problems with SVideo and CVBS captures.
*/
/* the fast clock is at 200/245 MHz */
/* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
/* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7, cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
CX18_FAST_CLOCK_PLL_FRAC); CX18_FAST_CLOCK_PLL_FRAC);
...@@ -234,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) ...@@ -234,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
/* set slow clock to 125/120 MHz */ /* set slow clock to 125/120 MHz */
cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT); /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8, /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
CX18_SLOW_CLOCK_PLL_FRAC); CX18_SLOW_CLOCK_PLL_FRAC);
cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST); cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
/* mpeg clock pll 54MHz */ /* mpeg clock pll 54MHz */
/* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC); cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
/*
* VDCLK Integer = 0x0f, Post Divider = 0x04
* AIMCLK Integer = 0x0e, Post Divider = 0x16
*/
cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
/* VDCLK Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
/* AIMCLK Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
/* Defaults */ /* Defaults */
/* APU = SC or SC/2 = 125/62.5 */ /* APU = SC or SC/2 = 125/62.5 */
/* EPU = SC = 125 */ /* EPU = SC = 125 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment