Commit | Line | Data |
---|---|---|
df34403d VB |
1 | /* |
2 | * Copyright (C) 1995 Linus Torvalds | |
3 | * Adapted from 'alpha' version by Gary Thomas | |
4 | * Modified by Cort Dougan (cort@cs.nmt.edu) | |
5 | * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net) | |
6 | * Further modified for generic 8xx by Dan. | |
7 | */ | |
8 | ||
9 | /* | |
10 | * bootup setup stuff.. | |
11 | */ | |
12 | ||
df34403d | 13 | #include <linux/kernel.h> |
df34403d | 14 | #include <linux/interrupt.h> |
df34403d | 15 | #include <linux/init.h> |
df34403d VB |
16 | #include <linux/time.h> |
17 | #include <linux/rtc.h> | |
02753cb6 | 18 | #include <linux/fsl_devices.h> |
df34403d | 19 | |
df34403d | 20 | #include <asm/io.h> |
df34403d | 21 | #include <asm/8xx_immap.h> |
df34403d VB |
22 | #include <asm/prom.h> |
23 | #include <asm/fs_pd.h> | |
24 | #include <mm/mmu_decl.h> | |
25 | ||
fb533d0c | 26 | #include <sysdev/mpc8xx_pic.h> |
49b51545 JF |
27 | |
28 | #include "mpc8xx.h" | |
80128ff7 | 29 | |
df34403d VB |
30 | extern int cpm_pic_init(void); |
31 | extern int cpm_get_irq(void); | |
32 | ||
33 | /* A place holder for time base interrupts, if they are ever enabled. */ | |
fb533d0c | 34 | static irqreturn_t timebase_interrupt(int irq, void *dev) |
df34403d VB |
35 | { |
36 | printk ("timebase_interrupt()\n"); | |
37 | ||
38 | return IRQ_HANDLED; | |
39 | } | |
40 | ||
41 | static struct irqaction tbint_irqaction = { | |
42 | .handler = timebase_interrupt, | |
e8003404 | 43 | .flags = IRQF_NO_THREAD, |
df34403d VB |
44 | .name = "tbint", |
45 | }; | |
46 | ||
47 | /* per-board overridable init_internal_rtc() function. */ | |
48 | void __init __attribute__ ((weak)) | |
49 | init_internal_rtc(void) | |
50 | { | |
fb533d0c | 51 | sit8xx_t __iomem *sys_tmr = immr_map(im_sit); |
df34403d VB |
52 | |
53 | /* Disable the RTC one second and alarm interrupts. */ | |
54 | clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); | |
55 | ||
56 | /* Enable the RTC */ | |
57 | setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE)); | |
58 | immr_unmap(sys_tmr); | |
59 | } | |
60 | ||
61 | static int __init get_freq(char *name, unsigned long *val) | |
62 | { | |
4b218e9b SW |
63 | struct device_node *cpu; |
64 | const unsigned int *fp; | |
65 | int found = 0; | |
df34403d | 66 | |
4b218e9b SW |
67 | /* The cpu node should have timebase and clock frequency properties */ |
68 | cpu = of_find_node_by_type(NULL, "cpu"); | |
df34403d | 69 | |
4b218e9b SW |
70 | if (cpu) { |
71 | fp = of_get_property(cpu, name, NULL); | |
72 | if (fp) { | |
73 | found = 1; | |
74 | *val = *fp; | |
75 | } | |
df34403d | 76 | |
4b218e9b SW |
77 | of_node_put(cpu); |
78 | } | |
df34403d | 79 | |
4b218e9b | 80 | return found; |
df34403d VB |
81 | } |
82 | ||
83 | /* The decrementer counts at the system (internal) clock frequency divided by | |
84 | * sixteen, or external oscillator divided by four. We force the processor | |
85 | * to use system clock divided by sixteen. | |
86 | */ | |
87 | void __init mpc8xx_calibrate_decr(void) | |
88 | { | |
89 | struct device_node *cpu; | |
fb533d0c SW |
90 | cark8xx_t __iomem *clk_r1; |
91 | car8xx_t __iomem *clk_r2; | |
92 | sitk8xx_t __iomem *sys_tmr1; | |
93 | sit8xx_t __iomem *sys_tmr2; | |
df34403d VB |
94 | int irq, virq; |
95 | ||
fb533d0c | 96 | clk_r1 = immr_map(im_clkrstk); |
df34403d VB |
97 | |
98 | /* Unlock the SCCR. */ | |
99 | out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); | |
100 | out_be32(&clk_r1->cark_sccrk, KAPWR_KEY); | |
101 | immr_unmap(clk_r1); | |
102 | ||
103 | /* Force all 8xx processors to use divide by 16 processor clock. */ | |
fb533d0c | 104 | clk_r2 = immr_map(im_clkrst); |
df34403d VB |
105 | setbits32(&clk_r2->car_sccr, 0x02000000); |
106 | immr_unmap(clk_r2); | |
107 | ||
108 | /* Processor frequency is MHz. | |
109 | */ | |
4b218e9b SW |
110 | ppc_proc_freq = 50000000; |
111 | if (!get_freq("clock-frequency", &ppc_proc_freq)) | |
df3c9019 | 112 | printk(KERN_ERR "WARNING: Estimating processor frequency " |
4b218e9b SW |
113 | "(not found)\n"); |
114 | ||
50530378 | 115 | ppc_tb_freq = ppc_proc_freq / 16; |
4b218e9b | 116 | printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); |
df34403d VB |
117 | |
118 | /* Perform some more timer/timebase initialization. This used | |
119 | * to be done elsewhere, but other changes caused it to get | |
120 | * called more than once....that is a bad thing. | |
121 | * | |
122 | * First, unlock all of the registers we are going to modify. | |
123 | * To protect them from corruption during power down, registers | |
124 | * that are maintained by keep alive power are "locked". To | |
125 | * modify these registers we have to write the key value to | |
126 | * the key location associated with the register. | |
127 | * Some boards power up with these unlocked, while others | |
128 | * are locked. Writing anything (including the unlock code?) | |
129 | * to the unlocked registers will lock them again. So, here | |
130 | * we guarantee the registers are locked, then we unlock them | |
131 | * for our use. | |
132 | */ | |
fb533d0c | 133 | sys_tmr1 = immr_map(im_sitk); |
df34403d VB |
134 | out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); |
135 | out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); | |
136 | out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); | |
137 | out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY); | |
138 | out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY); | |
139 | out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY); | |
140 | immr_unmap(sys_tmr1); | |
141 | ||
142 | init_internal_rtc(); | |
143 | ||
144 | /* Enabling the decrementer also enables the timebase interrupts | |
145 | * (or from the other point of view, to get decrementer interrupts | |
146 | * we have to enable the timebase). The decrementer interrupt | |
147 | * is wired into the vector table, nothing to do here for that. | |
148 | */ | |
4b218e9b SW |
149 | cpu = of_find_node_by_type(NULL, "cpu"); |
150 | virq= irq_of_parse_and_map(cpu, 0); | |
476eb491 | 151 | irq = virq_to_hw(virq); |
df34403d | 152 | |
fb533d0c | 153 | sys_tmr2 = immr_map(im_sit); |
df34403d VB |
154 | out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | |
155 | (TBSCR_TBF | TBSCR_TBE)); | |
156 | immr_unmap(sys_tmr2); | |
157 | ||
158 | if (setup_irq(virq, &tbint_irqaction)) | |
159 | panic("Could not allocate timer IRQ!"); | |
df34403d VB |
160 | } |
161 | ||
162 | /* The RTC on the MPC8xx is an internal register. | |
163 | * We want to protect this during power down, so we need to unlock, | |
164 | * modify, and re-lock. | |
165 | */ | |
166 | ||
167 | int mpc8xx_set_rtc_time(struct rtc_time *tm) | |
168 | { | |
fb533d0c SW |
169 | sitk8xx_t __iomem *sys_tmr1; |
170 | sit8xx_t __iomem *sys_tmr2; | |
df34403d VB |
171 | int time; |
172 | ||
fb533d0c SW |
173 | sys_tmr1 = immr_map(im_sitk); |
174 | sys_tmr2 = immr_map(im_sit); | |
df34403d | 175 | time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, |
4b218e9b | 176 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
df34403d VB |
177 | |
178 | out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY); | |
179 | out_be32(&sys_tmr2->sit_rtc, time); | |
180 | out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY); | |
181 | ||
182 | immr_unmap(sys_tmr2); | |
183 | immr_unmap(sys_tmr1); | |
184 | return 0; | |
185 | } | |
186 | ||
187 | void mpc8xx_get_rtc_time(struct rtc_time *tm) | |
188 | { | |
189 | unsigned long data; | |
fb533d0c | 190 | sit8xx_t __iomem *sys_tmr = immr_map(im_sit); |
df34403d VB |
191 | |
192 | /* Get time from the RTC. */ | |
193 | data = in_be32(&sys_tmr->sit_rtc); | |
194 | to_tm(data, tm); | |
4b218e9b SW |
195 | tm->tm_year -= 1900; |
196 | tm->tm_mon -= 1; | |
df34403d VB |
197 | immr_unmap(sys_tmr); |
198 | return; | |
199 | } | |
200 | ||
201 | void mpc8xx_restart(char *cmd) | |
202 | { | |
fb533d0c | 203 | car8xx_t __iomem *clk_r = immr_map(im_clkrst); |
df34403d VB |
204 | |
205 | ||
206 | local_irq_disable(); | |
207 | ||
208 | setbits32(&clk_r->car_plprcr, 0x00000080); | |
209 | /* Clear the ME bit in MSR to cause checkstop on machine check | |
210 | */ | |
211 | mtmsr(mfmsr() & ~0x1000); | |
212 | ||
fb533d0c SW |
213 | in_8(&clk_r->res[0]); |
214 | panic("Restart failed\n"); | |
df34403d VB |
215 | } |
216 | ||
217 | static void cpm_cascade(unsigned int irq, struct irq_desc *desc) | |
218 | { | |
7601f597 LC |
219 | struct irq_chip *chip = irq_desc_get_chip(desc); |
220 | int cascade_irq = cpm_get_irq(); | |
df34403d | 221 | |
7601f597 | 222 | if (cascade_irq >= 0) |
df34403d | 223 | generic_handle_irq(cascade_irq); |
cfe4a109 | 224 | |
cfe4a109 | 225 | chip->irq_eoi(&desc->irq_data); |
df34403d VB |
226 | } |
227 | ||
d0a02a06 | 228 | /* Initialize the internal interrupt controllers. The number of |
df34403d VB |
229 | * interrupts supported can vary with the processor type, and the |
230 | * 82xx family can have up to 64. | |
231 | * External interrupts can be either edge or level triggered, and | |
232 | * need to be initialized by the appropriate driver. | |
233 | */ | |
d0a02a06 | 234 | void __init mpc8xx_pics_init(void) |
df34403d VB |
235 | { |
236 | int irq; | |
237 | ||
238 | if (mpc8xx_pic_init()) { | |
4b218e9b | 239 | printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); |
df34403d VB |
240 | return; |
241 | } | |
242 | ||
243 | irq = cpm_pic_init(); | |
244 | if (irq != NO_IRQ) | |
ec775d0e | 245 | irq_set_chained_handler(irq, cpm_cascade); |
df34403d | 246 | } |