/* * (C) Copyright 2015 * Alexander Couzens, lynxis@fe80.eu * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #ifdef CFG_CMD_SETMAC #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #define SERIAL_LOCATION 0x20 extern flash_info_t flash_info[]; /* info for FLASH chips */ static int mac_location[] = { 0x0, /* eth0 */ 0x6, /* eth1 */ 0x1002, /* wlan0 */ }; typedef unsigned char bool; #define true 1 #define false 0 /* from xyzmodem.c */ // Validate a hex character __inline__ static bool _is_hex(char c) { return (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))); } /* from xyzmodem.c */ // Convert a single hex nibble __inline__ static u8 _from_hex(char c) { u8 ret = 0; if ((c >= '0') && (c <= '9')) { ret = (c - '0'); } else if ((c >= 'a') && (c <= 'f')) { ret = (c - 'a' + 0x0a); } else if ((c >= 'A') && (c <= 'F')) { ret = (c - 'A' + 0x0A); } return ret; } static int is_valid_mac_str(char *mac) { /* mac must look like "00:11:22:33:44:55" */ int i; if (strlen(mac) < 17) return 0; for (i=0; i <=15 ; i+=3) { if (!_is_hex(mac[i]) || !_is_hex(mac[i+1])) return 0; /* check for colons - last group doesn't end with a colon*/ if (i != 15 && mac[i+2] != ':') return 0; } return 1; } static int parse_mac(u8 *dst, char *mac_str) { int i; int j; if (!is_valid_mac_str(mac_str)) return 1; /* j = dst offset * i = mac_str offset */ for (i=0, j=0; i<= 15; i+=3, j++) { dst[j] = _from_hex(mac_str[i]) << 4 | _from_hex(mac_str[i + 1]); } return 0; } /* copy calibration sector to the sector before calibration */ static int backup_calibration(u8 *buffer) { int rc = -1; ulong sector_size = flash_info[0].sector_size; ushort cal_sector = flash_info[0].sector_count -1; u8 *board_cal = (u8 *) (KSEG1ADDR(AR7240_SPI_BASE) + cal_sector * flash_info[0].sector_size); /* read */ memcpy(buffer, (void *)board_cal, sector_size); /* erase */ rc = flash_erase(flash_info, cal_sector-1, cal_sector-1); if (rc) { printf("Backup failed because flash erase failed! rc %d\n", rc); return 1; } /* writing into flash - we use the mapped flash as source */ rc = write_buff(flash_info, buffer, board_cal - sector_size, sector_size); if (rc) { printf("Backup failed because write to flash failed! rc %d\n", rc); return 1; } /* compare */ if (memcmp(buffer, (void *)board_cal - sector_size, sector_size)) { printf("Backup failed. Read back different value!\n"); return 1; } return 0; } int write_mac(u8 *buffer, u8 macs[ARRAY_SIZE(mac_location)][ETH_ALEN]) { int i; int rc; ulong sector_size = flash_info[0].sector_size; ushort cal_sector = flash_info[0].sector_count -1; u8 *board_cal = (u8 *) (KSEG1ADDR(AR7240_SPI_BASE) + cal_sector * flash_info[0].sector_size); /* read */ memcpy(buffer, (void *)board_cal, sector_size); /* set macs */ for(i=0; i [..] or set_mac [..] nobackup * check if enough arguments given */ if (argc != (ARRAY_SIZE(mac_location)+1) && argc != (ARRAY_SIZE(mac_location)+2)) return CMD_RET_FAILURE; /* check if nobackup was given */ if (argc == (ARRAY_SIZE(mac_location)+2)) { if(!strncmp("nobackup", argv[argc-1], 8)) { do_backup = false; } else { printf("Unknown argument %s!\n", argv[argc-1]); return CMD_RET_FAILURE; } } /* all other arguments are mac address */ for (i=0; i < ARRAY_SIZE(mac_location); i++) { if (!is_valid_mac_str(argv[i+1])) { printf("Invalid MAC address %s!\n", argv[i+1]); return CMD_RET_FAILURE; } } /* parse macs and copy into macs */ for (i=0; i < ARRAY_SIZE(mac_location); i++) { if (parse_mac(macs[i], argv[i+1])) { printf("Can not parse mac %s!\n", argv[i+1]); return CMD_RET_FAILURE; } } buffer = malloc(sector_size); if (!buffer) { printf("Could not allocate memory"); return CMD_RET_FAILURE; } if (do_backup) { if (backup_calibration(buffer)) { printf("Backup failed to the sector before calibration.\n" "Not updating calibration sector!\n"); rc = CMD_RET_FAILURE; goto out; } } if (!write_mac(buffer, macs)) { rc = CMD_RET_FAILURE; goto out; } rc = CMD_RET_SUCCESS; out: free(buffer); return rc; } int do_showmac(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int i = 0; u8 *buffer; u8 *mac; ushort cal_sector = flash_info[0].sector_count -1; u8 *board_cal = (u8 *) (KSEG1ADDR(AR7240_SPI_BASE) + cal_sector * flash_info[0].sector_size); /* using mapped spi memory */ buffer = (void *)board_cal; for (i=0; i < ARRAY_SIZE(mac_location); i++) { mac = buffer + mac_location[i]; printf("mac %d = %02x:%02x:%02x:%02x:%02x:%02x\n", i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } return CMD_RET_SUCCESS; } int do_setserial(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { u8 *buffer; int32_t *serial; int32_t serial_number; int rc; ulong sector_size = flash_info[0].sector_size; ushort cal_sector = flash_info[0].sector_count -1; u8 *board_cal = KSEG1ADDR(AR7240_SPI_BASE) + cal_sector * flash_info[0].sector_size; if (argc != 2) return CMD_RET_FAILURE; serial_number = simple_strtoul(argv[1], NULL, 16); if (serial_number <= 0) { printf("Invalid serialnumber. <= 0!\n"); return CMD_RET_FAILURE; } buffer = malloc(sector_size); if (!buffer) { printf("Could not allocate memory"); return CMD_RET_FAILURE; } /* read */ memcpy(buffer, (void *)board_cal, sector_size); /* set serial number */ serial = (int32_t *) (buffer + SERIAL_LOCATION); *serial = serial_number; /* erase */ rc = flash_erase(flash_info, cal_sector, cal_sector); if (rc) { printf("Write serial failed because flash_erase failed! rc %d\n", rc); rc = CMD_RET_SUCCESS; goto out; } /* write */ rc = write_buff(flash_info, buffer, board_cal, sector_size); if (rc) { printf("Write serial failed because write_buff failed! rc %d\n", rc); rc = CMD_RET_FAILURE; goto out; } printf("Set serial to %d\n", serial_number); rc = CMD_RET_SUCCESS; out: free(buffer); return rc; } int do_showserial(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong sector_size = flash_info[0].sector_size; ushort cal_sector = flash_info[0].sector_count -1; u8 *board_cal = KSEG1ADDR(AR7240_SPI_BASE) + cal_sector * flash_info[0].sector_size; u8 *buffer = board_cal; int32_t *serial; serial = (int32_t *) (buffer + SERIAL_LOCATION); printf("serial %d\n", *serial); return CMD_RET_SUCCESS; } U_BOOT_CMD( setmac, ARRAY_SIZE(mac_location)+2, 0, do_setmac, "setmac - Set ethernet MAC addresses\n", "setmac [ [nobackup]]\n" " without arguments it shows actual configuration\n" " mac address\n" " mac address\n" " mac address\n" " mac address 00:aa:bb:cc:dd:ee\n" " nobackup - don't do a backup in the sector before calibration" ); U_BOOT_CMD( showmac, 1, 0, do_showmac, "showmac - Show ethernet MAC addresses\n", ); U_BOOT_CMD( setserial, 2, 0, do_setserial, "setserial - Set the serial number\n", "setserial serial\n" ); U_BOOT_CMD( showserial, 1, 0, do_showserial, "showserial - Show serial number\n", ); #endif /* CFG_CMD_SETMAC */