Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
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 | ||
13 | #include <linux/config.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/sched.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/mm.h> | |
18 | #include <linux/stddef.h> | |
19 | #include <linux/unistd.h> | |
20 | #include <linux/ptrace.h> | |
21 | #include <linux/slab.h> | |
22 | #include <linux/user.h> | |
23 | #include <linux/a.out.h> | |
24 | #include <linux/tty.h> | |
25 | #include <linux/major.h> | |
26 | #include <linux/interrupt.h> | |
27 | #include <linux/reboot.h> | |
28 | #include <linux/init.h> | |
29 | #include <linux/initrd.h> | |
30 | #include <linux/ioport.h> | |
31 | #include <linux/bootmem.h> | |
32 | #include <linux/seq_file.h> | |
33 | #include <linux/root_dev.h> | |
34 | ||
076d022c VB |
35 | #if defined(CONFIG_MTD) && defined(CONFIG_MTD_PHYSMAP) |
36 | #include <linux/mtd/partitions.h> | |
37 | #include <linux/mtd/physmap.h> | |
38 | #include <linux/mtd/mtd.h> | |
39 | #include <linux/mtd/map.h> | |
40 | #endif | |
41 | ||
1da177e4 LT |
42 | #include <asm/mmu.h> |
43 | #include <asm/reg.h> | |
44 | #include <asm/residual.h> | |
45 | #include <asm/io.h> | |
46 | #include <asm/pgtable.h> | |
47 | #include <asm/mpc8xx.h> | |
48 | #include <asm/8xx_immap.h> | |
49 | #include <asm/machdep.h> | |
50 | #include <asm/bootinfo.h> | |
51 | #include <asm/time.h> | |
52 | #include <asm/xmon.h> | |
457e04ca | 53 | #include <asm/ppc_sys.h> |
1da177e4 LT |
54 | |
55 | #include "ppc8xx_pic.h" | |
56 | ||
076d022c VB |
57 | #ifdef CONFIG_MTD_PHYSMAP |
58 | #define MPC8xxADS_BANK_WIDTH 4 | |
59 | #endif | |
60 | ||
61 | #define MPC8xxADS_U_BOOT_SIZE 0x80000 | |
62 | #define MPC8xxADS_FREE_AREA_OFFSET MPC8xxADS_U_BOOT_SIZE | |
63 | ||
64 | #if defined(CONFIG_MTD_PARTITIONS) | |
65 | /* | |
66 | NOTE: bank width and interleave relative to the installed flash | |
67 | should have been chosen within MTD_CFI_GEOMETRY options. | |
68 | */ | |
69 | static struct mtd_partition mpc8xxads_partitions[] = { | |
70 | { | |
71 | .name = "bootloader", | |
72 | .size = MPC8xxADS_U_BOOT_SIZE, | |
73 | .offset = 0, | |
74 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | |
75 | }, { | |
76 | .name = "User FS", | |
77 | .offset = MPC8xxADS_FREE_AREA_OFFSET | |
78 | } | |
79 | }; | |
80 | ||
81 | #define mpc8xxads_part_num (sizeof (mpc8xxads_partitions) / sizeof (mpc8xxads_partitions[0])) | |
82 | ||
83 | #endif | |
84 | ||
1da177e4 LT |
85 | static int m8xx_set_rtc_time(unsigned long time); |
86 | static unsigned long m8xx_get_rtc_time(void); | |
87 | void m8xx_calibrate_decr(void); | |
88 | ||
89 | unsigned char __res[sizeof(bd_t)]; | |
90 | ||
91 | extern void m8xx_ide_init(void); | |
92 | ||
93 | extern unsigned long find_available_memory(void); | |
62c592ed | 94 | extern void m8xx_cpm_reset(void); |
1da177e4 LT |
95 | extern void m8xx_wdt_handler_install(bd_t *bp); |
96 | extern void rpxfb_alloc_pages(void); | |
97 | extern void cpm_interrupt_init(void); | |
98 | ||
99 | void __attribute__ ((weak)) | |
100 | board_init(void) | |
101 | { | |
102 | } | |
103 | ||
104 | void __init | |
105 | m8xx_setup_arch(void) | |
106 | { | |
076d022c VB |
107 | #if defined(CONFIG_MTD) && defined(CONFIG_MTD_PHYSMAP) |
108 | bd_t *binfo = (bd_t *)__res; | |
109 | #endif | |
110 | ||
1da177e4 LT |
111 | /* Reset the Communication Processor Module. |
112 | */ | |
079da354 | 113 | m8xx_cpm_reset(); |
1da177e4 LT |
114 | |
115 | #ifdef CONFIG_FB_RPX | |
116 | rpxfb_alloc_pages(); | |
117 | #endif | |
118 | ||
119 | #ifdef notdef | |
120 | ROOT_DEV = Root_HDA1; /* hda1 */ | |
121 | #endif | |
122 | ||
123 | #ifdef CONFIG_BLK_DEV_INITRD | |
124 | #if 0 | |
125 | ROOT_DEV = Root_FD0; /* floppy */ | |
126 | rd_prompt = 1; | |
127 | rd_doload = 1; | |
128 | rd_image_start = 0; | |
129 | #endif | |
130 | #if 0 /* XXX this may need to be updated for the new bootmem stuff, | |
131 | or possibly just deleted (see set_phys_avail() in init.c). | |
132 | - paulus. */ | |
133 | /* initrd_start and size are setup by boot/head.S and kernel/head.S */ | |
134 | if ( initrd_start ) | |
135 | { | |
136 | if (initrd_end > *memory_end_p) | |
137 | { | |
138 | printk("initrd extends beyond end of memory " | |
139 | "(0x%08lx > 0x%08lx)\ndisabling initrd\n", | |
140 | initrd_end,*memory_end_p); | |
141 | initrd_start = 0; | |
142 | } | |
143 | } | |
144 | #endif | |
145 | #endif | |
076d022c VB |
146 | |
147 | #if defined (CONFIG_MPC86XADS) || defined (CONFIG_MPC885ADS) | |
148 | #if defined(CONFIG_MTD_PHYSMAP) | |
149 | physmap_configure(binfo->bi_flashstart, binfo->bi_flashsize, | |
150 | MPC8xxADS_BANK_WIDTH, NULL); | |
151 | #ifdef CONFIG_MTD_PARTITIONS | |
152 | physmap_set_partitions(mpc8xxads_partitions, mpc8xxads_part_num); | |
153 | #endif /* CONFIG_MTD_PARTITIONS */ | |
154 | #endif /* CONFIG_MTD_PHYSMAP */ | |
155 | #endif | |
156 | ||
1da177e4 LT |
157 | board_init(); |
158 | } | |
159 | ||
160 | void | |
161 | abort(void) | |
162 | { | |
163 | #ifdef CONFIG_XMON | |
164 | xmon(0); | |
165 | #endif | |
166 | machine_restart(NULL); | |
167 | ||
168 | /* not reached */ | |
169 | for (;;); | |
170 | } | |
171 | ||
172 | /* A place holder for time base interrupts, if they are ever enabled. */ | |
173 | irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs) | |
174 | { | |
175 | printk ("timebase_interrupt()\n"); | |
176 | ||
177 | return IRQ_HANDLED; | |
178 | } | |
179 | ||
180 | static struct irqaction tbint_irqaction = { | |
181 | .handler = timebase_interrupt, | |
182 | .mask = CPU_MASK_NONE, | |
183 | .name = "tbint", | |
184 | }; | |
185 | ||
fb64c244 MT |
186 | /* per-board overridable init_internal_rtc() function. */ |
187 | void __init __attribute__ ((weak)) | |
188 | init_internal_rtc(void) | |
189 | { | |
190 | /* Disable the RTC one second and alarm interrupts. */ | |
0ce928e1 VB |
191 | clrbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); |
192 | ||
fb64c244 | 193 | /* Enable the RTC */ |
0ce928e1 VB |
194 | setbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_RTF | RTCSC_RTE)); |
195 | ||
fb64c244 MT |
196 | } |
197 | ||
1da177e4 LT |
198 | /* The decrementer counts at the system (internal) clock frequency divided by |
199 | * sixteen, or external oscillator divided by four. We force the processor | |
200 | * to use system clock divided by sixteen. | |
201 | */ | |
202 | void __init m8xx_calibrate_decr(void) | |
203 | { | |
204 | bd_t *binfo = (bd_t *)__res; | |
205 | int freq, fp, divisor; | |
206 | ||
207 | /* Unlock the SCCR. */ | |
e37b0c96 MT |
208 | out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, ~KAPWR_KEY); |
209 | out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, KAPWR_KEY); | |
1da177e4 LT |
210 | |
211 | /* Force all 8xx processors to use divide by 16 processor clock. */ | |
0ce928e1 | 212 | setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr, 0x02000000); |
1da177e4 LT |
213 | /* Processor frequency is MHz. |
214 | * The value 'fp' is the number of decrementer ticks per second. | |
215 | */ | |
216 | fp = binfo->bi_intfreq / 16; | |
217 | freq = fp*60; /* try to make freq/1e6 an integer */ | |
218 | divisor = 60; | |
219 | printk("Decrementer Frequency = %d/%d\n", freq, divisor); | |
220 | tb_ticks_per_jiffy = freq / HZ / divisor; | |
221 | tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); | |
222 | ||
223 | /* Perform some more timer/timebase initialization. This used | |
224 | * to be done elsewhere, but other changes caused it to get | |
225 | * called more than once....that is a bad thing. | |
226 | * | |
227 | * First, unlock all of the registers we are going to modify. | |
228 | * To protect them from corruption during power down, registers | |
229 | * that are maintained by keep alive power are "locked". To | |
230 | * modify these registers we have to write the key value to | |
231 | * the key location associated with the register. | |
232 | * Some boards power up with these unlocked, while others | |
233 | * are locked. Writing anything (including the unlock code?) | |
234 | * to the unlocked registers will lock them again. So, here | |
235 | * we guarantee the registers are locked, then we unlock them | |
236 | * for our use. | |
237 | */ | |
e37b0c96 MT |
238 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk, ~KAPWR_KEY); |
239 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, ~KAPWR_KEY); | |
240 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, ~KAPWR_KEY); | |
241 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk, KAPWR_KEY); | |
242 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY); | |
243 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY); | |
1da177e4 | 244 | |
fb64c244 | 245 | init_internal_rtc(); |
1da177e4 LT |
246 | |
247 | /* Enabling the decrementer also enables the timebase interrupts | |
248 | * (or from the other point of view, to get decrementer interrupts | |
249 | * we have to enable the timebase). The decrementer interrupt | |
250 | * is wired into the vector table, nothing to do here for that. | |
251 | */ | |
e37b0c96 | 252 | out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr, (mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); |
1da177e4 LT |
253 | |
254 | if (setup_irq(DEC_INTERRUPT, &tbint_irqaction)) | |
255 | panic("Could not allocate timer IRQ!"); | |
256 | ||
257 | #ifdef CONFIG_8xx_WDT | |
258 | /* Install watchdog timer handler early because it might be | |
259 | * already enabled by the bootloader | |
260 | */ | |
261 | m8xx_wdt_handler_install(binfo); | |
262 | #endif | |
263 | } | |
264 | ||
265 | /* The RTC on the MPC8xx is an internal register. | |
266 | * We want to protect this during power down, so we need to unlock, | |
267 | * modify, and re-lock. | |
268 | */ | |
269 | static int | |
270 | m8xx_set_rtc_time(unsigned long time) | |
271 | { | |
e37b0c96 MT |
272 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck, KAPWR_KEY); |
273 | out_be32(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtc, time); | |
274 | out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck, ~KAPWR_KEY); | |
1da177e4 LT |
275 | return(0); |
276 | } | |
277 | ||
278 | static unsigned long | |
279 | m8xx_get_rtc_time(void) | |
280 | { | |
281 | /* Get time from the RTC. */ | |
e37b0c96 | 282 | return (unsigned long) in_be32(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtc); |
1da177e4 LT |
283 | } |
284 | ||
285 | static void | |
286 | m8xx_restart(char *cmd) | |
287 | { | |
288 | __volatile__ unsigned char dummy; | |
289 | ||
290 | local_irq_disable(); | |
1da177e4 | 291 | |
0ce928e1 | 292 | setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, 0x00000080); |
1da177e4 LT |
293 | /* Clear the ME bit in MSR to cause checkstop on machine check |
294 | */ | |
295 | mtmsr(mfmsr() & ~0x1000); | |
296 | ||
e37b0c96 | 297 | dummy = in_8(&((immap_t *)IMAP_ADDR)->im_clkrst.res[0]); |
1da177e4 LT |
298 | printk("Restart failed\n"); |
299 | while(1); | |
300 | } | |
301 | ||
302 | static void | |
303 | m8xx_power_off(void) | |
304 | { | |
305 | m8xx_restart(NULL); | |
306 | } | |
307 | ||
308 | static void | |
309 | m8xx_halt(void) | |
310 | { | |
311 | m8xx_restart(NULL); | |
312 | } | |
313 | ||
314 | ||
315 | static int | |
316 | m8xx_show_percpuinfo(struct seq_file *m, int i) | |
317 | { | |
318 | bd_t *bp; | |
319 | ||
320 | bp = (bd_t *)__res; | |
321 | ||
62c592ed MT |
322 | seq_printf(m, "clock\t\t: %uMHz\n" |
323 | "bus clock\t: %uMHz\n", | |
1da177e4 LT |
324 | bp->bi_intfreq / 1000000, |
325 | bp->bi_busfreq / 1000000); | |
326 | ||
327 | return 0; | |
328 | } | |
329 | ||
330 | #ifdef CONFIG_PCI | |
331 | static struct irqaction mbx_i8259_irqaction = { | |
332 | .handler = mbx_i8259_action, | |
333 | .mask = CPU_MASK_NONE, | |
334 | .name = "i8259 cascade", | |
335 | }; | |
336 | #endif | |
337 | ||
338 | /* Initialize the internal interrupt controller. The number of | |
339 | * interrupts supported can vary with the processor type, and the | |
340 | * 82xx family can have up to 64. | |
341 | * External interrupts can be either edge or level triggered, and | |
342 | * need to be initialized by the appropriate driver. | |
343 | */ | |
344 | static void __init | |
345 | m8xx_init_IRQ(void) | |
346 | { | |
347 | int i; | |
348 | ||
349 | for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++) | |
350 | irq_desc[i].handler = &ppc8xx_pic; | |
351 | ||
352 | cpm_interrupt_init(); | |
353 | ||
354 | #if defined(CONFIG_PCI) | |
355 | for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++) | |
356 | irq_desc[i].handler = &i8259_pic; | |
357 | ||
358 | i8259_pic_irq_offset = I8259_IRQ_OFFSET; | |
359 | i8259_init(0); | |
360 | ||
361 | /* The i8259 cascade interrupt must be level sensitive. */ | |
1da177e4 | 362 | |
0ce928e1 | 363 | clrbits32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, (0x80000000 >> ISA_BRIDGE_INT)); |
1da177e4 LT |
364 | if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction)) |
365 | enable_irq(ISA_BRIDGE_INT); | |
366 | #endif /* CONFIG_PCI */ | |
367 | } | |
368 | ||
369 | /* -------------------------------------------------------------------- */ | |
370 | ||
371 | /* | |
372 | * This is a big hack right now, but it may turn into something real | |
373 | * someday. | |
374 | * | |
375 | * For the 8xx boards (at this time anyway), there is nothing to initialize | |
376 | * associated the PROM. Rather than include all of the prom.c | |
377 | * functions in the image just to get prom_init, all we really need right | |
378 | * now is the initialization of the physical memory region. | |
379 | */ | |
380 | static unsigned long __init | |
381 | m8xx_find_end_of_memory(void) | |
382 | { | |
383 | bd_t *binfo; | |
384 | extern unsigned char __res[]; | |
385 | ||
386 | binfo = (bd_t *)__res; | |
387 | ||
388 | return binfo->bi_memsize; | |
389 | } | |
390 | ||
391 | /* | |
392 | * Now map in some of the I/O space that is generically needed | |
393 | * or shared with multiple devices. | |
394 | * All of this fits into the same 4Mbyte region, so it only | |
395 | * requires one page table page. (or at least it used to -- paulus) | |
396 | */ | |
397 | static void __init | |
398 | m8xx_map_io(void) | |
399 | { | |
400 | io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO); | |
401 | #ifdef CONFIG_MBX | |
402 | io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO); | |
403 | io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO); | |
404 | io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO); | |
405 | ||
406 | /* Map some of the PCI/ISA I/O space to get the IDE interface. | |
407 | */ | |
408 | io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO); | |
409 | io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO); | |
410 | #endif | |
411 | #if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) | |
412 | io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO); | |
413 | #if !defined(CONFIG_PCI) | |
414 | io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO); | |
415 | #endif | |
416 | #endif | |
417 | #if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX) | |
418 | io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO); | |
419 | #endif | |
420 | #ifdef CONFIG_FADS | |
421 | io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO); | |
422 | #endif | |
423 | #ifdef CONFIG_PCI | |
424 | io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO); | |
425 | #endif | |
426 | #if defined(CONFIG_NETTA) | |
427 | io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO); | |
428 | #endif | |
429 | } | |
430 | ||
431 | void __init | |
432 | platform_init(unsigned long r3, unsigned long r4, unsigned long r5, | |
433 | unsigned long r6, unsigned long r7) | |
434 | { | |
435 | parse_bootinfo(find_bootinfo()); | |
436 | ||
437 | if ( r3 ) | |
438 | memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); | |
439 | ||
440 | #ifdef CONFIG_PCI | |
441 | m8xx_setup_pci_ptrs(); | |
442 | #endif | |
443 | ||
444 | #ifdef CONFIG_BLK_DEV_INITRD | |
445 | /* take care of initrd if we have one */ | |
446 | if ( r4 ) | |
447 | { | |
448 | initrd_start = r4 + KERNELBASE; | |
449 | initrd_end = r5 + KERNELBASE; | |
450 | } | |
451 | #endif /* CONFIG_BLK_DEV_INITRD */ | |
452 | /* take care of cmd line */ | |
453 | if ( r6 ) | |
454 | { | |
455 | *(char *)(r7+KERNELBASE) = 0; | |
456 | strcpy(cmd_line, (char *)(r6+KERNELBASE)); | |
457 | } | |
458 | ||
1461b4ea VB |
459 | identify_ppc_sys_by_name(BOARD_CHIP_NAME); |
460 | ||
1da177e4 LT |
461 | ppc_md.setup_arch = m8xx_setup_arch; |
462 | ppc_md.show_percpuinfo = m8xx_show_percpuinfo; | |
1da177e4 LT |
463 | ppc_md.init_IRQ = m8xx_init_IRQ; |
464 | ppc_md.get_irq = m8xx_get_irq; | |
465 | ppc_md.init = NULL; | |
466 | ||
467 | ppc_md.restart = m8xx_restart; | |
468 | ppc_md.power_off = m8xx_power_off; | |
469 | ppc_md.halt = m8xx_halt; | |
470 | ||
471 | ppc_md.time_init = NULL; | |
472 | ppc_md.set_rtc_time = m8xx_set_rtc_time; | |
473 | ppc_md.get_rtc_time = m8xx_get_rtc_time; | |
474 | ppc_md.calibrate_decr = m8xx_calibrate_decr; | |
475 | ||
476 | ppc_md.find_end_of_memory = m8xx_find_end_of_memory; | |
477 | ppc_md.setup_io_mappings = m8xx_map_io; | |
478 | ||
566ecb9b | 479 | #if defined(CONFIG_BLK_DEV_MPC8xx_IDE) |
1da177e4 LT |
480 | m8xx_ide_init(); |
481 | #endif | |
482 | } |