Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * Board setup routines for Force PowerPMC-250 Processor PMC |
3 | * | |
4 | * Author: Troy Benjegerdes <tbenjegerdes@mvista.com> | |
5 | * Borrowed heavily from prpmc750_*.c by | |
6 | * Matt Porter <mporter@mvista.com> | |
7 | * | |
8 | * 2001 (c) MontaVista, Software, Inc. This file is licensed under | |
9 | * the terms of the GNU General Public License version 2. This program | |
10 | * is licensed "as is" without any warranty of any kind, whether express | |
11 | * or implied. | |
12 | */ | |
13 | ||
1da177e4 LT |
14 | #include <linux/stddef.h> |
15 | #include <linux/kernel.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/reboot.h> | |
19 | #include <linux/pci.h> | |
20 | #include <linux/kdev_t.h> | |
21 | #include <linux/types.h> | |
22 | #include <linux/major.h> | |
23 | #include <linux/initrd.h> | |
24 | #include <linux/console.h> | |
25 | #include <linux/delay.h> | |
1da177e4 LT |
26 | #include <linux/slab.h> |
27 | #include <linux/seq_file.h> | |
1da177e4 LT |
28 | #include <linux/root_dev.h> |
29 | ||
30 | #include <asm/byteorder.h> | |
31 | #include <asm/system.h> | |
32 | #include <asm/pgtable.h> | |
33 | #include <asm/page.h> | |
34 | #include <asm/dma.h> | |
35 | #include <asm/io.h> | |
36 | #include <asm/irq.h> | |
37 | #include <asm/machdep.h> | |
38 | #include <asm/time.h> | |
39 | #include <platforms/powerpmc250.h> | |
40 | #include <asm/open_pic.h> | |
41 | #include <asm/pci-bridge.h> | |
42 | #include <asm/mpc10x.h> | |
43 | #include <asm/uaccess.h> | |
44 | #include <asm/bootinfo.h> | |
45 | ||
46 | extern void powerpmc250_find_bridges(void); | |
47 | extern unsigned long loops_per_jiffy; | |
48 | ||
49 | static u_char powerpmc250_openpic_initsenses[] __initdata = | |
50 | { | |
51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
52 | 1, /* PMC INTA (also MPC107 output interrupt INTA) */ | |
53 | 1, /* PMC INTB (also I82559 Ethernet controller) */ | |
54 | 1, /* PMC INTC */ | |
55 | 1, /* PMC INTD */ | |
56 | 0, /* DUART interrupt (active high) */ | |
57 | }; | |
58 | ||
59 | static int | |
60 | powerpmc250_show_cpuinfo(struct seq_file *m) | |
61 | { | |
62 | seq_printf(m,"machine\t\t: Force PowerPMC250\n"); | |
63 | ||
64 | return 0; | |
65 | } | |
66 | ||
67 | static void __init | |
68 | powerpmc250_setup_arch(void) | |
69 | { | |
70 | /* init to some ~sane value until calibrate_delay() runs */ | |
71 | loops_per_jiffy = 50000000/HZ; | |
72 | ||
73 | /* Lookup PCI host bridges */ | |
74 | powerpmc250_find_bridges(); | |
75 | ||
76 | #ifdef CONFIG_BLK_DEV_INITRD | |
77 | if (initrd_start) | |
78 | ROOT_DEV = Root_RAM0; | |
79 | else | |
80 | #endif | |
81 | #ifdef CONFIG_ROOT_NFS | |
82 | ROOT_DEV = Root_NFS; | |
83 | #else | |
84 | ROOT_DEV = Root_SDA2; | |
85 | #endif | |
86 | ||
87 | printk("Force PowerPMC250 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); | |
88 | } | |
89 | ||
90 | #if 0 | |
91 | /* | |
92 | * Compute the PrPMC750's bus speed using the baud clock as a | |
93 | * reference. | |
94 | */ | |
95 | unsigned long __init powerpmc250_get_bus_speed(void) | |
96 | { | |
97 | unsigned long tbl_start, tbl_end; | |
98 | unsigned long current_state, old_state, bus_speed; | |
99 | unsigned char lcr, dll, dlm; | |
100 | int baud_divisor, count; | |
101 | ||
102 | /* Read the UART's baud clock divisor */ | |
103 | lcr = readb(PRPMC750_SERIAL_0_LCR); | |
104 | writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); | |
105 | dll = readb(PRPMC750_SERIAL_0_DLL); | |
106 | dlm = readb(PRPMC750_SERIAL_0_DLM); | |
107 | writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); | |
108 | baud_divisor = (dlm << 8) | dll; | |
109 | ||
110 | /* | |
111 | * Use the baud clock divisor and base baud clock | |
112 | * to determine the baud rate and use that as | |
113 | * the number of baud clock edges we use for | |
114 | * the time base sample. Make it half the baud | |
115 | * rate. | |
116 | */ | |
117 | count = PRPMC750_BASE_BAUD / (baud_divisor * 16); | |
118 | ||
119 | /* Find the first edge of the baud clock */ | |
120 | old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK; | |
121 | do { | |
122 | current_state = readb(PRPMC750_STATUS_REG) & | |
123 | PRPMC750_BAUDOUT_MASK; | |
124 | } while(old_state == current_state); | |
125 | ||
126 | old_state = current_state; | |
127 | ||
128 | /* Get the starting time base value */ | |
129 | tbl_start = get_tbl(); | |
130 | ||
131 | /* | |
132 | * Loop until we have found a number of edges equal | |
133 | * to half the count (half the baud rate) | |
134 | */ | |
135 | do { | |
136 | do { | |
137 | current_state = readb(PRPMC750_STATUS_REG) & | |
138 | PRPMC750_BAUDOUT_MASK; | |
139 | } while(old_state == current_state); | |
140 | old_state = current_state; | |
141 | } while (--count); | |
142 | ||
143 | /* Get the ending time base value */ | |
144 | tbl_end = get_tbl(); | |
145 | ||
146 | /* Compute bus speed */ | |
147 | bus_speed = (tbl_end-tbl_start)*128; | |
148 | ||
149 | return bus_speed; | |
150 | } | |
151 | #endif | |
152 | ||
153 | static void __init | |
154 | powerpmc250_calibrate_decr(void) | |
155 | { | |
156 | unsigned long freq; | |
157 | int divisor = 4; | |
158 | ||
159 | //freq = powerpmc250_get_bus_speed(); | |
160 | #warning hardcoded bus freq | |
161 | freq = 100000000; | |
162 | ||
163 | tb_ticks_per_jiffy = freq / (HZ * divisor); | |
164 | tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); | |
165 | } | |
166 | ||
167 | static void | |
168 | powerpmc250_restart(char *cmd) | |
169 | { | |
170 | local_irq_disable(); | |
171 | /* Hard reset */ | |
172 | writeb(0x11, 0xfe000332); | |
173 | while(1); | |
174 | } | |
175 | ||
176 | static void | |
177 | powerpmc250_halt(void) | |
178 | { | |
179 | local_irq_disable(); | |
180 | while (1); | |
181 | } | |
182 | ||
183 | static void | |
184 | powerpmc250_power_off(void) | |
185 | { | |
186 | powerpmc250_halt(); | |
187 | } | |
188 | ||
189 | static void __init | |
190 | powerpmc250_init_IRQ(void) | |
191 | { | |
192 | ||
193 | OpenPIC_InitSenses = powerpmc250_openpic_initsenses; | |
194 | OpenPIC_NumInitSenses = sizeof(powerpmc250_openpic_initsenses); | |
195 | mpc10x_set_openpic(); | |
196 | } | |
197 | ||
198 | /* | |
199 | * Set BAT 3 to map 0xf0000000 to end of physical memory space. | |
200 | */ | |
201 | static __inline__ void | |
202 | powerpmc250_set_bat(void) | |
203 | { | |
204 | unsigned long bat3u, bat3l; | |
205 | static int mapping_set = 0; | |
206 | ||
207 | if (!mapping_set) | |
208 | { | |
209 | __asm__ __volatile__( | |
210 | " lis %0,0xf000\n \ | |
211 | ori %1,%0,0x002a\n \ | |
212 | ori %0,%0,0x1ffe\n \ | |
213 | mtspr 0x21e,%0\n \ | |
214 | mtspr 0x21f,%1\n \ | |
215 | isync\n \ | |
216 | sync " | |
217 | : "=r" (bat3u), "=r" (bat3l)); | |
218 | ||
219 | mapping_set = 1; | |
220 | } | |
221 | return; | |
222 | } | |
223 | ||
224 | static unsigned long __init | |
225 | powerpmc250_find_end_of_memory(void) | |
226 | { | |
227 | /* Cover I/O space with a BAT */ | |
228 | /* yuck, better hope your ram size is a power of 2 -- paulus */ | |
229 | powerpmc250_set_bat(); | |
230 | ||
231 | return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); | |
232 | } | |
233 | ||
234 | static void __init | |
235 | powerpmc250_map_io(void) | |
236 | { | |
237 | io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); | |
238 | } | |
239 | ||
240 | void __init | |
241 | platform_init(unsigned long r3, unsigned long r4, unsigned long r5, | |
242 | unsigned long r6, unsigned long r7) | |
243 | { | |
244 | parse_bootinfo(find_bootinfo()); | |
245 | ||
246 | #ifdef CONFIG_BLK_DEV_INITRD | |
247 | if ( r4 ) | |
248 | { | |
249 | initrd_start = r4 + KERNELBASE; | |
250 | initrd_end = r5 + KERNELBASE; | |
251 | } | |
252 | #endif | |
253 | ||
254 | /* Copy cmd_line parameters */ | |
255 | if ( r6) | |
256 | { | |
257 | *(char *)(r7 + KERNELBASE) = 0; | |
258 | strcpy(cmd_line, (char *)(r6 + KERNELBASE)); | |
259 | } | |
260 | ||
261 | isa_io_base = MPC10X_MAPB_ISA_IO_BASE; | |
262 | isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; | |
263 | pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; | |
264 | ||
265 | ppc_md.setup_arch = powerpmc250_setup_arch; | |
266 | ppc_md.show_cpuinfo = powerpmc250_show_cpuinfo; | |
267 | ppc_md.init_IRQ = powerpmc250_init_IRQ; | |
268 | ppc_md.get_irq = openpic_get_irq; | |
269 | ||
270 | ppc_md.find_end_of_memory = powerpmc250_find_end_of_memory; | |
271 | ppc_md.setup_io_mappings = powerpmc250_map_io; | |
272 | ||
273 | ppc_md.restart = powerpmc250_restart; | |
274 | ppc_md.power_off = powerpmc250_power_off; | |
275 | ppc_md.halt = powerpmc250_halt; | |
276 | ||
277 | /* PowerPMC250 has no timekeeper part */ | |
278 | ppc_md.time_init = NULL; | |
279 | ppc_md.get_rtc_time = NULL; | |
280 | ppc_md.set_rtc_time = NULL; | |
281 | ppc_md.calibrate_decr = powerpmc250_calibrate_decr; | |
282 | } | |
283 | ||
284 | ||
285 | /* | |
286 | * (This used to be arch/ppc/platforms/powerpmc250_pci.c) | |
287 | * | |
288 | * PCI support for Force PowerPMC250 | |
289 | * | |
290 | */ | |
291 | ||
292 | #undef DEBUG | |
293 | #ifdef DEBUG | |
294 | #define DBG(x...) printk(x) | |
295 | #else | |
296 | #define DBG(x...) | |
297 | #endif /* DEBUG */ | |
298 | ||
299 | static inline int __init | |
300 | powerpmc250_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) | |
301 | { | |
302 | static char pci_irq_table[][4] = | |
303 | /* | |
304 | * PCI IDSEL/INTPIN->INTLINE | |
305 | * A B C D | |
306 | */ | |
307 | { | |
308 | {17, 0, 0, 0}, /* Device 11 - 82559 */ | |
309 | {0, 0, 0, 0}, /* 12 */ | |
310 | {0, 0, 0, 0}, /* 13 */ | |
311 | {0, 0, 0, 0}, /* 14 */ | |
312 | {0, 0, 0, 0}, /* 15 */ | |
313 | {16, 17, 18, 19}, /* Device 16 - PMC A1?? */ | |
314 | }; | |
315 | const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; | |
316 | return PCI_IRQ_TABLE_LOOKUP; | |
317 | }; | |
318 | ||
319 | static int | |
320 | powerpmc250_exclude_device(u_char bus, u_char devfn) | |
321 | { | |
322 | /* | |
323 | * While doing PCI Scan the MPC107 will 'detect' itself as | |
324 | * device on the PCI Bus, will create an incorrect response and | |
325 | * later will respond incorrectly to Configuration read coming | |
326 | * from another device. | |
327 | * | |
328 | * The work around is that when doing a PCI Scan one | |
329 | * should skip its own device number in the scan. | |
330 | * | |
331 | * The top IDsel is AD13 and the middle is AD14. | |
332 | * | |
333 | * -- Note from force | |
334 | */ | |
335 | ||
336 | if ((bus == 0) && (PCI_SLOT(devfn) == 13 || PCI_SLOT(devfn) == 14)) { | |
337 | return PCIBIOS_DEVICE_NOT_FOUND; | |
338 | } | |
339 | else { | |
340 | return PCIBIOS_SUCCESSFUL; | |
341 | } | |
342 | } | |
343 | ||
344 | void __init | |
345 | powerpmc250_find_bridges(void) | |
346 | { | |
347 | struct pci_controller* hose; | |
348 | ||
349 | hose = pcibios_alloc_controller(); | |
350 | if (!hose){ | |
351 | printk("Can't allocate PCI 'hose' structure!!!\n"); | |
352 | return; | |
353 | } | |
354 | ||
355 | hose->first_busno = 0; | |
356 | hose->last_busno = 0xff; | |
357 | ||
358 | if (mpc10x_bridge_init(hose, | |
359 | MPC10X_MEM_MAP_B, | |
360 | MPC10X_MEM_MAP_B, | |
361 | MPC10X_MAPB_EUMB_BASE) == 0) { | |
362 | ||
363 | hose->mem_resources[0].end = 0xffffffff; | |
364 | ||
365 | hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); | |
366 | ||
367 | /* ppc_md.pcibios_fixup = pcore_pcibios_fixup; */ | |
368 | ppc_md.pci_swizzle = common_swizzle; | |
369 | ||
370 | ppc_md.pci_exclude_device = powerpmc250_exclude_device; | |
371 | ppc_md.pci_map_irq = powerpmc250_map_irq; | |
372 | } else { | |
373 | if (ppc_md.progress) | |
374 | ppc_md.progress("Bridge init failed", 0x100); | |
375 | printk("Host bridge init failed\n"); | |
376 | } | |
377 | ||
378 | } |