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