1c752cd2aSSimon Glass #include <common.h> 224b852a7SSimon Glass #include <console.h> 3ce5207e1SKyle Moffett #include "e1000.h" 4deb7282fSAnatolij Gustschin #include <linux/compiler.h> 5ce5207e1SKyle Moffett 6ce5207e1SKyle Moffett /*----------------------------------------------------------------------- 7ce5207e1SKyle Moffett * SPI transfer 8ce5207e1SKyle Moffett * 9ce5207e1SKyle Moffett * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks 10ce5207e1SKyle Moffett * "bitlen" bits in the SPI MISO port. That's just the way SPI works. 11ce5207e1SKyle Moffett * 12ce5207e1SKyle Moffett * The source of the outgoing bits is the "dout" parameter and the 13ce5207e1SKyle Moffett * destination of the input bits is the "din" parameter. Note that "dout" 14ce5207e1SKyle Moffett * and "din" can point to the same memory location, in which case the 15ce5207e1SKyle Moffett * input data overwrites the output data (since both are buffered by 16ce5207e1SKyle Moffett * temporary variables, this is OK). 17ce5207e1SKyle Moffett * 18ce5207e1SKyle Moffett * This may be interrupted with Ctrl-C if "intr" is true, otherwise it will 19ce5207e1SKyle Moffett * never return an error. 20ce5207e1SKyle Moffett */ 21ce5207e1SKyle Moffett static int e1000_spi_xfer(struct e1000_hw *hw, unsigned int bitlen, 22472d5460SYork Sun const void *dout_mem, void *din_mem, bool intr) 23ce5207e1SKyle Moffett { 24ce5207e1SKyle Moffett const uint8_t *dout = dout_mem; 25ce5207e1SKyle Moffett uint8_t *din = din_mem; 26ce5207e1SKyle Moffett 27ce5207e1SKyle Moffett uint8_t mask = 0; 28ce5207e1SKyle Moffett uint32_t eecd; 29ce5207e1SKyle Moffett unsigned long i; 30ce5207e1SKyle Moffett 31ce5207e1SKyle Moffett /* Pre-read the control register */ 32ce5207e1SKyle Moffett eecd = E1000_READ_REG(hw, EECD); 33ce5207e1SKyle Moffett 34ce5207e1SKyle Moffett /* Iterate over each bit */ 35ce5207e1SKyle Moffett for (i = 0, mask = 0x80; i < bitlen; i++, mask = (mask >> 1)?:0x80) { 36ce5207e1SKyle Moffett /* Check for interrupt */ 37ce5207e1SKyle Moffett if (intr && ctrlc()) 38ce5207e1SKyle Moffett return -1; 39ce5207e1SKyle Moffett 40ce5207e1SKyle Moffett /* Determine the output bit */ 41ce5207e1SKyle Moffett if (dout && dout[i >> 3] & mask) 42ce5207e1SKyle Moffett eecd |= E1000_EECD_DI; 43ce5207e1SKyle Moffett else 44ce5207e1SKyle Moffett eecd &= ~E1000_EECD_DI; 45ce5207e1SKyle Moffett 46ce5207e1SKyle Moffett /* Write the output bit and wait 50us */ 47ce5207e1SKyle Moffett E1000_WRITE_REG(hw, EECD, eecd); 48ce5207e1SKyle Moffett E1000_WRITE_FLUSH(hw); 49ce5207e1SKyle Moffett udelay(50); 50ce5207e1SKyle Moffett 51ce5207e1SKyle Moffett /* Poke the clock (waits 50us) */ 52ce5207e1SKyle Moffett e1000_raise_ee_clk(hw, &eecd); 53ce5207e1SKyle Moffett 54ce5207e1SKyle Moffett /* Now read the input bit */ 55ce5207e1SKyle Moffett eecd = E1000_READ_REG(hw, EECD); 56ce5207e1SKyle Moffett if (din) { 57ce5207e1SKyle Moffett if (eecd & E1000_EECD_DO) 58ce5207e1SKyle Moffett din[i >> 3] |= mask; 59ce5207e1SKyle Moffett else 60ce5207e1SKyle Moffett din[i >> 3] &= ~mask; 61ce5207e1SKyle Moffett } 62ce5207e1SKyle Moffett 63ce5207e1SKyle Moffett /* Poke the clock again (waits 50us) */ 64ce5207e1SKyle Moffett e1000_lower_ee_clk(hw, &eecd); 65ce5207e1SKyle Moffett } 66ce5207e1SKyle Moffett 67ce5207e1SKyle Moffett /* Now clear any remaining bits of the input */ 68ce5207e1SKyle Moffett if (din && (i & 7)) 69ce5207e1SKyle Moffett din[i >> 3] &= ~((mask << 1) - 1); 70ce5207e1SKyle Moffett 71ce5207e1SKyle Moffett return 0; 72ce5207e1SKyle Moffett } 73ce5207e1SKyle Moffett 74ce5207e1SKyle Moffett #ifdef CONFIG_E1000_SPI_GENERIC 75ce5207e1SKyle Moffett static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi) 76ce5207e1SKyle Moffett { 77ce5207e1SKyle Moffett return container_of(spi, struct e1000_hw, spi); 78ce5207e1SKyle Moffett } 79ce5207e1SKyle Moffett 80ce5207e1SKyle Moffett /* Not sure why all of these are necessary */ 81ce5207e1SKyle Moffett void spi_init_r(void) { /* Nothing to do */ } 82ce5207e1SKyle Moffett void spi_init_f(void) { /* Nothing to do */ } 83ce5207e1SKyle Moffett void spi_init(void) { /* Nothing to do */ } 84ce5207e1SKyle Moffett 85ce5207e1SKyle Moffett struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 86ce5207e1SKyle Moffett unsigned int max_hz, unsigned int mode) 87ce5207e1SKyle Moffett { 88ce5207e1SKyle Moffett /* Find the right PCI device */ 89ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_find_card(bus); 90ce5207e1SKyle Moffett if (!hw) { 91ce5207e1SKyle Moffett printf("ERROR: No such e1000 device: e1000#%u\n", bus); 92ce5207e1SKyle Moffett return NULL; 93ce5207e1SKyle Moffett } 94ce5207e1SKyle Moffett 95ce5207e1SKyle Moffett /* Make sure it has an SPI chip */ 96ce5207e1SKyle Moffett if (hw->eeprom.type != e1000_eeprom_spi) { 97*eb4e8cebSAlban Bedel E1000_ERR(hw, "No attached SPI EEPROM found!\n"); 98ce5207e1SKyle Moffett return NULL; 99ce5207e1SKyle Moffett } 100ce5207e1SKyle Moffett 101ce5207e1SKyle Moffett /* Argument sanity checks */ 102ce5207e1SKyle Moffett if (cs != 0) { 103*eb4e8cebSAlban Bedel E1000_ERR(hw, "No such SPI chip: %u\n", cs); 104ce5207e1SKyle Moffett return NULL; 105ce5207e1SKyle Moffett } 106ce5207e1SKyle Moffett if (mode != SPI_MODE_0) { 107*eb4e8cebSAlban Bedel E1000_ERR(hw, "Only SPI MODE-0 is supported!\n"); 108ce5207e1SKyle Moffett return NULL; 109ce5207e1SKyle Moffett } 110ce5207e1SKyle Moffett 111ce5207e1SKyle Moffett /* TODO: Use max_hz somehow */ 112ce5207e1SKyle Moffett E1000_DBG(hw->nic, "EEPROM SPI access requested\n"); 113ce5207e1SKyle Moffett return &hw->spi; 114ce5207e1SKyle Moffett } 115ce5207e1SKyle Moffett 116ce5207e1SKyle Moffett void spi_free_slave(struct spi_slave *spi) 117ce5207e1SKyle Moffett { 118deb7282fSAnatolij Gustschin __maybe_unused struct e1000_hw *hw = e1000_hw_from_spi(spi); 119ce5207e1SKyle Moffett E1000_DBG(hw->nic, "EEPROM SPI access released\n"); 120ce5207e1SKyle Moffett } 121ce5207e1SKyle Moffett 122ce5207e1SKyle Moffett int spi_claim_bus(struct spi_slave *spi) 123ce5207e1SKyle Moffett { 124ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi); 125ce5207e1SKyle Moffett 126ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) { 127*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); 128ce5207e1SKyle Moffett return -1; 129ce5207e1SKyle Moffett } 130ce5207e1SKyle Moffett 131ce5207e1SKyle Moffett return 0; 132ce5207e1SKyle Moffett } 133ce5207e1SKyle Moffett 134ce5207e1SKyle Moffett void spi_release_bus(struct spi_slave *spi) 135ce5207e1SKyle Moffett { 136ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi); 137ce5207e1SKyle Moffett e1000_release_eeprom(hw); 138ce5207e1SKyle Moffett } 139ce5207e1SKyle Moffett 140ce5207e1SKyle Moffett /* Skinny wrapper around e1000_spi_xfer */ 141ce5207e1SKyle Moffett int spi_xfer(struct spi_slave *spi, unsigned int bitlen, 142ce5207e1SKyle Moffett const void *dout_mem, void *din_mem, unsigned long flags) 143ce5207e1SKyle Moffett { 144ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi); 145ce5207e1SKyle Moffett int ret; 146ce5207e1SKyle Moffett 147ce5207e1SKyle Moffett if (flags & SPI_XFER_BEGIN) 148ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 149ce5207e1SKyle Moffett 150472d5460SYork Sun ret = e1000_spi_xfer(hw, bitlen, dout_mem, din_mem, true); 151ce5207e1SKyle Moffett 152ce5207e1SKyle Moffett if (flags & SPI_XFER_END) 153ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 154ce5207e1SKyle Moffett 155ce5207e1SKyle Moffett return ret; 156ce5207e1SKyle Moffett } 157ce5207e1SKyle Moffett 158ce5207e1SKyle Moffett #endif /* not CONFIG_E1000_SPI_GENERIC */ 159ce5207e1SKyle Moffett 160ce5207e1SKyle Moffett #ifdef CONFIG_CMD_E1000 161ce5207e1SKyle Moffett 162ce5207e1SKyle Moffett /* The EEPROM opcodes */ 163ce5207e1SKyle Moffett #define SPI_EEPROM_ENABLE_WR 0x06 164ce5207e1SKyle Moffett #define SPI_EEPROM_DISABLE_WR 0x04 165ce5207e1SKyle Moffett #define SPI_EEPROM_WRITE_STATUS 0x01 166ce5207e1SKyle Moffett #define SPI_EEPROM_READ_STATUS 0x05 167ce5207e1SKyle Moffett #define SPI_EEPROM_WRITE_PAGE 0x02 168ce5207e1SKyle Moffett #define SPI_EEPROM_READ_PAGE 0x03 169ce5207e1SKyle Moffett 170ce5207e1SKyle Moffett /* The EEPROM status bits */ 171ce5207e1SKyle Moffett #define SPI_EEPROM_STATUS_BUSY 0x01 172ce5207e1SKyle Moffett #define SPI_EEPROM_STATUS_WREN 0x02 173ce5207e1SKyle Moffett 174472d5460SYork Sun static int e1000_spi_eeprom_enable_wr(struct e1000_hw *hw, bool intr) 175ce5207e1SKyle Moffett { 176ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_ENABLE_WR }; 177ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 178ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr); 179ce5207e1SKyle Moffett } 180ce5207e1SKyle Moffett 181ce5207e1SKyle Moffett /* 182ce5207e1SKyle Moffett * These have been tested to perform correctly, but they are not used by any 183ce5207e1SKyle Moffett * of the EEPROM commands at this time. 184ce5207e1SKyle Moffett */ 185140bc33eSBin Meng static __maybe_unused int e1000_spi_eeprom_disable_wr(struct e1000_hw *hw, 186140bc33eSBin Meng bool intr) 187ce5207e1SKyle Moffett { 188ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_DISABLE_WR }; 189ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 190ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr); 191ce5207e1SKyle Moffett } 192ce5207e1SKyle Moffett 193140bc33eSBin Meng static __maybe_unused int e1000_spi_eeprom_write_status(struct e1000_hw *hw, 194472d5460SYork Sun u8 status, bool intr) 195ce5207e1SKyle Moffett { 196ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_WRITE_STATUS, status }; 197ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 198ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr); 199ce5207e1SKyle Moffett } 200ce5207e1SKyle Moffett 201472d5460SYork Sun static int e1000_spi_eeprom_read_status(struct e1000_hw *hw, bool intr) 202ce5207e1SKyle Moffett { 203ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_READ_STATUS, 0 }; 204ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 205ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8*sizeof(op), op, op, intr)) 206ce5207e1SKyle Moffett return -1; 207ce5207e1SKyle Moffett return op[1]; 208ce5207e1SKyle Moffett } 209ce5207e1SKyle Moffett 210ce5207e1SKyle Moffett static int e1000_spi_eeprom_write_page(struct e1000_hw *hw, 211472d5460SYork Sun const void *data, u16 off, u16 len, bool intr) 212ce5207e1SKyle Moffett { 213ce5207e1SKyle Moffett u8 op[] = { 214ce5207e1SKyle Moffett SPI_EEPROM_WRITE_PAGE, 215ce5207e1SKyle Moffett (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff 216ce5207e1SKyle Moffett }; 217ce5207e1SKyle Moffett 218ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 219ce5207e1SKyle Moffett 220ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr)) 221ce5207e1SKyle Moffett return -1; 222ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, len << 3, data, NULL, intr)) 223ce5207e1SKyle Moffett return -1; 224ce5207e1SKyle Moffett 225ce5207e1SKyle Moffett return 0; 226ce5207e1SKyle Moffett } 227ce5207e1SKyle Moffett 228ce5207e1SKyle Moffett static int e1000_spi_eeprom_read_page(struct e1000_hw *hw, 229472d5460SYork Sun void *data, u16 off, u16 len, bool intr) 230ce5207e1SKyle Moffett { 231ce5207e1SKyle Moffett u8 op[] = { 232ce5207e1SKyle Moffett SPI_EEPROM_READ_PAGE, 233ce5207e1SKyle Moffett (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff 234ce5207e1SKyle Moffett }; 235ce5207e1SKyle Moffett 236ce5207e1SKyle Moffett e1000_standby_eeprom(hw); 237ce5207e1SKyle Moffett 238ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr)) 239ce5207e1SKyle Moffett return -1; 240ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, len << 3, NULL, data, intr)) 241ce5207e1SKyle Moffett return -1; 242ce5207e1SKyle Moffett 243ce5207e1SKyle Moffett return 0; 244ce5207e1SKyle Moffett } 245ce5207e1SKyle Moffett 246472d5460SYork Sun static int e1000_spi_eeprom_poll_ready(struct e1000_hw *hw, bool intr) 247ce5207e1SKyle Moffett { 248ce5207e1SKyle Moffett int status; 249ce5207e1SKyle Moffett while ((status = e1000_spi_eeprom_read_status(hw, intr)) >= 0) { 250ce5207e1SKyle Moffett if (!(status & SPI_EEPROM_STATUS_BUSY)) 251ce5207e1SKyle Moffett return 0; 252ce5207e1SKyle Moffett } 253ce5207e1SKyle Moffett return -1; 254ce5207e1SKyle Moffett } 255ce5207e1SKyle Moffett 256ce5207e1SKyle Moffett static int e1000_spi_eeprom_dump(struct e1000_hw *hw, 257472d5460SYork Sun void *data, u16 off, unsigned int len, bool intr) 258ce5207e1SKyle Moffett { 259ce5207e1SKyle Moffett /* Interruptibly wait for the EEPROM to be ready */ 260ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr)) 261ce5207e1SKyle Moffett return -1; 262ce5207e1SKyle Moffett 263ce5207e1SKyle Moffett /* Dump each page in sequence */ 264ce5207e1SKyle Moffett while (len) { 265ce5207e1SKyle Moffett /* Calculate the data bytes on this page */ 266ce5207e1SKyle Moffett u16 pg_off = off & (hw->eeprom.page_size - 1); 267ce5207e1SKyle Moffett u16 pg_len = hw->eeprom.page_size - pg_off; 268ce5207e1SKyle Moffett if (pg_len > len) 269ce5207e1SKyle Moffett pg_len = len; 270ce5207e1SKyle Moffett 271ce5207e1SKyle Moffett /* Now dump the page */ 272ce5207e1SKyle Moffett if (e1000_spi_eeprom_read_page(hw, data, off, pg_len, intr)) 273ce5207e1SKyle Moffett return -1; 274ce5207e1SKyle Moffett 275ce5207e1SKyle Moffett /* Otherwise go on to the next page */ 276ce5207e1SKyle Moffett len -= pg_len; 277ce5207e1SKyle Moffett off += pg_len; 278ce5207e1SKyle Moffett data += pg_len; 279ce5207e1SKyle Moffett } 280ce5207e1SKyle Moffett 281ce5207e1SKyle Moffett /* We're done! */ 282ce5207e1SKyle Moffett return 0; 283ce5207e1SKyle Moffett } 284ce5207e1SKyle Moffett 285ce5207e1SKyle Moffett static int e1000_spi_eeprom_program(struct e1000_hw *hw, 286472d5460SYork Sun const void *data, u16 off, u16 len, bool intr) 287ce5207e1SKyle Moffett { 288ce5207e1SKyle Moffett /* Program each page in sequence */ 289ce5207e1SKyle Moffett while (len) { 290ce5207e1SKyle Moffett /* Calculate the data bytes on this page */ 291ce5207e1SKyle Moffett u16 pg_off = off & (hw->eeprom.page_size - 1); 292ce5207e1SKyle Moffett u16 pg_len = hw->eeprom.page_size - pg_off; 293ce5207e1SKyle Moffett if (pg_len > len) 294ce5207e1SKyle Moffett pg_len = len; 295ce5207e1SKyle Moffett 296ce5207e1SKyle Moffett /* Interruptibly wait for the EEPROM to be ready */ 297ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr)) 298ce5207e1SKyle Moffett return -1; 299ce5207e1SKyle Moffett 300ce5207e1SKyle Moffett /* Enable write access */ 301ce5207e1SKyle Moffett if (e1000_spi_eeprom_enable_wr(hw, intr)) 302ce5207e1SKyle Moffett return -1; 303ce5207e1SKyle Moffett 304ce5207e1SKyle Moffett /* Now program the page */ 305ce5207e1SKyle Moffett if (e1000_spi_eeprom_write_page(hw, data, off, pg_len, intr)) 306ce5207e1SKyle Moffett return -1; 307ce5207e1SKyle Moffett 308ce5207e1SKyle Moffett /* Otherwise go on to the next page */ 309ce5207e1SKyle Moffett len -= pg_len; 310ce5207e1SKyle Moffett off += pg_len; 311ce5207e1SKyle Moffett data += pg_len; 312ce5207e1SKyle Moffett } 313ce5207e1SKyle Moffett 314ce5207e1SKyle Moffett /* Wait for the last write to complete */ 315ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr)) 316ce5207e1SKyle Moffett return -1; 317ce5207e1SKyle Moffett 318ce5207e1SKyle Moffett /* We're done! */ 319ce5207e1SKyle Moffett return 0; 320ce5207e1SKyle Moffett } 321ce5207e1SKyle Moffett 322ce5207e1SKyle Moffett static int do_e1000_spi_show(cmd_tbl_t *cmdtp, struct e1000_hw *hw, 323ce5207e1SKyle Moffett int argc, char * const argv[]) 324ce5207e1SKyle Moffett { 325ce5207e1SKyle Moffett unsigned int length = 0; 326ce5207e1SKyle Moffett u16 i, offset = 0; 327ce5207e1SKyle Moffett u8 *buffer; 328ce5207e1SKyle Moffett int err; 329ce5207e1SKyle Moffett 330ce5207e1SKyle Moffett if (argc > 2) { 331ce5207e1SKyle Moffett cmd_usage(cmdtp); 332ce5207e1SKyle Moffett return 1; 333ce5207e1SKyle Moffett } 334ce5207e1SKyle Moffett 335ce5207e1SKyle Moffett /* Parse the offset and length */ 336ce5207e1SKyle Moffett if (argc >= 1) 337ce5207e1SKyle Moffett offset = simple_strtoul(argv[0], NULL, 0); 338ce5207e1SKyle Moffett if (argc == 2) 339ce5207e1SKyle Moffett length = simple_strtoul(argv[1], NULL, 0); 340ce5207e1SKyle Moffett else if (offset < (hw->eeprom.word_size << 1)) 341ce5207e1SKyle Moffett length = (hw->eeprom.word_size << 1) - offset; 342ce5207e1SKyle Moffett 343ce5207e1SKyle Moffett /* Extra sanity checks */ 344ce5207e1SKyle Moffett if (!length) { 345*eb4e8cebSAlban Bedel E1000_ERR(hw, "Requested zero-sized dump!\n"); 346ce5207e1SKyle Moffett return 1; 347ce5207e1SKyle Moffett } 348ce5207e1SKyle Moffett if ((0x10000 < length) || (0x10000 - length < offset)) { 349*eb4e8cebSAlban Bedel E1000_ERR(hw, "Can't dump past 0xFFFF!\n"); 350ce5207e1SKyle Moffett return 1; 351ce5207e1SKyle Moffett } 352ce5207e1SKyle Moffett 353ce5207e1SKyle Moffett /* Allocate a buffer to hold stuff */ 354ce5207e1SKyle Moffett buffer = malloc(length); 355ce5207e1SKyle Moffett if (!buffer) { 356*eb4e8cebSAlban Bedel E1000_ERR(hw, "Out of Memory!\n"); 357ce5207e1SKyle Moffett return 1; 358ce5207e1SKyle Moffett } 359ce5207e1SKyle Moffett 360ce5207e1SKyle Moffett /* Acquire the EEPROM and perform the dump */ 361ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) { 362*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); 363ce5207e1SKyle Moffett free(buffer); 364ce5207e1SKyle Moffett return 1; 365ce5207e1SKyle Moffett } 366472d5460SYork Sun err = e1000_spi_eeprom_dump(hw, buffer, offset, length, true); 367ce5207e1SKyle Moffett e1000_release_eeprom(hw); 368ce5207e1SKyle Moffett if (err) { 369*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n"); 370ce5207e1SKyle Moffett free(buffer); 371ce5207e1SKyle Moffett return 1; 372ce5207e1SKyle Moffett } 373ce5207e1SKyle Moffett 374ce5207e1SKyle Moffett /* Now hexdump the result */ 375ce5207e1SKyle Moffett printf("%s: ===== Intel e1000 EEPROM (0x%04hX - 0x%04hX) =====", 376*eb4e8cebSAlban Bedel hw->name, offset, offset + length - 1); 377ce5207e1SKyle Moffett for (i = 0; i < length; i++) { 378ce5207e1SKyle Moffett if ((i & 0xF) == 0) 379*eb4e8cebSAlban Bedel printf("\n%s: %04hX: ", hw->name, offset + i); 380ce5207e1SKyle Moffett else if ((i & 0xF) == 0x8) 381ce5207e1SKyle Moffett printf(" "); 382ce5207e1SKyle Moffett printf(" %02hx", buffer[i]); 383ce5207e1SKyle Moffett } 384ce5207e1SKyle Moffett printf("\n"); 385ce5207e1SKyle Moffett 386ce5207e1SKyle Moffett /* Success! */ 387ce5207e1SKyle Moffett free(buffer); 388ce5207e1SKyle Moffett return 0; 389ce5207e1SKyle Moffett } 390ce5207e1SKyle Moffett 391ce5207e1SKyle Moffett static int do_e1000_spi_dump(cmd_tbl_t *cmdtp, struct e1000_hw *hw, 392ce5207e1SKyle Moffett int argc, char * const argv[]) 393ce5207e1SKyle Moffett { 394ce5207e1SKyle Moffett unsigned int length; 395ce5207e1SKyle Moffett u16 offset; 396ce5207e1SKyle Moffett void *dest; 397ce5207e1SKyle Moffett 398ce5207e1SKyle Moffett if (argc != 3) { 399ce5207e1SKyle Moffett cmd_usage(cmdtp); 400ce5207e1SKyle Moffett return 1; 401ce5207e1SKyle Moffett } 402ce5207e1SKyle Moffett 403ce5207e1SKyle Moffett /* Parse the arguments */ 404ce5207e1SKyle Moffett dest = (void *)simple_strtoul(argv[0], NULL, 16); 405ce5207e1SKyle Moffett offset = simple_strtoul(argv[1], NULL, 0); 406ce5207e1SKyle Moffett length = simple_strtoul(argv[2], NULL, 0); 407ce5207e1SKyle Moffett 408ce5207e1SKyle Moffett /* Extra sanity checks */ 409ce5207e1SKyle Moffett if (!length) { 410*eb4e8cebSAlban Bedel E1000_ERR(hw, "Requested zero-sized dump!\n"); 411ce5207e1SKyle Moffett return 1; 412ce5207e1SKyle Moffett } 413ce5207e1SKyle Moffett if ((0x10000 < length) || (0x10000 - length < offset)) { 414*eb4e8cebSAlban Bedel E1000_ERR(hw, "Can't dump past 0xFFFF!\n"); 415ce5207e1SKyle Moffett return 1; 416ce5207e1SKyle Moffett } 417ce5207e1SKyle Moffett 418ce5207e1SKyle Moffett /* Acquire the EEPROM */ 419ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) { 420*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); 421ce5207e1SKyle Moffett return 1; 422ce5207e1SKyle Moffett } 423ce5207e1SKyle Moffett 424ce5207e1SKyle Moffett /* Perform the programming operation */ 425472d5460SYork Sun if (e1000_spi_eeprom_dump(hw, dest, offset, length, true) < 0) { 426*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n"); 427ce5207e1SKyle Moffett e1000_release_eeprom(hw); 428ce5207e1SKyle Moffett return 1; 429ce5207e1SKyle Moffett } 430ce5207e1SKyle Moffett 431ce5207e1SKyle Moffett e1000_release_eeprom(hw); 432*eb4e8cebSAlban Bedel printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->name); 433ce5207e1SKyle Moffett return 0; 434ce5207e1SKyle Moffett } 435ce5207e1SKyle Moffett 436ce5207e1SKyle Moffett static int do_e1000_spi_program(cmd_tbl_t *cmdtp, struct e1000_hw *hw, 437ce5207e1SKyle Moffett int argc, char * const argv[]) 438ce5207e1SKyle Moffett { 439ce5207e1SKyle Moffett unsigned int length; 440ce5207e1SKyle Moffett const void *source; 441ce5207e1SKyle Moffett u16 offset; 442ce5207e1SKyle Moffett 443ce5207e1SKyle Moffett if (argc != 3) { 444ce5207e1SKyle Moffett cmd_usage(cmdtp); 445ce5207e1SKyle Moffett return 1; 446ce5207e1SKyle Moffett } 447ce5207e1SKyle Moffett 448ce5207e1SKyle Moffett /* Parse the arguments */ 449ce5207e1SKyle Moffett source = (const void *)simple_strtoul(argv[0], NULL, 16); 450ce5207e1SKyle Moffett offset = simple_strtoul(argv[1], NULL, 0); 451ce5207e1SKyle Moffett length = simple_strtoul(argv[2], NULL, 0); 452ce5207e1SKyle Moffett 453ce5207e1SKyle Moffett /* Acquire the EEPROM */ 454ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) { 455*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); 456ce5207e1SKyle Moffett return 1; 457ce5207e1SKyle Moffett } 458ce5207e1SKyle Moffett 459ce5207e1SKyle Moffett /* Perform the programming operation */ 460472d5460SYork Sun if (e1000_spi_eeprom_program(hw, source, offset, length, true) < 0) { 461*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n"); 462ce5207e1SKyle Moffett e1000_release_eeprom(hw); 463ce5207e1SKyle Moffett return 1; 464ce5207e1SKyle Moffett } 465ce5207e1SKyle Moffett 466ce5207e1SKyle Moffett e1000_release_eeprom(hw); 467*eb4e8cebSAlban Bedel printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->name); 468ce5207e1SKyle Moffett return 0; 469ce5207e1SKyle Moffett } 470ce5207e1SKyle Moffett 471ce5207e1SKyle Moffett static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw, 472ce5207e1SKyle Moffett int argc, char * const argv[]) 473ce5207e1SKyle Moffett { 474deb7282fSAnatolij Gustschin uint16_t i, length, checksum = 0, checksum_reg; 475ce5207e1SKyle Moffett uint16_t *buffer; 476472d5460SYork Sun bool upd; 477ce5207e1SKyle Moffett 478ce5207e1SKyle Moffett if (argc == 0) 479ce5207e1SKyle Moffett upd = 0; 480ce5207e1SKyle Moffett else if ((argc == 1) && !strcmp(argv[0], "update")) 481ce5207e1SKyle Moffett upd = 1; 482ce5207e1SKyle Moffett else { 483ce5207e1SKyle Moffett cmd_usage(cmdtp); 484ce5207e1SKyle Moffett return 1; 485ce5207e1SKyle Moffett } 486ce5207e1SKyle Moffett 487ce5207e1SKyle Moffett /* Allocate a temporary buffer */ 488ce5207e1SKyle Moffett length = sizeof(uint16_t) * (EEPROM_CHECKSUM_REG + 1); 489ce5207e1SKyle Moffett buffer = malloc(length); 490ce5207e1SKyle Moffett if (!buffer) { 491*eb4e8cebSAlban Bedel E1000_ERR(hw, "Unable to allocate EEPROM buffer!\n"); 492ce5207e1SKyle Moffett return 1; 493ce5207e1SKyle Moffett } 494ce5207e1SKyle Moffett 495ce5207e1SKyle Moffett /* Acquire the EEPROM */ 496ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) { 497*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); 498ce5207e1SKyle Moffett return 1; 499ce5207e1SKyle Moffett } 500ce5207e1SKyle Moffett 501ce5207e1SKyle Moffett /* Read the EEPROM */ 502472d5460SYork Sun if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) { 503*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n"); 504ce5207e1SKyle Moffett e1000_release_eeprom(hw); 505ce5207e1SKyle Moffett return 1; 506ce5207e1SKyle Moffett } 507ce5207e1SKyle Moffett 508ce5207e1SKyle Moffett /* Compute the checksum and read the expected value */ 509ce5207e1SKyle Moffett for (i = 0; i < EEPROM_CHECKSUM_REG; i++) 510ce5207e1SKyle Moffett checksum += le16_to_cpu(buffer[i]); 511ce5207e1SKyle Moffett checksum = ((uint16_t)EEPROM_SUM) - checksum; 512ce5207e1SKyle Moffett checksum_reg = le16_to_cpu(buffer[i]); 513ce5207e1SKyle Moffett 514ce5207e1SKyle Moffett /* Verify it! */ 515ce5207e1SKyle Moffett if (checksum_reg == checksum) { 516ce5207e1SKyle Moffett printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n", 517*eb4e8cebSAlban Bedel hw->name, checksum); 518ce5207e1SKyle Moffett e1000_release_eeprom(hw); 519ce5207e1SKyle Moffett return 0; 520ce5207e1SKyle Moffett } 521ce5207e1SKyle Moffett 522ce5207e1SKyle Moffett /* Hrm, verification failed, print an error */ 523*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM checksum is incorrect!\n"); 524*eb4e8cebSAlban Bedel E1000_ERR(hw, " ...register was 0x%04hx, calculated 0x%04hx\n", 525ce5207e1SKyle Moffett checksum_reg, checksum); 526ce5207e1SKyle Moffett 527ce5207e1SKyle Moffett /* If they didn't ask us to update it, just return an error */ 528ce5207e1SKyle Moffett if (!upd) { 529ce5207e1SKyle Moffett e1000_release_eeprom(hw); 530ce5207e1SKyle Moffett return 1; 531ce5207e1SKyle Moffett } 532ce5207e1SKyle Moffett 533ce5207e1SKyle Moffett /* Ok, correct it! */ 534*eb4e8cebSAlban Bedel printf("%s: Reprogramming the EEPROM checksum...\n", hw->name); 535ce5207e1SKyle Moffett buffer[i] = cpu_to_le16(checksum); 536ce5207e1SKyle Moffett if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t), 537472d5460SYork Sun sizeof(uint16_t), true)) { 538*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n"); 539ce5207e1SKyle Moffett e1000_release_eeprom(hw); 540ce5207e1SKyle Moffett return 1; 541ce5207e1SKyle Moffett } 542ce5207e1SKyle Moffett 543ce5207e1SKyle Moffett e1000_release_eeprom(hw); 544ce5207e1SKyle Moffett return 0; 545ce5207e1SKyle Moffett } 546ce5207e1SKyle Moffett 547ce5207e1SKyle Moffett int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw, 548ce5207e1SKyle Moffett int argc, char * const argv[]) 549ce5207e1SKyle Moffett { 550ce5207e1SKyle Moffett if (argc < 1) { 551ce5207e1SKyle Moffett cmd_usage(cmdtp); 552ce5207e1SKyle Moffett return 1; 553ce5207e1SKyle Moffett } 554ce5207e1SKyle Moffett 555ce5207e1SKyle Moffett /* Make sure it has an SPI chip */ 556ce5207e1SKyle Moffett if (hw->eeprom.type != e1000_eeprom_spi) { 557*eb4e8cebSAlban Bedel E1000_ERR(hw, "No attached SPI EEPROM found (%d)!\n", 558*eb4e8cebSAlban Bedel hw->eeprom.type); 559ce5207e1SKyle Moffett return 1; 560ce5207e1SKyle Moffett } 561ce5207e1SKyle Moffett 562ce5207e1SKyle Moffett /* Check the eeprom sub-sub-command arguments */ 563ce5207e1SKyle Moffett if (!strcmp(argv[0], "show")) 564ce5207e1SKyle Moffett return do_e1000_spi_show(cmdtp, hw, argc - 1, argv + 1); 565ce5207e1SKyle Moffett 566ce5207e1SKyle Moffett if (!strcmp(argv[0], "dump")) 567ce5207e1SKyle Moffett return do_e1000_spi_dump(cmdtp, hw, argc - 1, argv + 1); 568ce5207e1SKyle Moffett 569ce5207e1SKyle Moffett if (!strcmp(argv[0], "program")) 570ce5207e1SKyle Moffett return do_e1000_spi_program(cmdtp, hw, argc - 1, argv + 1); 571ce5207e1SKyle Moffett 572ce5207e1SKyle Moffett if (!strcmp(argv[0], "checksum")) 573ce5207e1SKyle Moffett return do_e1000_spi_checksum(cmdtp, hw, argc - 1, argv + 1); 574ce5207e1SKyle Moffett 575ce5207e1SKyle Moffett cmd_usage(cmdtp); 576ce5207e1SKyle Moffett return 1; 577ce5207e1SKyle Moffett } 578ce5207e1SKyle Moffett 579ce5207e1SKyle Moffett #endif /* not CONFIG_CMD_E1000 */ 580