aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2013-09-12 07:01:53 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-09-13 05:56:13 -0400
commitdaed1285c33582d93447a0ad971bbc1dd15d1940 (patch)
treeec0f2c412b01cf6944b7f1b448c5a2b8d6827094
parent5a7d8a28080caed7fd4cb1b81d092adac4445e8e (diff)
MIPS: DECstation HRT initialization rearrangement
Not all I/O ASIC versions have the free-running counter implemented, an early revision used in the 5000/1xx models aka 3MIN and 4MIN did not have it. Therefore we cannot unconditionally use it as a clock source. Fortunately if not implemented its register slot has a fixed value so it is enough if we check for the value at the end of the calibration period being the same as at the beginning. This also means we need to look for another high-precision clock source on the systems affected. The 5000/1xx can have an R4000SC processor installed where the CP0 Count register can be used as a clock source. Unfortunately all the R4k DECstations suffer from the missed timer interrupt on CP0 Count reads erratum, so we cannot use the CP0 timer as a clock source and a clock event both at a time. However we never need an R4k clock event device because all DECstations have a DS1287A RTC chip whose periodic interrupt can be used as a clock source. This gives us the following four configuration possibilities for I/O ASIC DECstations: 1. No I/O ASIC counter and no CP0 timer, e.g. R3k 5000/1xx (3MIN). 2. No I/O ASIC counter but the CP0 timer, i.e. R4k 5000/150 (4MIN). 3. The I/O ASIC counter but no CP0 timer, e.g. R3k 5000/240 (3MAX+). 4. The I/O ASIC counter and the CP0 timer, e.g. R4k 5000/260 (4MAX+). For #1 and #2 this change stops the I/O ASIC free-running counter from being installed as a clock source of a 0Hz frequency. For #2 it also arranges for the CP0 timer to be used as a clock source rather than a clock event device, because having an accurate wall clock is more important than a high-precision interval timer. For #3 there is no change. For #4 the change makes the I/O ASIC free-running counter installed as a clock source so that the CP0 timer can be used as a clock event device. Unfortunately the use of the CP0 timer as a clock event device relies on a succesful completion of c0_compare_interrupt. That never happens, because while waiting for a CP0 Compare interrupt to happen the function spins in a loop reading the CP0 Count register. This makes the CP0 Count erratum trigger reliably causing the interrupt waited for to be lost in all cases. As a result #4 resorts to using the CP0 timer as a clock source as well, just as #2. However we want to keep this separate arrangement in case (hope) c0_compare_interrupt is eventually rewritten such that it avoids the erratum. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5825/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/dec/time.c22
-rw-r--r--arch/mips/include/asm/dec/ioasic.h2
-rw-r--r--arch/mips/kernel/csrc-ioasic.c8
3 files changed, 27 insertions, 5 deletions
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 56ebc7f2bede..1914e56f0d96 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -125,12 +125,16 @@ int rtc_mips_set_mmss(unsigned long nowtime)
125 125
126void __init plat_time_init(void) 126void __init plat_time_init(void)
127{ 127{
128 int ioasic_clock = 0;
128 u32 start, end; 129 u32 start, end;
129 int i = HZ / 8; 130 int i = HZ / 8;
130 131
131 /* Set up the rate of periodic DS1287 interrupts. */ 132 /* Set up the rate of periodic DS1287 interrupts. */
132 ds1287_set_base_clock(HZ); 133 ds1287_set_base_clock(HZ);
133 134
135 /* On some I/O ASIC systems we have the I/O ASIC's counter. */
136 if (IOASIC)
137 ioasic_clock = dec_ioasic_clocksource_init() == 0;
134 if (cpu_has_counter) { 138 if (cpu_has_counter) {
135 ds1287_timer_state(); 139 ds1287_timer_state();
136 while (!ds1287_timer_state()) 140 while (!ds1287_timer_state())
@@ -147,9 +151,21 @@ void __init plat_time_init(void)
147 mips_hpt_frequency = (end - start) * 8; 151 mips_hpt_frequency = (end - start) * 8;
148 printk(KERN_INFO "MIPS counter frequency %dHz\n", 152 printk(KERN_INFO "MIPS counter frequency %dHz\n",
149 mips_hpt_frequency); 153 mips_hpt_frequency);
150 } else if (IOASIC) 154
151 /* For pre-R4k systems we use the I/O ASIC's counter. */ 155 /*
152 dec_ioasic_clocksource_init(); 156 * All R4k DECstations suffer from the CP0 Count erratum,
157 * so we can't use the timer as a clock source, and a clock
158 * event both at a time. An accurate wall clock is more
159 * important than a high-precision interval timer so only
160 * use the timer as a clock source, and not a clock event
161 * if there's no I/O ASIC counter available to serve as a
162 * clock source.
163 */
164 if (!ioasic_clock) {
165 init_r4k_clocksource();
166 mips_hpt_frequency = 0;
167 }
168 }
153 169
154 ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); 170 ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
155} 171}
diff --git a/arch/mips/include/asm/dec/ioasic.h b/arch/mips/include/asm/dec/ioasic.h
index 98badd6bf22d..be4d62a5a10e 100644
--- a/arch/mips/include/asm/dec/ioasic.h
+++ b/arch/mips/include/asm/dec/ioasic.h
@@ -33,6 +33,6 @@ static inline u32 ioasic_read(unsigned int reg)
33 33
34extern void init_ioasic_irqs(int base); 34extern void init_ioasic_irqs(int base);
35 35
36extern void dec_ioasic_clocksource_init(void); 36extern int dec_ioasic_clocksource_init(void);
37 37
38#endif /* __ASM_DEC_IOASIC_H */ 38#endif /* __ASM_DEC_IOASIC_H */
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c
index 87e88feb4a25..6cbbf6e106b9 100644
--- a/arch/mips/kernel/csrc-ioasic.c
+++ b/arch/mips/kernel/csrc-ioasic.c
@@ -37,7 +37,7 @@ static struct clocksource clocksource_dec = {
37 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 37 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
38}; 38};
39 39
40void __init dec_ioasic_clocksource_init(void) 40int __init dec_ioasic_clocksource_init(void)
41{ 41{
42 unsigned int freq; 42 unsigned int freq;
43 u32 start, end; 43 u32 start, end;
@@ -56,8 +56,14 @@ void __init dec_ioasic_clocksource_init(void)
56 end = dec_ioasic_hpt_read(&clocksource_dec); 56 end = dec_ioasic_hpt_read(&clocksource_dec);
57 57
58 freq = (end - start) * 8; 58 freq = (end - start) * 8;
59
60 /* An early revision of the I/O ASIC didn't have the counter. */
61 if (!freq)
62 return -ENXIO;
63
59 printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); 64 printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
60 65
61 clocksource_dec.rating = 200 + freq / 10000000; 66 clocksource_dec.rating = 200 + freq / 10000000;
62 clocksource_register_hz(&clocksource_dec, freq); 67 clocksource_register_hz(&clocksource_dec, freq);
68 return 0;
63} 69}