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 char arcs_cmdline[CL_SIZE];
42 
43 extern unsigned long mv64340_base;
44 extern unsigned long cpu_clock;
45 
46 #ifdef CONFIG_MV64340_ETH
47 extern unsigned char prom_mac_addr_base[6];
48 #endif
49 
get_system_type(void)50 const char *get_system_type(void)
51 {
52 #ifdef CONFIG_CPU_SR71000
53 	return "Momentum Ocelot-CS";
54 #else
55 	return "Momentum Ocelot-C";
56 #endif
57 }
58 
59 #ifdef CONFIG_MV64340_ETH
burn_clocks(void)60 static void burn_clocks(void)
61 {
62 	int i;
63 
64 	/* this loop should burn at least 1us -- this should be plenty */
65 	for (i = 0; i < 0x10000; i++)
66 		;
67 }
68 
exchange_bit(u8 val,u8 cs)69 static u8 exchange_bit(u8 val, u8 cs)
70 {
71 	/* place the data */
72 	OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
73 	burn_clocks();
74 
75 	/* turn the clock on */
76 	OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
77 	burn_clocks();
78 
79 	/* turn the clock off and read-strobe */
80 	OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
81 
82 	/* return the data */
83 	return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
84 }
85 
get_mac(char dest[6])86 void get_mac(char dest[6])
87 {
88 	u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
89 	int i,j;
90 
91 	for (i = 0; i < 12; i++)
92 		exchange_bit(read_opcode[i], 1);
93 
94 	for (j = 0; j < 6; j++) {
95 		dest[j] = 0;
96 		for (i = 0; i < 8; i++) {
97 			dest[j] <<= 1;
98 			dest[j] |= exchange_bit(0, 1);
99 		}
100 	}
101 
102 	/* turn off CS */
103 	exchange_bit(0,0);
104 }
105 #endif
106 
107 
108 #ifdef CONFIG_MIPS64
109 
signext(unsigned long addr)110 unsigned long signext(unsigned long addr)
111 {
112   addr &= 0xffffffff;
113   return (unsigned long)((int)addr);
114 }
115 
get_arg(unsigned long args,int arc)116 void *get_arg(unsigned long args, int arc)
117 {
118   unsigned long ul;
119   unsigned char *puc, uc;
120 
121   args += (arc * 4);
122   ul = (unsigned long)signext(args);
123   puc = (unsigned char *)ul;
124   if (puc == 0)
125     return (void *)0;
126 
127 #ifdef CONFIG_CPU_LITTLE_ENDIAN
128   uc = *puc++;
129   ul = (unsigned long)uc;
130   uc = *puc++;
131   ul |= (((unsigned long)uc) << 8);
132   uc = *puc++;
133   ul |= (((unsigned long)uc) << 16);
134   uc = *puc++;
135   ul |= (((unsigned long)uc) << 24);
136 #else  /* CONFIG_CPU_LITTLE_ENDIAN */
137   uc = *puc++;
138   ul = ((unsigned long)uc) << 24;
139   uc = *puc++;
140   ul |= (((unsigned long)uc) << 16);
141   uc = *puc++;
142   ul |= (((unsigned long)uc) << 8);
143   uc = *puc++;
144   ul |= ((unsigned long)uc);
145 #endif  /* CONFIG_CPU_LITTLE_ENDIAN */
146   ul = signext(ul);
147   return (void *)ul;
148 }
149 
arg64(unsigned long addrin,int arg_index)150 char *arg64(unsigned long addrin, int arg_index)
151 {
152   unsigned long args;
153   char *p;
154   args = signext(addrin);
155   p = (char *)get_arg(args, arg_index);
156   return p;
157 }
158 #endif  /* CONFIG_MIPS64 */
159 
160 
161 /* [jsun@junsun.net] PMON passes arguments in C main() style */
prom_init(int argc,char ** arg,char ** env,struct callvectors * cv)162 void __init prom_init(int argc, char **arg, char** env, struct callvectors *cv)
163 {
164 	int i;
165 #ifdef CONFIG_MIPS64
166 	char *ptr;
167 
168 	printk("prom_init - MIPS64\n");
169 	/* save the PROM vectors for debugging use */
170 	debug_vectors = (struct callvectors *)signext((unsigned long)cv);
171 
172 	/* arg[0] is "g", the rest is boot parameters */
173 	arcs_cmdline[0] = '\0';
174 
175 	for (i = 1; i < argc; i++) {
176 		ptr = (char *)arg64((unsigned long)arg, i);
177 		if ((strlen(arcs_cmdline) + strlen(ptr) + 1) >=
178 		    sizeof(arcs_cmdline))
179 			break;
180 		strcat(arcs_cmdline, ptr);
181 		strcat(arcs_cmdline, " ");
182 	}
183 	i = 0;
184 	while (1) {
185 		ptr = (char *)arg64((unsigned long)env, i);
186 		if (! ptr)
187 			break;
188 
189 		if (strncmp("gtbase", ptr, strlen("gtbase")) == 0) {
190 			mv64340_base = simple_strtol(ptr + strlen("gtbase="),
191 							NULL, 16);
192 
193 			if ((mv64340_base & 0xffffffff00000000) == 0)
194 				mv64340_base |= 0xffffffff00000000;
195 
196 			printk("mv64340_base set to 0x%016lx\n", mv64340_base);
197 		}
198 		if (strncmp("cpuclock", ptr, strlen("cpuclock")) == 0) {
199 			cpu_clock = simple_strtol(ptr + strlen("cpuclock="),
200 							NULL, 10);
201 			printk("cpu_clock set to %d\n", cpu_clock);
202 		}
203 		i++;
204 	}
205 	printk("arcs_cmdline: %s\n", arcs_cmdline);
206 
207 #else   /* CONFIG_MIPS64 */
208 	/* save the PROM vectors for debugging use */
209 	debug_vectors = cv;
210 
211 	/* arg[0] is "g", the rest is boot parameters */
212 	arcs_cmdline[0] = '\0';
213 	for (i = 1; i < argc; i++) {
214 		if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
215 		    >= sizeof(arcs_cmdline))
216 			break;
217 		strcat(arcs_cmdline, arg[i]);
218 		strcat(arcs_cmdline, " ");
219 	}
220 
221 	while (*env) {
222 		if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
223 			mv64340_base = simple_strtol(*env + strlen("gtbase="),
224 							NULL, 16);
225 		}
226 		if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) {
227 			cpu_clock = simple_strtol(*env + strlen("cpuclock="),
228 							NULL, 10);
229 		}
230 		env++;
231 	}
232 #endif /* CONFIG_MIPS64 */
233 
234 	mips_machgroup = MACH_GROUP_MOMENCO;
235 	mips_machtype = MACH_MOMENCO_OCELOT_C;
236 
237 #ifdef CONFIG_MV64340_ETH
238 	/* get the base MAC address for on-board ethernet ports */
239 	get_mac(prom_mac_addr_base);
240 #endif
241 
242 #ifndef CONFIG_MIPS64
243 	debug_vectors->printf("Booting Linux kernel...\n");
244 #endif
245 }
246 
prom_free_prom_memory(void)247 void __init prom_free_prom_memory(void)
248 {
249 }
250 
prom_fixup_mem_map(unsigned long start,unsigned long end)251 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
252 {
253 }
254