Merge branch 'master' of git://git.denx.de/u-boot-arm
[platform/kernel/u-boot.git] / examples / standalone / smc911x_eeprom.c
1 /*
2  * smc911x_eeprom.c - EEPROM interface to SMC911x parts.
3  * Only tested on SMSC9118 though ...
4  *
5  * Copyright 2004-2008 Analog Devices Inc.
6  *
7  * Licensed under the GPL-2 or later.
8  *
9  * Based on smc91111_eeprom.c which:
10  * Heavily borrowed from the following peoples GPL'ed software:
11  *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de
12  *       Das U-boot
13  *  - Ladislav Michl ladis@linux-mips.org
14  *       A rejected patch on the U-Boot mailing list
15  */
16
17 #include <common.h>
18 #include <exports.h>
19
20 #ifdef CONFIG_DRIVER_SMC911X
21
22 #include "../drivers/net/smc911x.h"
23
24 /**
25  *      smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?)
26  */
27 static int smsc_ctrlc(void)
28 {
29         return (tstc() && getc() == 0x03);
30 }
31
32 /**
33  *      usage - dump usage information
34  */
35 static void usage(void)
36 {
37         puts(
38                 "MAC/EEPROM Commands:\n"
39                 " P : Print the MAC addresses\n"
40                 " D : Dump the EEPROM contents\n"
41                 " M : Dump the MAC contents\n"
42                 " C : Copy the MAC address from the EEPROM to the MAC\n"
43                 " W : Write a register in the EEPROM or in the MAC\n"
44                 " Q : Quit\n"
45                 "\n"
46                 "Some commands take arguments:\n"
47                 " W <E|M> <register> <value>\n"
48                 "    E: EEPROM   M: MAC\n"
49         );
50 }
51
52 /**
53  *      dump_regs - dump the MAC registers
54  *
55  * Registers 0x00 - 0x50 are FIFOs.  The 0x50+ are the control registers
56  * and they're all 32bits long.  0xB8+ are reserved, so don't bother.
57  */
58 static void dump_regs(void)
59 {
60         u8 i, j = 0;
61         for (i = 0x50; i < 0xB8; i += sizeof(u32))
62                 printf("%02x: 0x%08x %c", i,
63                         smc911x_reg_read(CONFIG_DRIVER_SMC911X_BASE + i),
64                         (j++ % 2 ? '\n' : ' '));
65 }
66
67 /**
68  *      do_eeprom_cmd - handle eeprom communication
69  */
70 static int do_eeprom_cmd(int cmd, u8 reg)
71 {
72         if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) {
73                 printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
74                         smc911x_reg_read(E2P_CMD));
75                 return -1;
76         }
77
78         smc911x_reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
79
80         while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
81                 if (smsc_ctrlc()) {
82                         printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
83                                 smc911x_reg_read(E2P_CMD));
84                         return -1;
85                 }
86
87         return 0;
88 }
89
90 /**
91  *      read_eeprom_reg - read specified register in EEPROM
92  */
93 static u8 read_eeprom_reg(u8 reg)
94 {
95         int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg);
96         return (ret ? : smc911x_reg_read(E2P_DATA));
97 }
98
99 /**
100  *      write_eeprom_reg - write specified value into specified register in EEPROM
101  */
102 static int write_eeprom_reg(u8 value, u8 reg)
103 {
104         int ret;
105
106         /* enable erasing/writing */
107         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWEN, reg);
108         if (ret)
109                 goto done;
110
111         /* erase the eeprom reg */
112         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_ERASE, reg);
113         if (ret)
114                 goto done;
115
116         /* write the eeprom reg */
117         smc911x_reg_write(E2P_DATA, value);
118         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg);
119         if (ret)
120                 goto done;
121
122         /* disable erasing/writing */
123         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWDS, reg);
124
125  done:
126         return ret;
127 }
128
129 /**
130  *      skip_space - find first non-whitespace in given pointer
131  */
132 static char *skip_space(char *buf)
133 {
134         while (buf[0] == ' ' || buf[0] == '\t')
135                 ++buf;
136         return buf;
137 }
138
139 /**
140  *      write_stuff - handle writing of MAC registers / eeprom
141  */
142 static void write_stuff(char *line)
143 {
144         char dest;
145         char *endp;
146         u8 reg;
147         u32 value;
148
149         /* Skip over the "W " part of the command */
150         line = skip_space(line + 1);
151
152         /* Figure out destination */
153         switch (line[0]) {
154         case 'E':
155         case 'M':
156                 dest = line[0];
157                 break;
158         default:
159         invalid_usage:
160                 printf("ERROR: Invalid write usage\n");
161                 usage();
162                 return;
163         }
164
165         /* Get the register to write */
166         line = skip_space(line + 1);
167         reg = simple_strtoul(line, &endp, 16);
168         if (line == endp)
169                 goto invalid_usage;
170
171         /* Get the value to write */
172         line = skip_space(endp);
173         value = simple_strtoul(line, &endp, 16);
174         if (line == endp)
175                 goto invalid_usage;
176
177         /* Check for trailing cruft */
178         line = skip_space(endp);
179         if (line[0])
180                 goto invalid_usage;
181
182         /* Finally, execute the command */
183         if (dest == 'E') {
184                 printf("Writing EEPROM register %02x with %02x\n", reg, value);
185                 write_eeprom_reg(value, reg);
186         } else {
187                 printf("Writing MAC register %02x with %08x\n", reg, value);
188                 smc911x_reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value);
189         }
190 }
191
192 /**
193  *      copy_from_eeprom - copy MAC address in eeprom to address registers
194  */
195 static void copy_from_eeprom(void)
196 {
197         ulong addrl =
198                 read_eeprom_reg(0x01) |
199                 read_eeprom_reg(0x02) << 8 |
200                 read_eeprom_reg(0x03) << 16 |
201                 read_eeprom_reg(0x04) << 24;
202         ulong addrh =
203                 read_eeprom_reg(0x05) |
204                 read_eeprom_reg(0x06) << 8;
205         smc911x_set_mac_csr(ADDRL, addrl);
206         smc911x_set_mac_csr(ADDRH, addrh);
207         puts("EEPROM contents copied to MAC\n");
208 }
209
210 /**
211  *      print_macaddr - print MAC address registers and MAC address in eeprom
212  */
213 static void print_macaddr(void)
214 {
215         puts("Current MAC Address in MAC:     ");
216         ulong addrl = smc911x_get_mac_csr(ADDRL);
217         ulong addrh = smc911x_get_mac_csr(ADDRH);
218         printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
219                 (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16),
220                 (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8));
221
222         puts("Current MAC Address in EEPROM:  ");
223         int i;
224         for (i = 1; i < 6; ++i)
225                 printf("%02x:", read_eeprom_reg(i));
226         printf("%02x\n", read_eeprom_reg(i));
227 }
228
229 /**
230  *      dump_eeprom - dump the whole content of the EEPROM
231  */
232 static void dump_eeprom(void)
233 {
234         int i;
235         puts("EEPROM:\n");
236         for (i = 0; i < 7; ++i)
237                 printf("%02x: 0x%02x\n", i, read_eeprom_reg(i));
238 }
239
240 /**
241  *      smc911x_init - get the MAC/EEPROM up and ready for use
242  */
243 static int smc911x_init(void)
244 {
245         /* See if there is anything there */
246         if (!smc911x_detect_chip())
247                 return 1;
248
249         smc911x_reset();
250
251         /* Make sure we set EEDIO/EECLK to the EEPROM */
252         if (smc911x_reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) {
253                 while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
254                         if (smsc_ctrlc()) {
255                                 printf("init: timeout (E2P_CMD = 0x%08x)\n",
256                                         smc911x_reg_read(E2P_CMD));
257                                 return 1;
258                         }
259                 smc911x_reg_write(GPIO_CFG, smc911x_reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
260         }
261
262         return 0;
263 }
264
265 /**
266  *      getline - consume a line of input and handle some escape sequences
267  */
268 static char *getline(void)
269 {
270         static char buffer[100];
271         char c;
272         size_t i;
273
274         i = 0;
275         while (1) {
276                 buffer[i] = '\0';
277                 while (!tstc())
278                         continue;
279
280                 c = getc();
281                 /* Convert to uppercase */
282                 if (c >= 'a' && c <= 'z')
283                         c -= ('a' - 'A');
284
285                 switch (c) {
286                 case '\r':      /* Enter/Return key */
287                 case '\n':
288                         puts("\n");
289                         return buffer;
290
291                 case 0x03:      /* ^C - break */
292                         return NULL;
293
294                 case 0x5F:
295                 case 0x08:      /* ^H  - backspace */
296                 case 0x7F:      /* DEL - backspace */
297                         if (i) {
298                                 puts("\b \b");
299                                 i--;
300                         }
301                         break;
302
303                 default:
304                         /* Ignore control characters */
305                         if (c < 0x20)
306                                 break;
307                         /* Queue up all other characters */
308                         buffer[i++] = c;
309                         printf("%c", c);
310                         break;
311                 }
312         }
313 }
314
315 /**
316  *      smc911x_eeprom - our application's main() function
317  */
318 int smc911x_eeprom(int argc, char *argv[])
319 {
320         /* Print the ABI version */
321         app_startup(argv);
322         if (XF_VERSION != get_version()) {
323                 printf("Expects ABI version %d\n", XF_VERSION);
324                 printf("Actual U-Boot ABI version %lu\n", get_version());
325                 printf("Can't run\n\n");
326                 return 1;
327         }
328
329         /* Initialize the MAC/EEPROM somewhat */
330         puts("\n");
331         if (smc911x_init())
332                 return 1;
333
334         /* Dump helpful usage information */
335         puts("\n");
336         usage();
337         puts("\n");
338
339         while (1) {
340                 char *line;
341
342                 /* Send the prompt and wait for a line */
343                 puts("eeprom> ");
344                 line = getline();
345
346                 /* Got a ctrl+c */
347                 if (!line)
348                         return 0;
349
350                 /* Eat leading space */
351                 line = skip_space(line);
352
353                 /* Empty line, try again */
354                 if (!line[0])
355                         continue;
356
357                 /* Only accept 1 letter commands */
358                 if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
359                         goto unknown_cmd;
360
361                 /* Now parse the command */
362                 switch (line[0]) {
363                 case 'W': write_stuff(line);  break;
364                 case 'D': dump_eeprom();      break;
365                 case 'M': dump_regs();        break;
366                 case 'C': copy_from_eeprom(); break;
367                 case 'P': print_macaddr();    break;
368                 unknown_cmd:
369                 default:  puts("ERROR: Unknown command!\n\n");
370                 case '?':
371                 case 'H': usage();            break;
372                 case 'Q': return 0;
373                 }
374         }
375 }
376
377 #else
378 int smc911x_eeprom(int argc, char *argv[])
379 {
380         puts("Not supported for this board\n");
381         return 1;
382 }
383 #endif