vserver 1.9.3
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_setup.c
1 /*
2  *
3  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
4  *
5  *    Copyright 2000-2001 MontaVista Software Inc.
6  *      Completed implementation.
7  *      Author: MontaVista Software, Inc.  <source@mvista.com>
8  *              Frank Rowand <frank_rowand@mvista.com>
9  *              Debbie Chu   <debbie_chu@mvista.com>
10  *      Further modifications by Armin Kuster
11  *
12  *    Module name: ppc4xx_setup.c
13  *
14  */
15
16 #include <linux/config.h>
17 #include <linux/init.h>
18 #include <linux/smp.h>
19 #include <linux/threads.h>
20 #include <linux/spinlock.h>
21 #include <linux/irq.h>
22 #include <linux/reboot.h>
23 #include <linux/param.h>
24 #include <linux/string.h>
25 #include <linux/initrd.h>
26 #include <linux/pci.h>
27 #include <linux/rtc.h>
28 #include <linux/console.h>
29 #include <linux/ide.h>
30 #include <linux/serial_reg.h>
31 #include <linux/seq_file.h>
32
33 #include <asm/system.h>
34 #include <asm/processor.h>
35 #include <asm/machdep.h>
36 #include <asm/page.h>
37 #include <asm/kgdb.h>
38 #include <asm/ibm4xx.h>
39 #include <asm/time.h>
40 #include <asm/todc.h>
41 #include <asm/ppc4xx_pic.h>
42 #include <asm/pci-bridge.h>
43 #include <asm/bootinfo.h>
44
45 /* Function Prototypes */
46 extern void abort(void);
47 extern void ppc4xx_find_bridges(void);
48
49 extern void ppc4xx_wdt_heartbeat(void);
50 extern int wdt_enable;
51 extern unsigned long wdt_period;
52
53 /* Global Variables */
54 bd_t __res;
55
56 void __init
57 ppc4xx_setup_arch(void)
58 {
59         /* Setup PCI host bridges */
60
61 #ifdef CONFIG_PCI
62         ppc4xx_find_bridges();
63 #endif
64 }
65
66 /*
67  *   This routine pretty-prints the platform's internal CPU clock
68  *   frequencies into the buffer for usage in /proc/cpuinfo.
69  */
70
71 static int
72 ppc4xx_show_percpuinfo(struct seq_file *m, int i)
73 {
74         seq_printf(m, "clock\t\t: %ldMHz\n", (long)__res.bi_intfreq / 1000000);
75
76         return 0;
77 }
78
79 /*
80  *   This routine pretty-prints the platform's internal bus clock
81  *   frequencies into the buffer for usage in /proc/cpuinfo.
82  */
83 static int
84 ppc4xx_show_cpuinfo(struct seq_file *m)
85 {
86         bd_t *bip = &__res;
87
88         seq_printf(m, "machine\t\t: %s\n", PPC4xx_MACHINE_NAME);
89         seq_printf(m, "plb bus clock\t: %ldMHz\n",
90                    (long) bip->bi_busfreq / 1000000);
91 #ifdef CONFIG_PCI
92         seq_printf(m, "pci bus clock\t: %dMHz\n",
93                    bip->bi_pci_busfreq / 1000000);
94 #endif
95
96         return 0;
97 }
98
99 /*
100  * Return the virtual address representing the top of physical RAM.
101  */
102 static unsigned long __init
103 ppc4xx_find_end_of_memory(void)
104 {
105         return ((unsigned long) __res.bi_memsize);
106 }
107
108 void __init
109 ppc4xx_map_io(void)
110 {
111         io_block_mapping(PPC4xx_ONB_IO_VADDR,
112                          PPC4xx_ONB_IO_PADDR, PPC4xx_ONB_IO_SIZE, _PAGE_IO);
113 #ifdef CONFIG_PCI
114         io_block_mapping(PPC4xx_PCI_IO_VADDR,
115                          PPC4xx_PCI_IO_PADDR, PPC4xx_PCI_IO_SIZE, _PAGE_IO);
116         io_block_mapping(PPC4xx_PCI_CFG_VADDR,
117                          PPC4xx_PCI_CFG_PADDR, PPC4xx_PCI_CFG_SIZE, _PAGE_IO);
118         io_block_mapping(PPC4xx_PCI_LCFG_VADDR,
119                          PPC4xx_PCI_LCFG_PADDR, PPC4xx_PCI_LCFG_SIZE, _PAGE_IO);
120 #endif
121 }
122
123 void __init
124 ppc4xx_init_IRQ(void)
125 {
126         int i;
127
128         ppc4xx_pic_init();
129
130         for (i = 0; i < NR_IRQS; i++)
131                 irq_desc[i].handler = ppc4xx_pic;
132 }
133
134 static void
135 ppc4xx_restart(char *cmd)
136 {
137         printk("%s\n", cmd);
138         abort();
139 }
140
141 static void
142 ppc4xx_power_off(void)
143 {
144         printk("System Halted\n");
145         local_irq_disable();
146         while (1) ;
147 }
148
149 static void
150 ppc4xx_halt(void)
151 {
152         printk("System Halted\n");
153         local_irq_disable();
154         while (1) ;
155 }
156
157 /*
158  * This routine retrieves the internal processor frequency from the board
159  * information structure, sets up the kernel timer decrementer based on
160  * that value, enables the 4xx programmable interval timer (PIT) and sets
161  * it up for auto-reload.
162  */
163 static void __init
164 ppc4xx_calibrate_decr(void)
165 {
166         unsigned int freq;
167         bd_t *bip = &__res;
168
169 #if defined(CONFIG_WALNUT) || defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
170         /* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
171         mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
172 #endif
173         freq = bip->bi_tbfreq;
174         tb_ticks_per_jiffy = freq / HZ;
175         tb_to_us = mulhwu_scale_factor(freq, 1000000);
176
177         /* Set the time base to zero.
178            ** At 200 Mhz, time base will rollover in ~2925 years.
179          */
180
181         mtspr(SPRN_TBWL, 0);
182         mtspr(SPRN_TBWU, 0);
183
184         /* Clear any pending timer interrupts */
185
186         mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
187         mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
188
189         /* Set the PIT reload value and just let it run. */
190         mtspr(SPRN_PIT, tb_ticks_per_jiffy);
191 }
192 #ifdef CONFIG_SERIAL_TEXT_DEBUG
193
194 /* We assume that the UART has already been initialized by the
195    firmware or the boot loader */
196 static void
197 serial_putc(u8 * com_port, unsigned char c)
198 {
199         while ((readb(com_port + (UART_LSR)) & UART_LSR_THRE) == 0) ;
200         writeb(c, com_port);
201 }
202
203 static void
204 ppc4xx_progress(char *s, unsigned short hex)
205 {
206         char c;
207 #ifdef SERIAL_DEBUG_IO_BASE
208         u8 *com_port = (u8 *) SERIAL_DEBUG_IO_BASE;
209
210         while ((c = *s++) != '\0') {
211                 serial_putc(com_port, c);
212         }
213         serial_putc(com_port, '\r');
214         serial_putc(com_port, '\n');
215 #else
216         printk("%s\r\n");
217 #endif
218 }
219 #endif                          /* CONFIG_SERIAL_TEXT_DEBUG */
220
221 /*
222  * IDE stuff.
223  * should be generic for every IDE PCI chipset
224  */
225 #if defined(CONFIG_PCI) && defined(CONFIG_IDE)
226 static void
227 ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
228                            unsigned long ctrl_port, int *irq)
229 {
230         int i;
231
232         for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
233                 hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
234
235         hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
236 }
237 #endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */
238
239 TODC_ALLOC();
240
241 /*
242  * Input(s):
243  *   r3 - Optional pointer to a board information structure.
244  *   r4 - Optional pointer to the physical starting address of the init RAM
245  *        disk.
246  *   r5 - Optional pointer to the physical ending address of the init RAM
247  *        disk.
248  *   r6 - Optional pointer to the physical starting address of any kernel
249  *        command-line parameters.
250  *   r7 - Optional pointer to the physical ending address of any kernel
251  *        command-line parameters.
252  */
253 void __init
254 ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
255             unsigned long r6, unsigned long r7)
256 {
257         parse_bootinfo(find_bootinfo());
258
259         /*
260          * If we were passed in a board information, copy it into the
261          * residual data area.
262          */
263         if (r3)
264                 __res = *(bd_t *)(r3 + KERNELBASE);
265
266 #if defined(CONFIG_BLK_DEV_INITRD)
267         /*
268          * If the init RAM disk has been configured in, and there's a valid
269          * starting address for it, set it up.
270          */
271         if (r4) {
272                 initrd_start = r4 + KERNELBASE;
273                 initrd_end = r5 + KERNELBASE;
274         }
275 #endif                          /* CONFIG_BLK_DEV_INITRD */
276
277         /* Copy the kernel command line arguments to a safe place. */
278
279         if (r6) {
280                 *(char *) (r7 + KERNELBASE) = 0;
281                 strcpy(cmd_line, (char *) (r6 + KERNELBASE));
282         }
283 #if defined(CONFIG_PPC405_WDT)
284 /* Look for wdt= option on command line */
285         if (strstr(cmd_line, "wdt=")) {
286                 int valid_wdt = 0;
287                 char *p, *q;
288                 for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
289                         q = p + 4;
290                         if (p > cmd_line && p[-1] != ' ')
291                                 continue;
292                         wdt_period = simple_strtoul(q, &q, 0);
293                         valid_wdt = 1;
294                         ++q;
295                 }
296                 wdt_enable = valid_wdt;
297         }
298 #endif
299
300         /* Initialize machine-dependent vectors */
301
302         ppc_md.setup_arch = ppc4xx_setup_arch;
303         ppc_md.show_percpuinfo = ppc4xx_show_percpuinfo;
304         ppc_md.show_cpuinfo = ppc4xx_show_cpuinfo;
305         ppc_md.init_IRQ = ppc4xx_init_IRQ;
306
307         ppc_md.restart = ppc4xx_restart;
308         ppc_md.power_off = ppc4xx_power_off;
309         ppc_md.halt = ppc4xx_halt;
310
311         ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
312
313 #ifdef CONFIG_PPC405_WDT
314         ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
315 #endif
316         ppc_md.heartbeat_count = 0;
317
318         ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
319         ppc_md.setup_io_mappings = ppc4xx_map_io;
320
321 #ifdef CONFIG_SERIAL_TEXT_DEBUG
322         ppc_md.progress = ppc4xx_progress;
323 #endif
324
325 /*
326 **   m8xx_setup.c, prep_setup.c use
327 **     defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
328 */
329 #if defined(CONFIG_PCI) && defined(CONFIG_IDE)
330         ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
331 #endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */
332 }