Merge git://git.kernel.org/pub/scm/linux/kernel/git/bunk/trivial
[linux-2.6] / arch / mips / momentum / ocelot_3 / prom.c
1 /*
2  * Copyright 2002 Momentum Computer Inc.
3  * Author: Matthew Dharm <mdharm@momenco.com>
4  *
5  * Louis Hamilton, Red Hat, Inc.
6  *   hamilton@redhat.com  [MIPS64 modifications]
7  *
8  * Copyright 2004 PMC-Sierra
9  * Author: Manish Lachwani (lachwani@pmc-sierra.com)
10  *
11  * Based on Ocelot Linux port, which is
12  * Copyright 2001 MontaVista Software Inc.
13  * Author: jsun@mvista.com or jsun@junsun.net
14  *
15  * This program is free software; you can redistribute  it and/or modify it
16  * under  the terms of  the GNU General  Public License as published by the
17  * Free Software Foundation;  either version 2 of the  License, or (at your
18  * option) any later version.
19  *
20  * Copyright (C) 2004 MontaVista Software Inc.
21  * Author: Manish Lachwani, mlachwani@mvista.com
22  *
23  */
24 #include <linux/init.h>
25 #include <linux/bootmem.h>
26 #include <linux/mv643xx.h>
27
28 #include <asm/addrspace.h>
29 #include <asm/bootinfo.h>
30 #include <asm/pmon.h>
31 #include "ocelot_3_fpga.h"
32
33 struct callvectors* debug_vectors;
34 extern unsigned long marvell_base;
35 extern unsigned long cpu_clock;
36
37 #ifdef CONFIG_MV643XX_ETH
38 extern unsigned char prom_mac_addr_base[6];
39 #endif
40
41 const char *get_system_type(void)
42 {
43         return "Momentum Ocelot-3";
44 }
45
46 #ifdef CONFIG_MV643XX_ETH
47 void burn_clocks(void)
48 {
49         int i;
50
51         /* this loop should burn at least 1us -- this should be plenty */
52         for (i = 0; i < 0x10000; i++)
53                 ;
54 }
55
56 u8 exchange_bit(u8 val, u8 cs)
57 {
58         /* place the data */
59         OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
60         burn_clocks();
61
62         /* turn the clock on */
63         OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
64         burn_clocks();
65
66         /* turn the clock off and read-strobe */
67         OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
68
69         /* return the data */
70         return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
71 }
72
73 void get_mac(char dest[6])
74 {
75         u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
76         int i,j;
77
78         for (i = 0; i < 12; i++)
79                 exchange_bit(read_opcode[i], 1);
80
81         for (j = 0; j < 6; j++) {
82                 dest[j] = 0;
83                 for (i = 0; i < 8; i++) {
84                         dest[j] <<= 1;
85                         dest[j] |= exchange_bit(0, 1);
86                 }
87         }
88
89         /* turn off CS */
90         exchange_bit(0,0);
91 }
92 #endif
93
94
95 #ifdef CONFIG_64BIT
96
97 unsigned long signext(unsigned long addr)
98 {
99         addr &= 0xffffffff;
100         return (unsigned long)((int)addr);
101 }
102
103 void *get_arg(unsigned long args, int arc)
104 {
105         unsigned long ul;
106         unsigned char *puc, uc;
107
108         args += (arc * 4);
109         ul = (unsigned long)signext(args);
110         puc = (unsigned char *)ul;
111         if (puc == 0)
112                 return (void *)0;
113
114 #ifdef CONFIG_CPU_LITTLE_ENDIAN
115         uc = *puc++;
116         ul = (unsigned long)uc;
117         uc = *puc++;
118         ul |= (((unsigned long)uc) << 8);
119         uc = *puc++;
120         ul |= (((unsigned long)uc) << 16);
121         uc = *puc++;
122         ul |= (((unsigned long)uc) << 24);
123 #else  /* CONFIG_CPU_LITTLE_ENDIAN */
124         uc = *puc++;
125         ul = ((unsigned long)uc) << 24;
126         uc = *puc++;
127         ul |= (((unsigned long)uc) << 16);
128         uc = *puc++;
129         ul |= (((unsigned long)uc) << 8);
130         uc = *puc++;
131         ul |= ((unsigned long)uc);
132 #endif  /* CONFIG_CPU_LITTLE_ENDIAN */
133         ul = signext(ul);
134         return (void *)ul;
135 }
136
137 char *arg64(unsigned long addrin, int arg_index)
138 {
139         unsigned long args;
140         char *p;
141
142         args = signext(addrin);
143         p = (char *)get_arg(args, arg_index);
144
145         return p;
146 }
147 #endif  /* CONFIG_64BIT */
148
149 void __init prom_init(void)
150 {
151         int argc = fw_arg0;
152         char **arg = (char **) fw_arg1;
153         char **env = (char **) fw_arg2;
154         struct callvectors *cv = (struct callvectors *) fw_arg3;
155         int i;
156
157 #ifdef CONFIG_64BIT
158         char *ptr;
159         printk("prom_init - MIPS64\n");
160
161         /* save the PROM vectors for debugging use */
162         debug_vectors = (struct callvectors *)signext((unsigned long)cv);
163
164         /* arg[0] is "g", the rest is boot parameters */
165         arcs_cmdline[0] = '\0';
166
167         for (i = 1; i < argc; i++) {
168                 ptr = (char *)arg64((unsigned long)arg, i);
169                 if ((strlen(arcs_cmdline) + strlen(ptr) + 1) >=
170                     sizeof(arcs_cmdline))
171                         break;
172                 strcat(arcs_cmdline, ptr);
173                 strcat(arcs_cmdline, " ");
174         }
175         i = 0;
176
177         while (1) {
178                 ptr = (char *)arg64((unsigned long)env, i);
179                 if (! ptr)
180                         break;
181
182                 if (strncmp("gtbase", ptr, strlen("gtbase")) == 0) {
183                         marvell_base = simple_strtol(ptr + strlen("gtbase="),
184                                                         NULL, 16);
185
186                         if ((marvell_base & 0xffffffff00000000) == 0)
187                                 marvell_base |= 0xffffffff00000000;
188
189                         printk("marvell_base set to 0x%016lx\n", marvell_base);
190                 }
191                 if (strncmp("cpuclock", ptr, strlen("cpuclock")) == 0) {
192                         cpu_clock = simple_strtol(ptr + strlen("cpuclock="),
193                                                         NULL, 10);
194                         printk("cpu_clock set to %d\n", cpu_clock);
195                 }
196                 i++;
197         }
198         printk("arcs_cmdline: %s\n", arcs_cmdline);
199
200 #else   /* CONFIG_64BIT */
201
202         /* save the PROM vectors for debugging use */
203         debug_vectors = cv;
204
205         /* arg[0] is "g", the rest is boot parameters */
206         arcs_cmdline[0] = '\0';
207         for (i = 1; i < argc; i++) {
208                 if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
209                     >= sizeof(arcs_cmdline))
210                         break;
211                 strcat(arcs_cmdline, arg[i]);
212                 strcat(arcs_cmdline, " ");
213         }
214
215         while (*env) {
216                 if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
217                         marvell_base = simple_strtol(*env + strlen("gtbase="),
218                                                         NULL, 16);
219                 }
220                 if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) {
221                         cpu_clock = simple_strtol(*env + strlen("cpuclock="),
222                                                         NULL, 10);
223                 }
224                 env++;
225         }
226 #endif /* CONFIG_64BIT */
227
228         mips_machgroup = MACH_GROUP_MOMENCO;
229         mips_machtype = MACH_MOMENCO_OCELOT_3;
230
231 #ifdef CONFIG_MV643XX_ETH
232         /* get the base MAC address for on-board ethernet ports */
233         get_mac(prom_mac_addr_base);
234 #endif
235
236 #ifndef CONFIG_64BIT
237         debug_vectors->printf("Booting Linux kernel...\n");
238 #endif
239 }
240
241 unsigned long __init prom_free_prom_memory(void)
242 {
243         return 0;
244 }
245
246 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
247 {
248 }