提交 758e285f 编写于 作者: S Sergei Shtylyov 提交者: Ralf Baechle

[MIPS] Alchemy: work around clock misdetection on early Au1000

Work around the CPU clock miscalculation on Au1000DA/HA/HB due the
sys_cpupll register being write-only, i.e. actually do what the comment
before cal_r4off() function advertised for years but the code failed at.
This is achieved by just giving user a chance to define the clock
explicitly  in the board config. via CONFIG_SOC_AU1000_FREQUENCY option,
defaulting to 396 MHz if the option is not given...

The patch is based on the AMD's big unpublished patch, the issue seems to
be an undocumented errata (or feature :-)...
Signed-off-by: NSergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: NRalf Baechle <ralf@linux-mips.org>
上级 b1ec4c8e
...@@ -22,24 +22,24 @@ struct cpu_spec* cur_cpu_spec[NR_CPUS]; ...@@ -22,24 +22,24 @@ struct cpu_spec* cur_cpu_spec[NR_CPUS];
/* With some thought, we can probably use the mask to reduce the /* With some thought, we can probably use the mask to reduce the
* size of the table. * size of the table.
*/ */
struct cpu_spec cpu_specs[] = { struct cpu_spec cpu_specs[] = {
{ 0xffffffff, 0x00030100, "Au1000 DA", 1, 0 }, { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0, 1 },
{ 0xffffffff, 0x00030201, "Au1000 HA", 1, 0 }, { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0, 1 },
{ 0xffffffff, 0x00030202, "Au1000 HB", 1, 0 }, { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0, 1 },
{ 0xffffffff, 0x00030203, "Au1000 HC", 1, 1 }, { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1, 0 },
{ 0xffffffff, 0x00030204, "Au1000 HD", 1, 1 }, { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1, 0 },
{ 0xffffffff, 0x01030200, "Au1500 AB", 1, 1 }, { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1, 0 },
{ 0xffffffff, 0x01030201, "Au1500 AC", 0, 1 }, { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1, 0 },
{ 0xffffffff, 0x01030202, "Au1500 AD", 0, 1 }, { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1, 0 },
{ 0xffffffff, 0x02030200, "Au1100 AB", 1, 1 }, { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1, 0 },
{ 0xffffffff, 0x02030201, "Au1100 BA", 1, 1 }, { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1, 0 },
{ 0xffffffff, 0x02030202, "Au1100 BC", 1, 1 }, { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1, 0 },
{ 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 }, { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1, 0 },
{ 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 }, { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1, 0 },
{ 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 }, { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1, 0 },
{ 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 }, { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0, 0 },
{ 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 }, { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0, 0 },
{ 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 }, { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0, 0 }
}; };
void void
......
...@@ -57,7 +57,7 @@ void __init plat_mem_setup(void) ...@@ -57,7 +57,7 @@ void __init plat_mem_setup(void)
{ {
struct cpu_spec *sp; struct cpu_spec *sp;
char *argptr; char *argptr;
unsigned long prid, cpupll, bclk = 1; unsigned long prid, cpufreq, bclk = 1;
set_cpuspec(); set_cpuspec();
sp = cur_cpu_spec[0]; sp = cur_cpu_spec[0];
...@@ -65,8 +65,15 @@ void __init plat_mem_setup(void) ...@@ -65,8 +65,15 @@ void __init plat_mem_setup(void)
board_setup(); /* board specific setup */ board_setup(); /* board specific setup */
prid = read_c0_prid(); prid = read_c0_prid();
cpupll = (au_readl(0xB1900060) & 0x3F) * 12; if (sp->cpu_pll_wo)
printk("(PRId %08lx) @ %ldMHZ\n", prid, cpupll); #ifdef CONFIG_SOC_AU1000_FREQUENCY
cpufreq = CONFIG_SOC_AU1000_FREQUENCY / 1000000;
#else
cpufreq = 396;
#endif
else
cpufreq = (au_readl(SYS_CPUPLL) & 0x3F) * 12;
printk(KERN_INFO "(PRID %08lx) @ %ld MHz\n", prid, cpufreq);
bclk = sp->cpu_bclk; bclk = sp->cpu_bclk;
if (bclk) if (bclk)
......
...@@ -209,18 +209,22 @@ unsigned long cal_r4koff(void) ...@@ -209,18 +209,22 @@ unsigned long cal_r4koff(void)
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
au_writel(0, SYS_TOYWRITE); au_writel(0, SYS_TOYWRITE);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
} else
no_au1xxx_32khz = 1;
cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * /*
AU1000_SRC_CLK; * On early Au1000, sys_cpupll was write-only. Since these
} * silicon versions of Au1000 are not sold by AMD, we don't bend
else { * over backwards trying to determine the frequency.
/* The 32KHz oscillator isn't running, so assume there */
* isn't one and grab the processor speed from the PLL. if (cur_cpu_spec[0]->cpu_pll_wo)
* NOTE: some old silicon doesn't allow reading the PLL. #ifdef CONFIG_SOC_AU1000_FREQUENCY
*/ cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
#else
cpu_speed = 396000000;
#endif
else
cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
no_au1xxx_32khz = 1;
}
mips_hpt_frequency = cpu_speed; mips_hpt_frequency = cpu_speed;
// Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16)
set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
......
...@@ -1786,6 +1786,7 @@ struct cpu_spec { ...@@ -1786,6 +1786,7 @@ struct cpu_spec {
char *cpu_name; char *cpu_name;
unsigned char cpu_od; /* Set Config[OD] */ unsigned char cpu_od; /* Set Config[OD] */
unsigned char cpu_bclk; /* Enable BCLK switching */ unsigned char cpu_bclk; /* Enable BCLK switching */
unsigned char cpu_pll_wo; /* sys_cpupll reg. write-only */
}; };
extern struct cpu_spec cpu_specs[]; extern struct cpu_spec cpu_specs[];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册