1 /* 2 * (C) Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering 3 * 4 * Copyright 2005, Seagate Technology LLC 5 * 6 * See file CREDITS for list of people who contributed to this 7 * project. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 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 */ 24 25 #undef DEBUG 26 27 #include <common.h> 28 #include <command.h> 29 #include <config.h> 30 #include <net.h> 31 32 #include "vct.h" 33 34 #define SMSC9118_BASE CONFIG_DRIVER_SMC911X_BASE 35 #define BYTE_TEST (SMSC9118_BASE + 0x64) 36 #define GPIO_CFG (SMSC9118_BASE + 0x88) 37 #define MAC_CSR_CMD (SMSC9118_BASE + 0xA4) 38 #define MAC_CSR_CMD_CSR_BUSY (0x80000000) 39 #define MAC_CSR_CMD_RNW (0x40000000) 40 #define MAC_RD_CMD(reg) ((reg & 0x000000FF) | \ 41 (MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_RNW)) 42 #define MAC_WR_CMD(reg) ((reg & 0x000000FF) | \ 43 (MAC_CSR_CMD_CSR_BUSY)) 44 #define MAC_CSR_DATA (SMSC9118_BASE + 0xA8) 45 #define E2P_CMD (SMSC9118_BASE + 0xB0) 46 #define E2P_CMD_EPC_BUSY_ (0x80000000UL) /* Self Clearing */ 47 #define E2P_CMD_EPC_CMD_ (0x70000000UL) /* R/W */ 48 #define E2P_CMD_EPC_CMD_READ_ (0x00000000UL) /* R/W */ 49 #define E2P_CMD_EPC_CMD_EWDS_ (0x10000000UL) /* R/W */ 50 #define E2P_CMD_EPC_CMD_EWEN_ (0x20000000UL) /* R/W */ 51 #define E2P_CMD_EPC_CMD_WRITE_ (0x30000000UL) /* R/W */ 52 #define E2P_CMD_EPC_CMD_WRAL_ (0x40000000UL) /* R/W */ 53 #define E2P_CMD_EPC_CMD_ERASE_ (0x50000000UL) /* R/W */ 54 #define E2P_CMD_EPC_CMD_ERAL_ (0x60000000UL) /* R/W */ 55 #define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000UL) /* R/W */ 56 #define E2P_CMD_EPC_TIMEOUT_ (0x00000200UL) /* R */ 57 #define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100UL) /* RO */ 58 #define E2P_CMD_EPC_ADDR_ (0x000000FFUL) /* R/W */ 59 #define E2P_DATA (SMSC9118_BASE + 0xB4) 60 61 #define MAC_ADDRH (0x2) 62 #define MAC_ADDRL (0x3) 63 64 #define MAC_TIMEOUT 200 65 66 #define HIBYTE(word) ((u8)(((u16)(word)) >> 8)) 67 #define LOBYTE(word) ((u8)(((u16)(word)) & 0x00FFU)) 68 #define HIWORD(dword) ((u16)(((u32)(dword)) >> 16)) 69 #define LOWORD(dword) ((u16)(((u32)(dword)) & 0x0000FFFFUL)) 70 71 static int mac_busy(int req_to) 72 { 73 int timeout = req_to; 74 75 while (timeout--) { 76 if (!(smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)) 77 goto done; 78 } 79 return 1; /* Timeout */ 80 81 done: 82 return 0; /* No timeout */ 83 } 84 85 static ulong get_mac_reg(int reg) 86 { 87 ulong reg_val = 0xffffffff; 88 89 if (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) { 90 printf("get_mac_reg: previous command not complete\n"); 91 goto done; 92 } 93 94 smc911x_reg_write(MAC_CSR_CMD, MAC_RD_CMD(reg)); 95 udelay(10000); 96 97 if (mac_busy(MAC_TIMEOUT) == 1) { 98 printf("get_mac_reg: timeout waiting for response from MAC\n"); 99 goto done; 100 } 101 102 reg_val = smc911x_reg_read(MAC_CSR_DATA); 103 104 done: 105 return (reg_val); 106 } 107 108 static ulong eeprom_enable_access(void) 109 { 110 ulong gpio; 111 112 gpio = smc911x_reg_read(GPIO_CFG); 113 debug("%s: gpio= 0x%08lx ---> 0x%08lx\n", __func__, gpio, 114 (gpio & 0xFF0FFFFFUL)); 115 116 smc911x_reg_write(GPIO_CFG, (gpio & 0xFF0FFFFFUL)); 117 return gpio; 118 } 119 120 static void eeprom_disable_access(ulong gpio) 121 { 122 debug("%s: gpio= 0x%08lx\n", __func__, gpio); 123 smc911x_reg_write(GPIO_CFG, gpio); 124 } 125 126 static int eeprom_is_mac_address_loaded(void) 127 { 128 int ret; 129 130 ret = smc911x_reg_read(MAC_CSR_CMD) & E2P_CMD_MAC_ADDR_LOADED_; 131 debug("%s: ret = %x\n", __func__, ret); 132 133 return ret; 134 } 135 136 static int eeprom_read_location(unchar address, u8 *data) 137 { 138 ulong timeout = 100000; 139 ulong temp = 0; 140 141 if ((temp = smc911x_reg_read(E2P_CMD)) & E2P_CMD_EPC_BUSY_) { 142 printf("%s: Busy at start, E2P_CMD=0x%08lX\n", __func__, temp); 143 return 0; 144 } 145 146 smc911x_reg_write(E2P_CMD, 147 (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_ | 148 ((ulong) address))); 149 150 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 151 udelay(10); 152 timeout--; 153 } 154 155 if (timeout == 0) { 156 printf("Timeout\n"); 157 return 0; 158 } 159 (*data) = (unchar) (smc911x_reg_read(E2P_DATA)); 160 debug("%s: ret = %x\n", __func__, (*data)); 161 162 return 1; 163 } 164 165 static int eeprom_enable_erase_and_write(void) 166 { 167 ulong timeout = 100000; 168 169 if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_) { 170 printf("%s: Busy at start\n", __func__); 171 return 0; 172 } 173 smc911x_reg_write(E2P_CMD, (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_)); 174 175 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 176 udelay(10); 177 timeout--; 178 } 179 180 if (timeout == 0) { 181 printf("Timeout[1]\n"); 182 return 0; 183 } 184 185 return 1; 186 } 187 188 static int eeprom_disable_erase_and_write(void) 189 { 190 ulong timeout = 100000; 191 192 if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_) { 193 printf("%s: Busy at start\n", __func__); 194 return 0; 195 } 196 smc911x_reg_write(E2P_CMD, (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWDS_)); 197 198 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 199 udelay(10); 200 timeout--; 201 } 202 203 if (timeout == 0) { 204 printf("Timeout[2]\n"); 205 return 0; 206 } 207 208 return 1; 209 } 210 211 static int eeprom_write_location(unchar address, unchar data) 212 { 213 ulong timeout = 100000; 214 215 debug("%s: address: %x data = %x\n", __func__, address, data); 216 217 if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_) { 218 printf("%s: Busy at start\n", __func__); 219 return 0; 220 } 221 222 smc911x_reg_write(E2P_DATA, ((ulong) data)); 223 smc911x_reg_write(E2P_CMD, 224 (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_ | 225 ((ulong) address))); 226 227 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 228 udelay(10); 229 timeout--; 230 } 231 232 if (timeout == 0) { 233 printf("Timeout[3]\n"); 234 return 0; 235 } 236 237 return 1; 238 } 239 240 static int eeprom_erase_all(void) 241 { 242 ulong timeout = 100000; 243 244 if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_) { 245 printf("%s: Busy at start\n", __func__); 246 return 0; 247 } 248 249 smc911x_reg_write(E2P_CMD, (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_ERAL_)); 250 251 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 252 udelay(10); 253 timeout--; 254 } 255 256 if (timeout == 0) { 257 printf("Timeout[4]\n"); 258 return 0; 259 } 260 261 return 1; 262 } 263 264 static int eeprom_reload(void) 265 { 266 ulong timeout = 100000; 267 268 if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_) { 269 printf("%s: Busy at start\n", __func__); 270 return -1; 271 } 272 smc911x_reg_write(E2P_CMD, 273 (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); 274 275 while ((timeout > 0) && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY_)) { 276 udelay(10); 277 timeout--; 278 } 279 280 if (timeout == 0) 281 return 0; 282 283 return 1; 284 } 285 286 static int eeprom_save_mac_address(ulong dwHi16, ulong dwLo32) 287 { 288 int result = 0; 289 290 debug("%s: dwHI: 0x%08lx dwLO: %08lx, \n", __func__, dwHi16, dwLo32); 291 292 if (!eeprom_enable_erase_and_write()) 293 goto DONE; 294 if (!eeprom_erase_all()) 295 goto DONE; 296 if (!eeprom_write_location(0, 0xA5)) 297 goto DONE; 298 if (!eeprom_write_location(1, LOBYTE(LOWORD(dwLo32)))) 299 goto DONE; 300 if (!eeprom_write_location(2, HIBYTE(LOWORD(dwLo32)))) 301 goto DONE; 302 if (!eeprom_write_location(3, LOBYTE(HIWORD(dwLo32)))) 303 goto DONE; 304 if (!eeprom_write_location(4, HIBYTE(HIWORD(dwLo32)))) 305 goto DONE; 306 if (!eeprom_write_location(5, LOBYTE(LOWORD(dwHi16)))) 307 goto DONE; 308 if (!eeprom_write_location(6, HIBYTE(LOWORD(dwHi16)))) 309 goto DONE; 310 if (!eeprom_disable_erase_and_write()) 311 goto DONE; 312 313 result = 1; 314 315 DONE: 316 return result; 317 } 318 319 static int do_eeprom_dump(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 320 { 321 unchar data = 0, index = 0; 322 ulong gpio_old_val; 323 324 gpio_old_val = eeprom_enable_access(); 325 326 printf("EEPROM content: \n"); 327 for (index = 0; index < 8; index++) { 328 if (eeprom_read_location(index, &data)) 329 printf("%02x ", data); 330 else 331 printf("FAILED"); 332 } 333 334 eeprom_disable_access(gpio_old_val); 335 printf("\n"); 336 337 return 0; 338 } 339 340 static int do_eeprom_erase_all(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 341 { 342 eeprom_erase_all(); 343 344 return 0; 345 } 346 347 static int do_eeprom_save_mac(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 348 { 349 ulong hi16, lo32; 350 unchar ethaddr[6], i; 351 ulong gpio; 352 char *tmp, *end; 353 354 tmp = argv[1]; 355 for (i = 0; i < 6; i++) { 356 ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0; 357 if (tmp) 358 tmp = (*end) ? end + 1 : end; 359 } 360 361 hi16 = (ethaddr[5] << 8) | (ethaddr[4]); 362 lo32 = (ethaddr[3] << 24) | (ethaddr[2] << 16) | 363 (ethaddr[1] << 8) | (ethaddr[0]); 364 365 gpio = eeprom_enable_access(); 366 367 eeprom_save_mac_address(hi16, lo32); 368 369 eeprom_reload(); 370 371 /* Check new values */ 372 if (eeprom_is_mac_address_loaded()) { 373 ulong mac_hi16, mac_lo32; 374 375 mac_hi16 = get_mac_reg(MAC_ADDRH); 376 mac_lo32 = get_mac_reg(MAC_ADDRL); 377 printf("New MAC address: %lx, %lx\n", mac_hi16, mac_lo32); 378 } else { 379 printf("Address is not reloaded \n"); 380 } 381 eeprom_disable_access(gpio); 382 383 return 0; 384 } 385 386 U_BOOT_CMD(smcee, 1, 0, do_eeprom_erase_all, 387 "smcee - Erase content of SMC EEPROM",); 388 389 U_BOOT_CMD(smced, 1, 0, do_eeprom_dump, 390 "smced - Dump content of SMC EEPROM",); 391 392 U_BOOT_CMD(smcew, 2, 0, do_eeprom_save_mac, 393 "smcew - Write MAC address to SMC EEPROM\n", 394 "aa:bb:cc:dd:ee:ff new mac address"); 395