1 /*
2  * (C) Copyright 2004
3  * Robin Getz rgetz@blacfin.uclinux.org
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  *
23  * Heavily borrowed from the following peoples GPL'ed software:
24  *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de
25  *       Das U-boot
26  *  - Ladislav Michl ladis@linux-mips.org
27  *       A rejected patch on the U-Boot mailing list
28  */
29 
30 #include <common.h>
31 #include <exports.h>
32 #include "../drivers/net/smc91111.h"
33 
34 #ifdef CONFIG_DRIVER_SMC91111
35 
36 #ifndef SMC91111_EEPROM_INIT
37 # define SMC91111_EEPROM_INIT()
38 #endif
39 
40 #define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE
41 #define EEPROM		0x1
42 #define MAC		0x2
43 #define UNKNOWN		0x4
44 
45 void dump_reg (void);
46 void dump_eeprom (void);
47 int write_eeprom_reg (int, int);
48 void copy_from_eeprom (void);
49 void print_MAC (void);
50 int read_eeprom_reg (int);
51 void print_macaddr (void);
52 
53 int smc91111_eeprom (int argc, char *argv[])
54 {
55 	int c, i, j, done, line, reg, value, start, what;
56 	char input[50];
57 
58 	/* Print the ABI version */
59 	app_startup (argv);
60 	if (XF_VERSION != (int) get_version ()) {
61 		printf ("Expects ABI version %d\n", XF_VERSION);
62 		printf ("Actual U-Boot ABI version %d\n",
63 			(int) get_version ());
64 		printf ("Can't run\n\n");
65 		return (0);
66 	}
67 
68 	SMC91111_EEPROM_INIT();
69 
70 	if ((SMC_inw (BANK_SELECT) & 0xFF00) != 0x3300) {
71 		printf ("Can't find SMSC91111\n");
72 		return (0);
73 	}
74 
75 	done = 0;
76 	what = UNKNOWN;
77 	printf ("\n");
78 	while (!done) {
79 		/* print the prompt */
80 		printf ("SMC91111> ");
81 		line = 0;
82 		i = 0;
83 		start = 1;
84 		while (!line) {
85 			/* Wait for a keystroke */
86 			while (!tstc ());
87 
88 			c = getc ();
89 			/* Make Uppercase */
90 			if (c >= 'Z')
91 				c -= ('a' - 'A');
92 			/* printf(" |%02x| ",c); */
93 
94 			switch (c) {
95 			case '\r':	/* Enter                */
96 			case '\n':
97 				input[i] = 0;
98 				puts ("\r\n");
99 				line = 1;
100 				break;
101 			case '\0':	/* nul                  */
102 				continue;
103 
104 			case 0x03:	/* ^C - break           */
105 				input[0] = 0;
106 				i = 0;
107 				line = 1;
108 				done = 1;
109 				break;
110 
111 			case 0x5F:
112 			case 0x08:	/* ^H  - backspace      */
113 			case 0x7F:	/* DEL - backspace      */
114 				if (i > 0) {
115 					puts ("\b \b");
116 					i--;
117 				}
118 				break;
119 			default:
120 				if (start) {
121 					if ((c == 'W') || (c == 'D')
122 					    || (c == 'M') || (c == 'C')
123 					    || (c == 'P')) {
124 						putc (c);
125 						input[i] = c;
126 						if (i <= 45)
127 							i++;
128 						start = 0;
129 					}
130 				} else {
131 					if ((c >= '0' && c <= '9')
132 					    || (c >= 'A' && c <= 'F')
133 					    || (c == 'E') || (c == 'M')
134 					    || (c == ' ')) {
135 						putc (c);
136 						input[i] = c;
137 						if (i <= 45)
138 							i++;
139 						break;
140 					}
141 				}
142 				break;
143 			}
144 		}
145 
146 		for (; i < 49; i++)
147 			input[i] = 0;
148 
149 		switch (input[0]) {
150 		case ('W'):
151 			/* Line should be w reg value */
152 			i = 0;
153 			reg = 0;
154 			value = 0;
155 			/* Skip to the next space or end) */
156 			while ((input[i] != ' ') && (input[i] != 0))
157 				i++;
158 
159 			if (input[i] != 0)
160 				i++;
161 
162 			/* Are we writing to EEPROM or MAC */
163 			switch (input[i]) {
164 			case ('E'):
165 				what = EEPROM;
166 				break;
167 			case ('M'):
168 				what = MAC;
169 				break;
170 			default:
171 				what = UNKNOWN;
172 				break;
173 			}
174 
175 			/* skip to the next space or end */
176 			while ((input[i] != ' ') && (input[i] != 0))
177 				i++;
178 			if (input[i] != 0)
179 				i++;
180 
181 			/* Find register to write into */
182 			j = 0;
183 			while ((input[i] != ' ') && (input[i] != 0)) {
184 				j = input[i] - 0x30;
185 				if (j >= 0xA) {
186 					j -= 0x07;
187 				}
188 				reg = (reg * 0x10) + j;
189 				i++;
190 			}
191 
192 			while ((input[i] != ' ') && (input[i] != 0))
193 				i++;
194 
195 			if (input[i] != 0)
196 				i++;
197 			else
198 				what = UNKNOWN;
199 
200 			/* Get the value to write */
201 			j = 0;
202 			while ((input[i] != ' ') && (input[i] != 0)) {
203 				j = input[i] - 0x30;
204 				if (j >= 0xA) {
205 					j -= 0x07;
206 				}
207 				value = (value * 0x10) + j;
208 				i++;
209 			}
210 
211 			switch (what) {
212 			case 1:
213 				printf ("Writing EEPROM register %02x with %04x\n", reg, value);
214 				write_eeprom_reg (value, reg);
215 				break;
216 			case 2:
217 				printf ("Writing MAC register bank %i, reg %02x with %04x\n", reg >> 4, reg & 0xE, value);
218 				SMC_SELECT_BANK (reg >> 4);
219 				SMC_outw (value, reg & 0xE);
220 				break;
221 			default:
222 				printf ("Wrong\n");
223 				break;
224 			}
225 			break;
226 		case ('D'):
227 			dump_eeprom ();
228 			break;
229 		case ('M'):
230 			dump_reg ();
231 			break;
232 		case ('C'):
233 			copy_from_eeprom ();
234 			break;
235 		case ('P'):
236 			print_macaddr ();
237 			break;
238 		default:
239 			break;
240 		}
241 
242 	}
243 
244 	return (0);
245 }
246 
247 void copy_from_eeprom (void)
248 {
249 	int i;
250 
251 	SMC_SELECT_BANK (1);
252 	SMC_outw ((SMC_inw (CTL_REG) & !CTL_EEPROM_SELECT) | CTL_RELOAD,
253 		  CTL_REG);
254 	i = 100;
255 	while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --i)
256 		udelay (100);
257 	if (i == 0) {
258 		printf ("Timeout Refreshing EEPROM registers\n");
259 	} else {
260 		printf ("EEPROM contents copied to MAC\n");
261 	}
262 
263 }
264 
265 void print_macaddr (void)
266 {
267 	int i, j, k, mac[6];
268 
269 	printf ("Current MAC Address in SMSC91111 ");
270 	SMC_SELECT_BANK (1);
271 	for (i = 0; i < 5; i++) {
272 		printf ("%02x:", SMC_inb (ADDR0_REG + i));
273 	}
274 
275 	printf ("%02x\n", SMC_inb (ADDR0_REG + 5));
276 
277 	i = 0;
278 	for (j = 0x20; j < 0x23; j++) {
279 		k = read_eeprom_reg (j);
280 		mac[i] = k & 0xFF;
281 		i++;
282 		mac[i] = k >> 8;
283 		i++;
284 	}
285 
286 	printf ("Current MAC Address in EEPROM    ");
287 	for (i = 0; i < 5; i++)
288 		printf ("%02x:", mac[i]);
289 	printf ("%02x\n", mac[5]);
290 
291 }
292 void dump_eeprom (void)
293 {
294 	int j, k;
295 
296 	printf ("IOS2-0    ");
297 	for (j = 0; j < 8; j++) {
298 		printf ("%03x     ", j);
299 	}
300 	printf ("\n");
301 
302 	for (k = 0; k < 4; k++) {
303 		if (k == 0)
304 			printf ("CONFIG ");
305 		if (k == 1)
306 			printf ("BASE   ");
307 		if ((k == 2) || (k == 3))
308 			printf ("       ");
309 		for (j = 0; j < 0x20; j += 4) {
310 			printf ("%02x:%04x ", j + k, read_eeprom_reg (j + k));
311 		}
312 		printf ("\n");
313 	}
314 
315 	for (j = 0x20; j < 0x40; j++) {
316 		if ((j & 0x07) == 0)
317 			printf ("\n");
318 		printf ("%02x:%04x ", j, read_eeprom_reg (j));
319 	}
320 	printf ("\n");
321 
322 }
323 
324 int read_eeprom_reg (int reg)
325 {
326 	int timeout;
327 
328 	SMC_SELECT_BANK (2);
329 	SMC_outw (reg, PTR_REG);
330 
331 	SMC_SELECT_BANK (1);
332 	SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD,
333 		  CTL_REG);
334 	timeout = 100;
335 	while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --timeout)
336 		udelay (100);
337 	if (timeout == 0) {
338 		printf ("Timeout Reading EEPROM register %02x\n", reg);
339 		return 0;
340 	}
341 
342 	return SMC_inw (GP_REG);
343 
344 }
345 
346 int write_eeprom_reg (int value, int reg)
347 {
348 	int timeout;
349 
350 	SMC_SELECT_BANK (2);
351 	SMC_outw (reg, PTR_REG);
352 
353 	SMC_SELECT_BANK (1);
354 	SMC_outw (value, GP_REG);
355 	SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG);
356 	timeout = 100;
357 	while ((SMC_inw (CTL_REG) & CTL_STORE) && --timeout)
358 		udelay (100);
359 	if (timeout == 0) {
360 		printf ("Timeout Writing EEPROM register %02x\n", reg);
361 		return 0;
362 	}
363 
364 	return 1;
365 
366 }
367 
368 void dump_reg (void)
369 {
370 	int i, j;
371 
372 	printf ("    ");
373 	for (j = 0; j < 4; j++) {
374 		printf ("Bank%i ", j);
375 	}
376 	printf ("\n");
377 	for (i = 0; i < 0xF; i += 2) {
378 		printf ("%02x  ", i);
379 		for (j = 0; j < 4; j++) {
380 			SMC_SELECT_BANK (j);
381 			printf ("%04x  ", SMC_inw (i));
382 		}
383 		printf ("\n");
384 	}
385 }
386 
387 #else
388 
389 int smc91111_eeprom (int argc, char *argv[])
390 {
391 	printf("Not supported for this board\n");
392 	return 1;
393 }
394 
395 #endif
396