Merge branch 'master' of /home/wd/git/u-boot/master
[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-2009 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 #include "../drivers/net/smc911x.h"
20
21 /**
22  *      smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?)
23  */
24 static int smsc_ctrlc(void)
25 {
26         return (tstc() && getc() == 0x03);
27 }
28
29 /**
30  *      usage - dump usage information
31  */
32 static void usage(void)
33 {
34         puts(
35                 "MAC/EEPROM Commands:\n"
36                 " P : Print the MAC addresses\n"
37                 " D : Dump the EEPROM contents\n"
38                 " M : Dump the MAC contents\n"
39                 " C : Copy the MAC address from the EEPROM to the MAC\n"
40                 " W : Write a register in the EEPROM or in the MAC\n"
41                 " Q : Quit\n"
42                 "\n"
43                 "Some commands take arguments:\n"
44                 " W <E|M> <register> <value>\n"
45                 "    E: EEPROM   M: MAC\n"
46         );
47 }
48
49 /**
50  *      dump_regs - dump the MAC registers
51  *
52  * Registers 0x00 - 0x50 are FIFOs.  The 0x50+ are the control registers
53  * and they're all 32bits long.  0xB8+ are reserved, so don't bother.
54  */
55 static void dump_regs(struct eth_device *dev)
56 {
57         u8 i, j = 0;
58         for (i = 0x50; i < 0xB8; i += sizeof(u32))
59                 printf("%02x: 0x%08x %c", i,
60                         smc911x_reg_read(dev, i),
61                         (j++ % 2 ? '\n' : ' '));
62 }
63
64 /**
65  *      do_eeprom_cmd - handle eeprom communication
66  */
67 static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg)
68 {
69         if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) {
70                 printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
71                         smc911x_reg_read(dev, E2P_CMD));
72                 return -1;
73         }
74
75         smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
76
77         while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
78                 if (smsc_ctrlc()) {
79                         printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
80                                 smc911x_reg_read(dev, E2P_CMD));
81                         return -1;
82                 }
83
84         return 0;
85 }
86
87 /**
88  *      read_eeprom_reg - read specified register in EEPROM
89  */
90 static u8 read_eeprom_reg(struct eth_device *dev, u8 reg)
91 {
92         int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg);
93         return (ret ? : smc911x_reg_read(dev, E2P_DATA));
94 }
95
96 /**
97  *      write_eeprom_reg - write specified value into specified register in EEPROM
98  */
99 static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg)
100 {
101         int ret;
102
103         /* enable erasing/writing */
104         ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg);
105         if (ret)
106                 goto done;
107
108         /* erase the eeprom reg */
109         ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg);
110         if (ret)
111                 goto done;
112
113         /* write the eeprom reg */
114         smc911x_reg_write(dev, E2P_DATA, value);
115         ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg);
116         if (ret)
117                 goto done;
118
119         /* disable erasing/writing */
120         ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWDS, reg);
121
122  done:
123         return ret;
124 }
125
126 /**
127  *      skip_space - find first non-whitespace in given pointer
128  */
129 static char *skip_space(char *buf)
130 {
131         while (buf[0] == ' ' || buf[0] == '\t')
132                 ++buf;
133         return buf;
134 }
135
136 /**
137  *      write_stuff - handle writing of MAC registers / eeprom
138  */
139 static void write_stuff(struct eth_device *dev, char *line)
140 {
141         char dest;
142         char *endp;
143         u8 reg;
144         u32 value;
145
146         /* Skip over the "W " part of the command */
147         line = skip_space(line + 1);
148
149         /* Figure out destination */
150         switch (line[0]) {
151         case 'E':
152         case 'M':
153                 dest = line[0];
154                 break;
155         default:
156         invalid_usage:
157                 printf("ERROR: Invalid write usage\n");
158                 usage();
159                 return;
160         }
161
162         /* Get the register to write */
163         line = skip_space(line + 1);
164         reg = simple_strtoul(line, &endp, 16);
165         if (line == endp)
166                 goto invalid_usage;
167
168         /* Get the value to write */
169         line = skip_space(endp);
170         value = simple_strtoul(line, &endp, 16);
171         if (line == endp)
172                 goto invalid_usage;
173
174         /* Check for trailing cruft */
175         line = skip_space(endp);
176         if (line[0])
177                 goto invalid_usage;
178
179         /* Finally, execute the command */
180         if (dest == 'E') {
181                 printf("Writing EEPROM register %02x with %02x\n", reg, value);
182                 write_eeprom_reg(dev, value, reg);
183         } else {
184                 printf("Writing MAC register %02x with %08x\n", reg, value);
185                 smc911x_reg_write(dev, reg, value);
186         }
187 }
188
189 /**
190  *      copy_from_eeprom - copy MAC address in eeprom to address registers
191  */
192 static void copy_from_eeprom(struct eth_device *dev)
193 {
194         ulong addrl =
195                 read_eeprom_reg(dev, 0x01) |
196                 read_eeprom_reg(dev, 0x02) << 8 |
197                 read_eeprom_reg(dev, 0x03) << 16 |
198                 read_eeprom_reg(dev, 0x04) << 24;
199         ulong addrh =
200                 read_eeprom_reg(dev, 0x05) |
201                 read_eeprom_reg(dev, 0x06) << 8;
202         smc911x_set_mac_csr(dev, ADDRL, addrl);
203         smc911x_set_mac_csr(dev, ADDRH, addrh);
204         puts("EEPROM contents copied to MAC\n");
205 }
206
207 /**
208  *      print_macaddr - print MAC address registers and MAC address in eeprom
209  */
210 static void print_macaddr(struct eth_device *dev)
211 {
212         puts("Current MAC Address in MAC:     ");
213         ulong addrl = smc911x_get_mac_csr(dev, ADDRL);
214         ulong addrh = smc911x_get_mac_csr(dev, ADDRH);
215         printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
216                 (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16),
217                 (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8));
218
219         puts("Current MAC Address in EEPROM:  ");
220         int i;
221         for (i = 1; i < 6; ++i)
222                 printf("%02x:", read_eeprom_reg(dev, i));
223         printf("%02x\n", read_eeprom_reg(dev, i));
224 }
225
226 /**
227  *      dump_eeprom - dump the whole content of the EEPROM
228  */
229 static void dump_eeprom(struct eth_device *dev)
230 {
231         int i;
232         puts("EEPROM:\n");
233         for (i = 0; i < 7; ++i)
234                 printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i));
235 }
236
237 /**
238  *      smc911x_init - get the MAC/EEPROM up and ready for use
239  */
240 static int smc911x_init(struct eth_device *dev)
241 {
242         /* See if there is anything there */
243         if (smc911x_detect_chip(dev))
244                 return 1;
245
246         smc911x_reset(dev);
247
248         /* Make sure we set EEDIO/EECLK to the EEPROM */
249         if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) {
250                 while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
251                         if (smsc_ctrlc()) {
252                                 printf("init: timeout (E2P_CMD = 0x%08x)\n",
253                                         smc911x_reg_read(dev, E2P_CMD));
254                                 return 1;
255                         }
256                 smc911x_reg_write(dev, GPIO_CFG,
257                         smc911x_reg_read(dev, 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 * const argv[])
317 {
318         /* Avoid initializing on stack as gcc likes to call memset() */
319         struct eth_device dev;
320         dev.iobase = CONFIG_SMC911X_BASE;
321
322         /* Print the ABI version */
323         app_startup(argv);
324         if (XF_VERSION != get_version()) {
325                 printf("Expects ABI version %d\n", XF_VERSION);
326                 printf("Actual U-Boot ABI version %lu\n", get_version());
327                 printf("Can't run\n\n");
328                 return 1;
329         }
330
331         /* Initialize the MAC/EEPROM somewhat */
332         puts("\n");
333         if (smc911x_init(&dev))
334                 return 1;
335
336         /* Dump helpful usage information */
337         puts("\n");
338         usage();
339         puts("\n");
340
341         while (1) {
342                 char *line;
343
344                 /* Send the prompt and wait for a line */
345                 puts("eeprom> ");
346                 line = getline();
347
348                 /* Got a ctrl+c */
349                 if (!line)
350                         return 0;
351
352                 /* Eat leading space */
353                 line = skip_space(line);
354
355                 /* Empty line, try again */
356                 if (!line[0])
357                         continue;
358
359                 /* Only accept 1 letter commands */
360                 if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
361                         goto unknown_cmd;
362
363                 /* Now parse the command */
364                 switch (line[0]) {
365                 case 'W': write_stuff(&dev, line); break;
366                 case 'D': dump_eeprom(&dev);       break;
367                 case 'M': dump_regs(&dev);         break;
368                 case 'C': copy_from_eeprom(&dev);  break;
369                 case 'P': print_macaddr(&dev);     break;
370                 unknown_cmd:
371                 default:  puts("ERROR: Unknown command!\n\n");
372                 case '?':
373                 case 'H': usage();            break;
374                 case 'Q': return 0;
375                 }
376         }
377 }