]> git.sur5r.net Git - u-boot/blob - examples/smc911x_eeprom.c
smc911x_eeprom: new example app for managing newer SMC parts
[u-boot] / examples / 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, reg_read(CONFIG_DRIVER_SMC911X_BASE + i),
63                         (j++ % 2 ? '\n' : ' '));
64 }
65
66 /**
67  *      do_eeprom_cmd - handle eeprom communication
68  */
69 static int do_eeprom_cmd(int cmd, u8 reg)
70 {
71         if (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) {
72                 printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
73                         reg_read(E2P_CMD));
74                 return -1;
75         }
76
77         reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
78
79         while (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
80                 if (smsc_ctrlc()) {
81                         printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
82                                 reg_read(E2P_CMD));
83                         return -1;
84                 }
85
86         return 0;
87 }
88
89 /**
90  *      read_eeprom_reg - read specified register in EEPROM
91  */
92 static u8 read_eeprom_reg(u8 reg)
93 {
94         int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg);
95         return (ret ? : reg_read(E2P_DATA));
96 }
97
98 /**
99  *      write_eeprom_reg - write specified value into specified register in EEPROM
100  */
101 static int write_eeprom_reg(u8 value, u8 reg)
102 {
103         int ret;
104
105         /* enable erasing/writing */
106         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWEN, reg);
107         if (ret)
108                 goto done;
109
110         /* erase the eeprom reg */
111         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_ERASE, reg);
112         if (ret)
113                 goto done;
114
115         /* write the eeprom reg */
116         reg_write(E2P_DATA, value);
117         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg);
118         if (ret)
119                 goto done;
120
121         /* disable erasing/writing */
122         ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWDS, reg);
123
124  done:
125         return ret;
126 }
127
128 /**
129  *      skip_space - find first non-whitespace in given pointer
130  */
131 static char *skip_space(char *buf)
132 {
133         while (buf[0] == ' ' || buf[0] == '\t')
134                 ++buf;
135         return buf;
136 }
137
138 /**
139  *      write_stuff - handle writing of MAC registers / eeprom
140  */
141 static void write_stuff(char *line)
142 {
143         char dest;
144         char *endp;
145         u8 reg;
146         u32 value;
147
148         /* Skip over the "W " part of the command */
149         line = skip_space(line + 1);
150
151         /* Figure out destination */
152         switch (line[0]) {
153         case 'E':
154         case 'M':
155                 dest = line[0];
156                 break;
157         default:
158         invalid_usage:
159                 printf("ERROR: Invalid write usage\n");
160                 usage();
161                 return;
162         }
163
164         /* Get the register to write */
165         line = skip_space(line + 1);
166         reg = simple_strtoul(line, &endp, 16);
167         if (line == endp)
168                 goto invalid_usage;
169
170         /* Get the value to write */
171         line = skip_space(endp);
172         value = simple_strtoul(line, &endp, 16);
173         if (line == endp)
174                 goto invalid_usage;
175
176         /* Check for trailing cruft */
177         line = skip_space(endp);
178         if (line[0])
179                 goto invalid_usage;
180
181         /* Finally, execute the command */
182         if (dest == 'E') {
183                 printf("Writing EEPROM register %02x with %02x\n", reg, value);
184                 write_eeprom_reg(value, reg);
185         } else {
186                 printf("Writing MAC register %02x with %08x\n", reg, value);
187                 reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value);
188         }
189 }
190
191 /**
192  *      copy_from_eeprom - copy MAC address in eeprom to address registers
193  */
194 static void copy_from_eeprom(void)
195 {
196         ulong addrl =
197                 read_eeprom_reg(0x01) |
198                 read_eeprom_reg(0x02) << 8 |
199                 read_eeprom_reg(0x03) << 16 |
200                 read_eeprom_reg(0x04) << 24;
201         ulong addrh =
202                 read_eeprom_reg(0x05) |
203                 read_eeprom_reg(0x06) << 8;
204         smc911x_set_mac_csr(ADDRL, addrl);
205         smc911x_set_mac_csr(ADDRH, addrh);
206         puts("EEPROM contents copied to MAC\n");
207 }
208
209 /**
210  *      print_macaddr - print MAC address registers and MAC address in eeprom
211  */
212 static void print_macaddr(void)
213 {
214         puts("Current MAC Address in MAC:     ");
215         ulong addrl = smc911x_get_mac_csr(ADDRL);
216         ulong addrh = smc911x_get_mac_csr(ADDRH);
217         printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
218                 (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16),
219                 (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8));
220
221         puts("Current MAC Address in EEPROM:  ");
222         int i;
223         for (i = 1; i < 6; ++i)
224                 printf("%02x:", read_eeprom_reg(i));
225         printf("%02x\n", read_eeprom_reg(i));
226 }
227
228 /**
229  *      dump_eeprom - dump the whole content of the EEPROM
230  */
231 static void dump_eeprom(void)
232 {
233         int i;
234         puts("EEPROM:\n");
235         for (i = 0; i < 7; ++i)
236                 printf("%02x: 0x%02x\n", i, read_eeprom_reg(i));
237 }
238
239 /**
240  *      smc911x_init - get the MAC/EEPROM up and ready for use
241  */
242 static int smc911x_init(void)
243 {
244         /* See if there is anything there */
245         if (!smc911x_detect_chip())
246                 return 1;
247
248         smc911x_reset();
249
250         /* Make sure we set EEDIO/EECLK to the EEPROM */
251         if (reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) {
252                 while (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
253                         if (smsc_ctrlc()) {
254                                 printf("init: timeout (E2P_CMD = 0x%08x)\n", reg_read(E2P_CMD));
255                                 return 1;
256                         }
257                 reg_write(GPIO_CFG, reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
258         }
259
260         return 0;
261 }
262
263 /**
264  *      getline - consume a line of input and handle some escape sequences
265  */
266 static char *getline(void)
267 {
268         static char buffer[100];
269         char c;
270         size_t i;
271
272         i = 0;
273         while (1) {
274                 buffer[i] = '\0';
275                 while (!tstc())
276                         continue;
277
278                 c = getc();
279                 /* Convert to uppercase */
280                 if (c >= 'a' && c <= 'z')
281                         c -= ('a' - 'A');
282
283                 switch (c) {
284                 case '\r':      /* Enter/Return key */
285                 case '\n':
286                         puts("\n");
287                         return buffer;
288
289                 case 0x03:      /* ^C - break */
290                         return NULL;
291
292                 case 0x5F:
293                 case 0x08:      /* ^H  - backspace */
294                 case 0x7F:      /* DEL - backspace */
295                         if (i) {
296                                 puts("\b \b");
297                                 i--;
298                         }
299                         break;
300
301                 default:
302                         /* Ignore control characters */
303                         if (c < 0x20)
304                                 break;
305                         /* Queue up all other characters */
306                         buffer[i++] = c;
307                         printf("%c", c);
308                         break;
309                 }
310         }
311 }
312
313 /**
314  *      smc911x_eeprom - our application's main() function
315  */
316 int smc911x_eeprom(int argc, char *argv[])
317 {
318         /* Print the ABI version */
319         app_startup(argv);
320         if (XF_VERSION != get_version()) {
321                 printf("Expects ABI version %d\n", XF_VERSION);
322                 printf("Actual U-Boot ABI version %lu\n", get_version());
323                 printf("Can't run\n\n");
324                 return 1;
325         }
326
327         /* Initialize the MAC/EEPROM somewhat */
328         puts("\n");
329         if (smc911x_init())
330                 return 1;
331
332         /* Dump helpful usage information */
333         puts("\n");
334         usage();
335         puts("\n");
336
337         while (1) {
338                 char *line;
339
340                 /* Send the prompt and wait for a line */
341                 puts("eeprom> ");
342                 line = getline();
343
344                 /* Got a ctrl+c */
345                 if (!line)
346                         return 0;
347
348                 /* Eat leading space */
349                 line = skip_space(line);
350
351                 /* Empty line, try again */
352                 if (!line[0])
353                         continue;
354
355                 /* Only accept 1 letter commands */
356                 if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
357                         goto unknown_cmd;
358
359                 /* Now parse the command */
360                 switch (line[0]) {
361                 case 'W': write_stuff(line);  break;
362                 case 'D': dump_eeprom();      break;
363                 case 'M': dump_regs();        break;
364                 case 'C': copy_from_eeprom(); break;
365                 case 'P': print_macaddr();    break;
366                 unknown_cmd:
367                 default:  puts("ERROR: Unknown command!\n\n");
368                 case '?':
369                 case 'H': usage();            break;
370                 case 'Q': return 0;
371                 }
372         }
373 }
374
375 #else
376 int smc911x_eeprom(int argc, char *argv[])
377 {
378         puts("Not supported for this board\n");
379         return 1;
380 }
381 #endif