Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 124435
b: refs/heads/master
c: 55d81aa
h: refs/heads/master
i:
  124433: 3c4cc90
  124431: f5ab647
v: v3
  • Loading branch information
Andy Walls authored and Mauro Carvalho Chehab committed Dec 30, 2008
1 parent b7e08a6 commit a5ffb18
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 46 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 57e24b629a5282bee24aaff44977270a3e462041
refs/heads/master: 55d81aa5c11f9da510a72cc48fd59689b3e91e3a
165 changes: 126 additions & 39 deletions trunk/drivers/media/video/cx18/cx18-av-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,67 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000)
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) {
switch (freq) {
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 */
/* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
cx18_av_write4(cx, 0x110, 0x012a0863);
/* AUX_PLL Fraction = 0x176740c */
/* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x0176740c);

/* 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, 0x904, 0x0801f77f);
cx18_av_write4(cx, 0x90c, 0x0801f77f);

/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
cx18_av_write(cx, 0x127, 0x54);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
cx18_av_write(cx, 0x127, 0x60);

/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11202fff);
Expand All @@ -65,19 +105,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break;

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 */
/* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
cx18_av_write4(cx, 0x110, 0x00ec6bce);
/* AUX_PLL Fraction = 0x062a1f2 */
/* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x0062a1f2);

/* 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, 0x904, 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 */
cx18_av_write4(cx, 0x12c, 0x112092ff);

Expand All @@ -90,19 +140,29 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break;

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 */
/* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
cx18_av_write4(cx, 0x110, 0x0098d6dd);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
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 */
/* 0x1.4faa = (4 * 15734.26) / 48000 */
/* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
cx18_av_write4(cx, 0x900, 0x08014faa);
cx18_av_write4(cx, 0x904, 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 */
cx18_av_write4(cx, 0x12c, 0x11205fff);

Expand All @@ -117,12 +177,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
} else {
switch (freq) {
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 */
/* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
cx18_av_write4(cx, 0x110, 0x012a0863);
/* AUX_PLL Fraction = 0x176740c */
/* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x0176740c);

/* src1_ctl */
/* 0x1.0000 = 32000/32000 */
Expand All @@ -134,8 +201,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08020000);
cx18_av_write4(cx, 0x90c, 0x08020000);

/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
cx18_av_write(cx, 0x127, 0x54);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
cx18_av_write(cx, 0x127, 0x70);

/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11201fff);
Expand All @@ -149,12 +216,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break;

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 */
/* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
cx18_av_write4(cx, 0x110, 0x00ec6bce);
/* AUX_PLL Fraction = 0x062a1f2 */
/* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
cx18_av_write4(cx, 0x110, 0x0062a1f2);

/* src1_ctl */
/* 0x1.60cd = 44100/32000 */
Expand All @@ -166,6 +240,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 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 */
cx18_av_write4(cx, 0x12c, 0x112061ff);

Expand All @@ -178,12 +255,19 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
break;

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 */
/* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
cx18_av_write4(cx, 0x110, 0x0098d6dd);
/* VID_PLL Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
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 */
/* 0x1.8000 = 48000/32000 */
Expand All @@ -195,6 +279,9 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 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 */
cx18_av_write4(cx, 0x12c, 0x11203fff);

Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/media/video/cx18/cx18-av-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ void cx18_av_std_setup(struct cx18 *cx)
if (pll_post) {
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;
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
Expand Down
69 changes: 64 additions & 5 deletions trunk/drivers/media/video/cx18/cx18-firmware.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "cx18-irq.h"
#include "cx18-firmware.h"
#include "cx18-cards.h"
#include "cx18-av-core.h"
#include <linux/firmware.h>

#define CX18_PROC_SOFT_RESET 0xc70010
Expand Down Expand Up @@ -224,7 +225,45 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
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 ? 0x1EFBF37 : 0x038E3D7,
CX18_FAST_CLOCK_PLL_FRAC);
Expand All @@ -234,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);

/* set slow clock to 125/120 MHz */
cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
/* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
/* 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_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);

/* 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, 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);

/*
* 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 */
/* APU = SC or SC/2 = 125/62.5 */
/* EPU = SC = 125 */
Expand Down

0 comments on commit a5ffb18

Please sign in to comment.