Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * BRIEF MODULE DESCRIPTION | |
3 | * Momentum Computer Ocelot-C and -CS board dependent boot routines | |
4 | * | |
5 | * Copyright (C) 1996, 1997, 2001 Ralf Baechle | |
6 | * Copyright (C) 2000 RidgeRun, Inc. | |
7 | * Copyright (C) 2001 Red Hat, Inc. | |
8 | * Copyright (C) 2002 Momentum Computer | |
9 | * | |
10 | * Author: Matthew Dharm, Momentum Computer | |
11 | * mdharm@momenco.com | |
12 | * | |
13 | * Louis Hamilton, Red Hat, Inc. | |
14 | * hamilton@redhat.com [MIPS64 modifications] | |
15 | * | |
16 | * Author: RidgeRun, Inc. | |
17 | * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com | |
18 | * | |
19 | * Copyright 2001 MontaVista Software Inc. | |
20 | * Author: jsun@mvista.com or jsun@junsun.net | |
21 | * | |
22 | * This program is free software; you can redistribute it and/or modify it | |
23 | * under the terms of the GNU General Public License as published by the | |
24 | * Free Software Foundation; either version 2 of the License, or (at your | |
25 | * option) any later version. | |
26 | * | |
27 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
28 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
29 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
30 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
32 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
33 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
34 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
35 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
36 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
37 | * | |
38 | * You should have received a copy of the GNU General Public License along | |
39 | * with this program; if not, write to the Free Software Foundation, Inc., | |
40 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
41 | * | |
42 | */ | |
43 | #include <linux/config.h> | |
44 | #include <linux/bcd.h> | |
45 | #include <linux/init.h> | |
46 | #include <linux/kernel.h> | |
47 | #include <linux/types.h> | |
48 | #include <linux/mm.h> | |
49 | #include <linux/swap.h> | |
50 | #include <linux/ioport.h> | |
51 | #include <linux/sched.h> | |
52 | #include <linux/interrupt.h> | |
53 | #include <linux/pci.h> | |
54 | #include <linux/timex.h> | |
55 | #include <linux/vmalloc.h> | |
56 | #include <asm/time.h> | |
57 | #include <asm/bootinfo.h> | |
58 | #include <asm/page.h> | |
59 | #include <asm/io.h> | |
60 | #include <asm/irq.h> | |
61 | #include <asm/pci.h> | |
62 | #include <asm/processor.h> | |
63 | #include <asm/ptrace.h> | |
64 | #include <asm/reboot.h> | |
65 | #include <linux/bootmem.h> | |
66 | #include <linux/blkdev.h> | |
67 | #include <asm/mv64340.h> | |
68 | #include "ocelot_c_fpga.h" | |
69 | ||
70 | unsigned long marvell_base; | |
71 | extern unsigned long mv64340_sram_base; | |
72 | unsigned long cpu_clock; | |
73 | ||
74 | /* These functions are used for rebooting or halting the machine*/ | |
75 | extern void momenco_ocelot_restart(char *command); | |
76 | extern void momenco_ocelot_halt(void); | |
77 | extern void momenco_ocelot_power_off(void); | |
78 | ||
79 | void momenco_time_init(void); | |
80 | ||
81 | static char reset_reason; | |
82 | ||
83 | void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask); | |
84 | ||
85 | static unsigned long ENTRYLO(unsigned long paddr) | |
86 | { | |
87 | return ((paddr & PAGE_MASK) | | |
88 | (_PAGE_PRESENT | __READABLE | __WRITEABLE | _PAGE_GLOBAL | | |
89 | _CACHE_UNCACHED)) >> 6; | |
90 | } | |
91 | ||
92 | /* setup code for a handoff from a version 2 PMON 2000 PROM */ | |
93 | void PMON_v2_setup(void) | |
94 | { | |
95 | /* Some wired TLB entries for the MV64340 and perhiperals. The | |
96 | MV64340 is going to be hit on every IRQ anyway - there's | |
97 | absolutely no point in letting it be a random TLB entry, as | |
98 | it'll just cause needless churning of the TLB. And we use | |
99 | the other half for the serial port, which is just a PITA | |
100 | otherwise :) | |
101 | ||
102 | Device Physical Virtual | |
103 | MV64340 Internal Regs 0xf4000000 0xf4000000 | |
104 | Ocelot-C[S] PLD (CS0) 0xfc000000 0xfc000000 | |
105 | NVRAM (CS1) 0xfc800000 0xfc800000 | |
106 | UARTs (CS2) 0xfd000000 0xfd000000 | |
107 | Internal SRAM 0xfe000000 0xfe000000 | |
108 | M-Systems DOC (CS3) 0xff000000 0xff000000 | |
109 | */ | |
110 | printk("PMON_v2_setup\n"); | |
111 | ||
875d43e7 | 112 | #ifdef CONFIG_64BIT |
1da177e4 LT |
113 | /* marvell and extra space */ |
114 | add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xfffffffff4000000, PM_64K); | |
115 | /* fpga, rtc, and uart */ | |
116 | add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000), 0xfffffffffc000000, PM_16M); | |
117 | /* m-sys and internal SRAM */ | |
118 | add_wired_entry(ENTRYLO(0xfe000000), ENTRYLO(0xff000000), 0xfffffffffe000000, PM_16M); | |
119 | ||
120 | marvell_base = 0xfffffffff4000000; | |
121 | mv64340_sram_base = 0xfffffffffe000000; | |
122 | #else | |
123 | /* marvell and extra space */ | |
124 | add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xf4000000, PM_64K); | |
125 | /* fpga, rtc, and uart */ | |
126 | add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000), 0xfc000000, PM_16M); | |
127 | /* m-sys and internal SRAM */ | |
128 | add_wired_entry(ENTRYLO(0xfe000000), ENTRYLO(0xff000000), 0xfe000000, PM_16M); | |
129 | ||
130 | marvell_base = 0xf4000000; | |
131 | mv64340_sram_base = 0xfe000000; | |
132 | #endif | |
133 | } | |
134 | ||
135 | unsigned long m48t37y_get_time(void) | |
136 | { | |
875d43e7 | 137 | #ifdef CONFIG_64BIT |
1da177e4 LT |
138 | unsigned char *rtc_base = (unsigned char*)0xfffffffffc800000; |
139 | #else | |
140 | unsigned char* rtc_base = (unsigned char*)0xfc800000; | |
141 | #endif | |
142 | unsigned int year, month, day, hour, min, sec; | |
143 | ||
144 | /* stop the update */ | |
145 | rtc_base[0x7ff8] = 0x40; | |
146 | ||
147 | year = BCD2BIN(rtc_base[0x7fff]); | |
148 | year += BCD2BIN(rtc_base[0x7ff1]) * 100; | |
149 | ||
150 | month = BCD2BIN(rtc_base[0x7ffe]); | |
151 | ||
152 | day = BCD2BIN(rtc_base[0x7ffd]); | |
153 | ||
154 | hour = BCD2BIN(rtc_base[0x7ffb]); | |
155 | min = BCD2BIN(rtc_base[0x7ffa]); | |
156 | sec = BCD2BIN(rtc_base[0x7ff9]); | |
157 | ||
158 | /* start the update */ | |
159 | rtc_base[0x7ff8] = 0x00; | |
160 | ||
161 | return mktime(year, month, day, hour, min, sec); | |
162 | } | |
163 | ||
164 | int m48t37y_set_time(unsigned long sec) | |
165 | { | |
875d43e7 | 166 | #ifdef CONFIG_64BIT |
1da177e4 LT |
167 | unsigned char* rtc_base = (unsigned char*)0xfffffffffc800000; |
168 | #else | |
169 | unsigned char* rtc_base = (unsigned char*)0xfc800000; | |
170 | #endif | |
171 | struct rtc_time tm; | |
172 | ||
173 | /* convert to a more useful format -- note months count from 0 */ | |
174 | to_tm(sec, &tm); | |
175 | tm.tm_mon += 1; | |
176 | ||
177 | /* enable writing */ | |
178 | rtc_base[0x7ff8] = 0x80; | |
179 | ||
180 | /* year */ | |
181 | rtc_base[0x7fff] = BIN2BCD(tm.tm_year % 100); | |
182 | rtc_base[0x7ff1] = BIN2BCD(tm.tm_year / 100); | |
183 | ||
184 | /* month */ | |
185 | rtc_base[0x7ffe] = BIN2BCD(tm.tm_mon); | |
186 | ||
187 | /* day */ | |
188 | rtc_base[0x7ffd] = BIN2BCD(tm.tm_mday); | |
189 | ||
190 | /* hour/min/sec */ | |
191 | rtc_base[0x7ffb] = BIN2BCD(tm.tm_hour); | |
192 | rtc_base[0x7ffa] = BIN2BCD(tm.tm_min); | |
193 | rtc_base[0x7ff9] = BIN2BCD(tm.tm_sec); | |
194 | ||
195 | /* day of week -- not really used, but let's keep it up-to-date */ | |
196 | rtc_base[0x7ffc] = BIN2BCD(tm.tm_wday + 1); | |
197 | ||
198 | /* disable writing */ | |
199 | rtc_base[0x7ff8] = 0x00; | |
200 | ||
201 | return 0; | |
202 | } | |
203 | ||
204 | void momenco_timer_setup(struct irqaction *irq) | |
205 | { | |
206 | setup_irq(7, irq); | |
207 | } | |
208 | ||
209 | void momenco_time_init(void) | |
210 | { | |
211 | #ifdef CONFIG_CPU_SR71000 | |
212 | mips_hpt_frequency = cpu_clock; | |
213 | #elif defined(CONFIG_CPU_RM7000) | |
214 | mips_hpt_frequency = cpu_clock / 2; | |
215 | #else | |
216 | #error Unknown CPU for this board | |
217 | #endif | |
218 | printk("momenco_time_init cpu_clock=%d\n", cpu_clock); | |
219 | board_timer_setup = momenco_timer_setup; | |
220 | ||
221 | rtc_get_time = m48t37y_get_time; | |
222 | rtc_set_time = m48t37y_set_time; | |
223 | } | |
224 | ||
c83cfc9c | 225 | void __init plat_setup(void) |
1da177e4 LT |
226 | { |
227 | unsigned int tmpword; | |
228 | ||
229 | board_time_init = momenco_time_init; | |
230 | ||
231 | _machine_restart = momenco_ocelot_restart; | |
232 | _machine_halt = momenco_ocelot_halt; | |
233 | _machine_power_off = momenco_ocelot_power_off; | |
234 | ||
235 | /* | |
236 | * initrd_start = (ulong)ocelot_initrd_start; | |
237 | * initrd_end = (ulong)ocelot_initrd_start + (ulong)ocelot_initrd_size; | |
238 | * initrd_below_start_ok = 1; | |
239 | */ | |
240 | ||
241 | /* do handoff reconfiguration */ | |
242 | PMON_v2_setup(); | |
243 | ||
244 | /* shut down ethernet ports, just to be sure our memory doesn't get | |
245 | * corrupted by random ethernet traffic. | |
246 | */ | |
247 | MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8); | |
248 | MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8); | |
249 | MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8); | |
250 | MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8); | |
251 | do {} | |
252 | while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff); | |
253 | do {} | |
254 | while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff); | |
255 | do {} | |
256 | while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff); | |
257 | do {} | |
258 | while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff); | |
259 | MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0), | |
260 | MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1); | |
261 | MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1), | |
262 | MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1); | |
263 | ||
264 | /* Turn off the Bit-Error LED */ | |
265 | OCELOT_FPGA_WRITE(0x80, CLR); | |
266 | ||
267 | tmpword = OCELOT_FPGA_READ(BOARDREV); | |
268 | #ifdef CONFIG_CPU_SR71000 | |
269 | if (tmpword < 26) | |
270 | printk("Momenco Ocelot-CS: Board Assembly Rev. %c\n", | |
271 | 'A'+tmpword); | |
272 | else | |
273 | printk("Momenco Ocelot-CS: Board Assembly Revision #0x%x\n", | |
274 | tmpword); | |
275 | #else | |
276 | if (tmpword < 26) | |
277 | printk("Momenco Ocelot-C: Board Assembly Rev. %c\n", | |
278 | 'A'+tmpword); | |
279 | else | |
280 | printk("Momenco Ocelot-C: Board Assembly Revision #0x%x\n", | |
281 | tmpword); | |
282 | #endif | |
283 | ||
284 | tmpword = OCELOT_FPGA_READ(FPGA_REV); | |
285 | printk("FPGA Rev: %d.%d\n", tmpword>>4, tmpword&15); | |
286 | tmpword = OCELOT_FPGA_READ(RESET_STATUS); | |
287 | printk("Reset reason: 0x%x\n", tmpword); | |
288 | switch (tmpword) { | |
289 | case 0x1: | |
290 | printk(" - Power-up reset\n"); | |
291 | break; | |
292 | case 0x2: | |
293 | printk(" - Push-button reset\n"); | |
294 | break; | |
295 | case 0x4: | |
296 | printk(" - cPCI bus reset\n"); | |
297 | break; | |
298 | case 0x8: | |
299 | printk(" - Watchdog reset\n"); | |
300 | break; | |
301 | case 0x10: | |
302 | printk(" - Software reset\n"); | |
303 | break; | |
304 | default: | |
305 | printk(" - Unknown reset cause\n"); | |
306 | } | |
307 | reset_reason = tmpword; | |
308 | OCELOT_FPGA_WRITE(0xff, RESET_STATUS); | |
309 | ||
310 | tmpword = OCELOT_FPGA_READ(CPCI_ID); | |
311 | printk("cPCI ID register: 0x%02x\n", tmpword); | |
312 | printk(" - Slot number: %d\n", tmpword & 0x1f); | |
313 | printk(" - PCI bus present: %s\n", tmpword & 0x40 ? "yes" : "no"); | |
314 | printk(" - System Slot: %s\n", tmpword & 0x20 ? "yes" : "no"); | |
315 | ||
316 | tmpword = OCELOT_FPGA_READ(BOARD_STATUS); | |
317 | printk("Board Status register: 0x%02x\n", tmpword); | |
318 | printk(" - User jumper: %s\n", (tmpword & 0x80)?"installed":"absent"); | |
319 | printk(" - Boot flash write jumper: %s\n", (tmpword&0x40)?"installed":"absent"); | |
320 | printk(" - L3 Cache size: %d MiB\n", (1<<((tmpword&12) >> 2))&~1); | |
321 | printk(" - SDRAM size: %d MiB\n", 1<<(6+(tmpword&3))); | |
322 | ||
323 | switch(tmpword &3) { | |
324 | case 3: | |
325 | /* 512MiB */ | |
326 | add_memory_region(0x0, 0x200<<20, BOOT_MEM_RAM); | |
327 | break; | |
328 | case 2: | |
329 | /* 256MiB */ | |
330 | add_memory_region(0x0, 0x100<<20, BOOT_MEM_RAM); | |
331 | break; | |
332 | case 1: | |
333 | /* 128MiB */ | |
334 | add_memory_region(0x0, 0x80<<20, BOOT_MEM_RAM); | |
335 | break; | |
336 | case 0: | |
337 | /* 1GiB -- needs CONFIG_HIGHMEM */ | |
338 | add_memory_region(0x0, 0x400<<20, BOOT_MEM_RAM); | |
339 | break; | |
340 | } | |
341 | } | |
342 | ||
875d43e7 | 343 | #ifndef CONFIG_64BIT |
1da177e4 LT |
344 | /* This needs to be one of the first initcalls, because no I/O port access |
345 | can work before this */ | |
346 | static int io_base_ioremap(void) | |
347 | { | |
348 | /* we're mapping PCI accesses from 0xc0000000 to 0xf0000000 */ | |
349 | void *io_remap_range = ioremap(0xc0000000, 0x30000000); | |
350 | ||
351 | if (!io_remap_range) { | |
352 | panic("Could not ioremap I/O port range"); | |
353 | } | |
354 | printk("io_remap_range set at 0x%08x\n", (uint32_t)io_remap_range); | |
355 | set_io_port_base(io_remap_range - 0xc0000000); | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
360 | module_init(io_base_ioremap); | |
361 | #endif |