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 */
e1000_spi_xfer(struct e1000_hw * hw,unsigned int bitlen,const void * dout_mem,void * din_mem,bool intr)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
e1000_hw_from_spi(struct spi_slave * spi)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 */
spi_init(void)81ce5207e1SKyle Moffett void spi_init(void) { /* Nothing to do */ }
82ce5207e1SKyle Moffett
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)83ce5207e1SKyle Moffett struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
84ce5207e1SKyle Moffett unsigned int max_hz, unsigned int mode)
85ce5207e1SKyle Moffett {
86ce5207e1SKyle Moffett /* Find the right PCI device */
87ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_find_card(bus);
88ce5207e1SKyle Moffett if (!hw) {
89ce5207e1SKyle Moffett printf("ERROR: No such e1000 device: e1000#%u\n", bus);
90ce5207e1SKyle Moffett return NULL;
91ce5207e1SKyle Moffett }
92ce5207e1SKyle Moffett
93ce5207e1SKyle Moffett /* Make sure it has an SPI chip */
94ce5207e1SKyle Moffett if (hw->eeprom.type != e1000_eeprom_spi) {
95*eb4e8cebSAlban Bedel E1000_ERR(hw, "No attached SPI EEPROM found!\n");
96ce5207e1SKyle Moffett return NULL;
97ce5207e1SKyle Moffett }
98ce5207e1SKyle Moffett
99ce5207e1SKyle Moffett /* Argument sanity checks */
100ce5207e1SKyle Moffett if (cs != 0) {
101*eb4e8cebSAlban Bedel E1000_ERR(hw, "No such SPI chip: %u\n", cs);
102ce5207e1SKyle Moffett return NULL;
103ce5207e1SKyle Moffett }
104ce5207e1SKyle Moffett if (mode != SPI_MODE_0) {
105*eb4e8cebSAlban Bedel E1000_ERR(hw, "Only SPI MODE-0 is supported!\n");
106ce5207e1SKyle Moffett return NULL;
107ce5207e1SKyle Moffett }
108ce5207e1SKyle Moffett
109ce5207e1SKyle Moffett /* TODO: Use max_hz somehow */
110ce5207e1SKyle Moffett E1000_DBG(hw->nic, "EEPROM SPI access requested\n");
111ce5207e1SKyle Moffett return &hw->spi;
112ce5207e1SKyle Moffett }
113ce5207e1SKyle Moffett
spi_free_slave(struct spi_slave * spi)114ce5207e1SKyle Moffett void spi_free_slave(struct spi_slave *spi)
115ce5207e1SKyle Moffett {
116deb7282fSAnatolij Gustschin __maybe_unused struct e1000_hw *hw = e1000_hw_from_spi(spi);
117ce5207e1SKyle Moffett E1000_DBG(hw->nic, "EEPROM SPI access released\n");
118ce5207e1SKyle Moffett }
119ce5207e1SKyle Moffett
spi_claim_bus(struct spi_slave * spi)120ce5207e1SKyle Moffett int spi_claim_bus(struct spi_slave *spi)
121ce5207e1SKyle Moffett {
122ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi);
123ce5207e1SKyle Moffett
124ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) {
125*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
126ce5207e1SKyle Moffett return -1;
127ce5207e1SKyle Moffett }
128ce5207e1SKyle Moffett
129ce5207e1SKyle Moffett return 0;
130ce5207e1SKyle Moffett }
131ce5207e1SKyle Moffett
spi_release_bus(struct spi_slave * spi)132ce5207e1SKyle Moffett void spi_release_bus(struct spi_slave *spi)
133ce5207e1SKyle Moffett {
134ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi);
135ce5207e1SKyle Moffett e1000_release_eeprom(hw);
136ce5207e1SKyle Moffett }
137ce5207e1SKyle Moffett
138ce5207e1SKyle Moffett /* Skinny wrapper around e1000_spi_xfer */
spi_xfer(struct spi_slave * spi,unsigned int bitlen,const void * dout_mem,void * din_mem,unsigned long flags)139ce5207e1SKyle Moffett int spi_xfer(struct spi_slave *spi, unsigned int bitlen,
140ce5207e1SKyle Moffett const void *dout_mem, void *din_mem, unsigned long flags)
141ce5207e1SKyle Moffett {
142ce5207e1SKyle Moffett struct e1000_hw *hw = e1000_hw_from_spi(spi);
143ce5207e1SKyle Moffett int ret;
144ce5207e1SKyle Moffett
145ce5207e1SKyle Moffett if (flags & SPI_XFER_BEGIN)
146ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
147ce5207e1SKyle Moffett
148472d5460SYork Sun ret = e1000_spi_xfer(hw, bitlen, dout_mem, din_mem, true);
149ce5207e1SKyle Moffett
150ce5207e1SKyle Moffett if (flags & SPI_XFER_END)
151ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
152ce5207e1SKyle Moffett
153ce5207e1SKyle Moffett return ret;
154ce5207e1SKyle Moffett }
155ce5207e1SKyle Moffett
156ce5207e1SKyle Moffett #endif /* not CONFIG_E1000_SPI_GENERIC */
157ce5207e1SKyle Moffett
158ce5207e1SKyle Moffett #ifdef CONFIG_CMD_E1000
159ce5207e1SKyle Moffett
160ce5207e1SKyle Moffett /* The EEPROM opcodes */
161ce5207e1SKyle Moffett #define SPI_EEPROM_ENABLE_WR 0x06
162ce5207e1SKyle Moffett #define SPI_EEPROM_DISABLE_WR 0x04
163ce5207e1SKyle Moffett #define SPI_EEPROM_WRITE_STATUS 0x01
164ce5207e1SKyle Moffett #define SPI_EEPROM_READ_STATUS 0x05
165ce5207e1SKyle Moffett #define SPI_EEPROM_WRITE_PAGE 0x02
166ce5207e1SKyle Moffett #define SPI_EEPROM_READ_PAGE 0x03
167ce5207e1SKyle Moffett
168ce5207e1SKyle Moffett /* The EEPROM status bits */
169ce5207e1SKyle Moffett #define SPI_EEPROM_STATUS_BUSY 0x01
170ce5207e1SKyle Moffett #define SPI_EEPROM_STATUS_WREN 0x02
171ce5207e1SKyle Moffett
e1000_spi_eeprom_enable_wr(struct e1000_hw * hw,bool intr)172472d5460SYork Sun static int e1000_spi_eeprom_enable_wr(struct e1000_hw *hw, bool intr)
173ce5207e1SKyle Moffett {
174ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_ENABLE_WR };
175ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
176ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
177ce5207e1SKyle Moffett }
178ce5207e1SKyle Moffett
179ce5207e1SKyle Moffett /*
180ce5207e1SKyle Moffett * These have been tested to perform correctly, but they are not used by any
181ce5207e1SKyle Moffett * of the EEPROM commands at this time.
182ce5207e1SKyle Moffett */
e1000_spi_eeprom_disable_wr(struct e1000_hw * hw,bool intr)183140bc33eSBin Meng static __maybe_unused int e1000_spi_eeprom_disable_wr(struct e1000_hw *hw,
184140bc33eSBin Meng bool intr)
185ce5207e1SKyle Moffett {
186ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_DISABLE_WR };
187ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
188ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
189ce5207e1SKyle Moffett }
190ce5207e1SKyle Moffett
e1000_spi_eeprom_write_status(struct e1000_hw * hw,u8 status,bool intr)191140bc33eSBin Meng static __maybe_unused int e1000_spi_eeprom_write_status(struct e1000_hw *hw,
192472d5460SYork Sun u8 status, bool intr)
193ce5207e1SKyle Moffett {
194ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_WRITE_STATUS, status };
195ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
196ce5207e1SKyle Moffett return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
197ce5207e1SKyle Moffett }
198ce5207e1SKyle Moffett
e1000_spi_eeprom_read_status(struct e1000_hw * hw,bool intr)199472d5460SYork Sun static int e1000_spi_eeprom_read_status(struct e1000_hw *hw, bool intr)
200ce5207e1SKyle Moffett {
201ce5207e1SKyle Moffett u8 op[] = { SPI_EEPROM_READ_STATUS, 0 };
202ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
203ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8*sizeof(op), op, op, intr))
204ce5207e1SKyle Moffett return -1;
205ce5207e1SKyle Moffett return op[1];
206ce5207e1SKyle Moffett }
207ce5207e1SKyle Moffett
e1000_spi_eeprom_write_page(struct e1000_hw * hw,const void * data,u16 off,u16 len,bool intr)208ce5207e1SKyle Moffett static int e1000_spi_eeprom_write_page(struct e1000_hw *hw,
209472d5460SYork Sun const void *data, u16 off, u16 len, bool intr)
210ce5207e1SKyle Moffett {
211ce5207e1SKyle Moffett u8 op[] = {
212ce5207e1SKyle Moffett SPI_EEPROM_WRITE_PAGE,
213ce5207e1SKyle Moffett (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
214ce5207e1SKyle Moffett };
215ce5207e1SKyle Moffett
216ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
217ce5207e1SKyle Moffett
218ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
219ce5207e1SKyle Moffett return -1;
220ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, len << 3, data, NULL, intr))
221ce5207e1SKyle Moffett return -1;
222ce5207e1SKyle Moffett
223ce5207e1SKyle Moffett return 0;
224ce5207e1SKyle Moffett }
225ce5207e1SKyle Moffett
e1000_spi_eeprom_read_page(struct e1000_hw * hw,void * data,u16 off,u16 len,bool intr)226ce5207e1SKyle Moffett static int e1000_spi_eeprom_read_page(struct e1000_hw *hw,
227472d5460SYork Sun void *data, u16 off, u16 len, bool intr)
228ce5207e1SKyle Moffett {
229ce5207e1SKyle Moffett u8 op[] = {
230ce5207e1SKyle Moffett SPI_EEPROM_READ_PAGE,
231ce5207e1SKyle Moffett (off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
232ce5207e1SKyle Moffett };
233ce5207e1SKyle Moffett
234ce5207e1SKyle Moffett e1000_standby_eeprom(hw);
235ce5207e1SKyle Moffett
236ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
237ce5207e1SKyle Moffett return -1;
238ce5207e1SKyle Moffett if (e1000_spi_xfer(hw, len << 3, NULL, data, intr))
239ce5207e1SKyle Moffett return -1;
240ce5207e1SKyle Moffett
241ce5207e1SKyle Moffett return 0;
242ce5207e1SKyle Moffett }
243ce5207e1SKyle Moffett
e1000_spi_eeprom_poll_ready(struct e1000_hw * hw,bool intr)244472d5460SYork Sun static int e1000_spi_eeprom_poll_ready(struct e1000_hw *hw, bool intr)
245ce5207e1SKyle Moffett {
246ce5207e1SKyle Moffett int status;
247ce5207e1SKyle Moffett while ((status = e1000_spi_eeprom_read_status(hw, intr)) >= 0) {
248ce5207e1SKyle Moffett if (!(status & SPI_EEPROM_STATUS_BUSY))
249ce5207e1SKyle Moffett return 0;
250ce5207e1SKyle Moffett }
251ce5207e1SKyle Moffett return -1;
252ce5207e1SKyle Moffett }
253ce5207e1SKyle Moffett
e1000_spi_eeprom_dump(struct e1000_hw * hw,void * data,u16 off,unsigned int len,bool intr)254ce5207e1SKyle Moffett static int e1000_spi_eeprom_dump(struct e1000_hw *hw,
255472d5460SYork Sun void *data, u16 off, unsigned int len, bool intr)
256ce5207e1SKyle Moffett {
257ce5207e1SKyle Moffett /* Interruptibly wait for the EEPROM to be ready */
258ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr))
259ce5207e1SKyle Moffett return -1;
260ce5207e1SKyle Moffett
261ce5207e1SKyle Moffett /* Dump each page in sequence */
262ce5207e1SKyle Moffett while (len) {
263ce5207e1SKyle Moffett /* Calculate the data bytes on this page */
264ce5207e1SKyle Moffett u16 pg_off = off & (hw->eeprom.page_size - 1);
265ce5207e1SKyle Moffett u16 pg_len = hw->eeprom.page_size - pg_off;
266ce5207e1SKyle Moffett if (pg_len > len)
267ce5207e1SKyle Moffett pg_len = len;
268ce5207e1SKyle Moffett
269ce5207e1SKyle Moffett /* Now dump the page */
270ce5207e1SKyle Moffett if (e1000_spi_eeprom_read_page(hw, data, off, pg_len, intr))
271ce5207e1SKyle Moffett return -1;
272ce5207e1SKyle Moffett
273ce5207e1SKyle Moffett /* Otherwise go on to the next page */
274ce5207e1SKyle Moffett len -= pg_len;
275ce5207e1SKyle Moffett off += pg_len;
276ce5207e1SKyle Moffett data += pg_len;
277ce5207e1SKyle Moffett }
278ce5207e1SKyle Moffett
279ce5207e1SKyle Moffett /* We're done! */
280ce5207e1SKyle Moffett return 0;
281ce5207e1SKyle Moffett }
282ce5207e1SKyle Moffett
e1000_spi_eeprom_program(struct e1000_hw * hw,const void * data,u16 off,u16 len,bool intr)283ce5207e1SKyle Moffett static int e1000_spi_eeprom_program(struct e1000_hw *hw,
284472d5460SYork Sun const void *data, u16 off, u16 len, bool intr)
285ce5207e1SKyle Moffett {
286ce5207e1SKyle Moffett /* Program each page in sequence */
287ce5207e1SKyle Moffett while (len) {
288ce5207e1SKyle Moffett /* Calculate the data bytes on this page */
289ce5207e1SKyle Moffett u16 pg_off = off & (hw->eeprom.page_size - 1);
290ce5207e1SKyle Moffett u16 pg_len = hw->eeprom.page_size - pg_off;
291ce5207e1SKyle Moffett if (pg_len > len)
292ce5207e1SKyle Moffett pg_len = len;
293ce5207e1SKyle Moffett
294ce5207e1SKyle Moffett /* Interruptibly wait for the EEPROM to be ready */
295ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr))
296ce5207e1SKyle Moffett return -1;
297ce5207e1SKyle Moffett
298ce5207e1SKyle Moffett /* Enable write access */
299ce5207e1SKyle Moffett if (e1000_spi_eeprom_enable_wr(hw, intr))
300ce5207e1SKyle Moffett return -1;
301ce5207e1SKyle Moffett
302ce5207e1SKyle Moffett /* Now program the page */
303ce5207e1SKyle Moffett if (e1000_spi_eeprom_write_page(hw, data, off, pg_len, intr))
304ce5207e1SKyle Moffett return -1;
305ce5207e1SKyle Moffett
306ce5207e1SKyle Moffett /* Otherwise go on to the next page */
307ce5207e1SKyle Moffett len -= pg_len;
308ce5207e1SKyle Moffett off += pg_len;
309ce5207e1SKyle Moffett data += pg_len;
310ce5207e1SKyle Moffett }
311ce5207e1SKyle Moffett
312ce5207e1SKyle Moffett /* Wait for the last write to complete */
313ce5207e1SKyle Moffett if (e1000_spi_eeprom_poll_ready(hw, intr))
314ce5207e1SKyle Moffett return -1;
315ce5207e1SKyle Moffett
316ce5207e1SKyle Moffett /* We're done! */
317ce5207e1SKyle Moffett return 0;
318ce5207e1SKyle Moffett }
319ce5207e1SKyle Moffett
do_e1000_spi_show(cmd_tbl_t * cmdtp,struct e1000_hw * hw,int argc,char * const argv[])320ce5207e1SKyle Moffett static int do_e1000_spi_show(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
321ce5207e1SKyle Moffett int argc, char * const argv[])
322ce5207e1SKyle Moffett {
323ce5207e1SKyle Moffett unsigned int length = 0;
324ce5207e1SKyle Moffett u16 i, offset = 0;
325ce5207e1SKyle Moffett u8 *buffer;
326ce5207e1SKyle Moffett int err;
327ce5207e1SKyle Moffett
328ce5207e1SKyle Moffett if (argc > 2) {
329ce5207e1SKyle Moffett cmd_usage(cmdtp);
330ce5207e1SKyle Moffett return 1;
331ce5207e1SKyle Moffett }
332ce5207e1SKyle Moffett
333ce5207e1SKyle Moffett /* Parse the offset and length */
334ce5207e1SKyle Moffett if (argc >= 1)
335ce5207e1SKyle Moffett offset = simple_strtoul(argv[0], NULL, 0);
336ce5207e1SKyle Moffett if (argc == 2)
337ce5207e1SKyle Moffett length = simple_strtoul(argv[1], NULL, 0);
338ce5207e1SKyle Moffett else if (offset < (hw->eeprom.word_size << 1))
339ce5207e1SKyle Moffett length = (hw->eeprom.word_size << 1) - offset;
340ce5207e1SKyle Moffett
341ce5207e1SKyle Moffett /* Extra sanity checks */
342ce5207e1SKyle Moffett if (!length) {
343*eb4e8cebSAlban Bedel E1000_ERR(hw, "Requested zero-sized dump!\n");
344ce5207e1SKyle Moffett return 1;
345ce5207e1SKyle Moffett }
346ce5207e1SKyle Moffett if ((0x10000 < length) || (0x10000 - length < offset)) {
347*eb4e8cebSAlban Bedel E1000_ERR(hw, "Can't dump past 0xFFFF!\n");
348ce5207e1SKyle Moffett return 1;
349ce5207e1SKyle Moffett }
350ce5207e1SKyle Moffett
351ce5207e1SKyle Moffett /* Allocate a buffer to hold stuff */
352ce5207e1SKyle Moffett buffer = malloc(length);
353ce5207e1SKyle Moffett if (!buffer) {
354*eb4e8cebSAlban Bedel E1000_ERR(hw, "Out of Memory!\n");
355ce5207e1SKyle Moffett return 1;
356ce5207e1SKyle Moffett }
357ce5207e1SKyle Moffett
358ce5207e1SKyle Moffett /* Acquire the EEPROM and perform the dump */
359ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) {
360*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
361ce5207e1SKyle Moffett free(buffer);
362ce5207e1SKyle Moffett return 1;
363ce5207e1SKyle Moffett }
364472d5460SYork Sun err = e1000_spi_eeprom_dump(hw, buffer, offset, length, true);
365ce5207e1SKyle Moffett e1000_release_eeprom(hw);
366ce5207e1SKyle Moffett if (err) {
367*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n");
368ce5207e1SKyle Moffett free(buffer);
369ce5207e1SKyle Moffett return 1;
370ce5207e1SKyle Moffett }
371ce5207e1SKyle Moffett
372ce5207e1SKyle Moffett /* Now hexdump the result */
373ce5207e1SKyle Moffett printf("%s: ===== Intel e1000 EEPROM (0x%04hX - 0x%04hX) =====",
374*eb4e8cebSAlban Bedel hw->name, offset, offset + length - 1);
375ce5207e1SKyle Moffett for (i = 0; i < length; i++) {
376ce5207e1SKyle Moffett if ((i & 0xF) == 0)
377*eb4e8cebSAlban Bedel printf("\n%s: %04hX: ", hw->name, offset + i);
378ce5207e1SKyle Moffett else if ((i & 0xF) == 0x8)
379ce5207e1SKyle Moffett printf(" ");
380ce5207e1SKyle Moffett printf(" %02hx", buffer[i]);
381ce5207e1SKyle Moffett }
382ce5207e1SKyle Moffett printf("\n");
383ce5207e1SKyle Moffett
384ce5207e1SKyle Moffett /* Success! */
385ce5207e1SKyle Moffett free(buffer);
386ce5207e1SKyle Moffett return 0;
387ce5207e1SKyle Moffett }
388ce5207e1SKyle Moffett
do_e1000_spi_dump(cmd_tbl_t * cmdtp,struct e1000_hw * hw,int argc,char * const argv[])389ce5207e1SKyle Moffett static int do_e1000_spi_dump(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
390ce5207e1SKyle Moffett int argc, char * const argv[])
391ce5207e1SKyle Moffett {
392ce5207e1SKyle Moffett unsigned int length;
393ce5207e1SKyle Moffett u16 offset;
394ce5207e1SKyle Moffett void *dest;
395ce5207e1SKyle Moffett
396ce5207e1SKyle Moffett if (argc != 3) {
397ce5207e1SKyle Moffett cmd_usage(cmdtp);
398ce5207e1SKyle Moffett return 1;
399ce5207e1SKyle Moffett }
400ce5207e1SKyle Moffett
401ce5207e1SKyle Moffett /* Parse the arguments */
402ce5207e1SKyle Moffett dest = (void *)simple_strtoul(argv[0], NULL, 16);
403ce5207e1SKyle Moffett offset = simple_strtoul(argv[1], NULL, 0);
404ce5207e1SKyle Moffett length = simple_strtoul(argv[2], NULL, 0);
405ce5207e1SKyle Moffett
406ce5207e1SKyle Moffett /* Extra sanity checks */
407ce5207e1SKyle Moffett if (!length) {
408*eb4e8cebSAlban Bedel E1000_ERR(hw, "Requested zero-sized dump!\n");
409ce5207e1SKyle Moffett return 1;
410ce5207e1SKyle Moffett }
411ce5207e1SKyle Moffett if ((0x10000 < length) || (0x10000 - length < offset)) {
412*eb4e8cebSAlban Bedel E1000_ERR(hw, "Can't dump past 0xFFFF!\n");
413ce5207e1SKyle Moffett return 1;
414ce5207e1SKyle Moffett }
415ce5207e1SKyle Moffett
416ce5207e1SKyle Moffett /* Acquire the EEPROM */
417ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) {
418*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
419ce5207e1SKyle Moffett return 1;
420ce5207e1SKyle Moffett }
421ce5207e1SKyle Moffett
422ce5207e1SKyle Moffett /* Perform the programming operation */
423472d5460SYork Sun if (e1000_spi_eeprom_dump(hw, dest, offset, length, true) < 0) {
424*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n");
425ce5207e1SKyle Moffett e1000_release_eeprom(hw);
426ce5207e1SKyle Moffett return 1;
427ce5207e1SKyle Moffett }
428ce5207e1SKyle Moffett
429ce5207e1SKyle Moffett e1000_release_eeprom(hw);
430*eb4e8cebSAlban Bedel printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->name);
431ce5207e1SKyle Moffett return 0;
432ce5207e1SKyle Moffett }
433ce5207e1SKyle Moffett
do_e1000_spi_program(cmd_tbl_t * cmdtp,struct e1000_hw * hw,int argc,char * const argv[])434ce5207e1SKyle Moffett static int do_e1000_spi_program(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
435ce5207e1SKyle Moffett int argc, char * const argv[])
436ce5207e1SKyle Moffett {
437ce5207e1SKyle Moffett unsigned int length;
438ce5207e1SKyle Moffett const void *source;
439ce5207e1SKyle Moffett u16 offset;
440ce5207e1SKyle Moffett
441ce5207e1SKyle Moffett if (argc != 3) {
442ce5207e1SKyle Moffett cmd_usage(cmdtp);
443ce5207e1SKyle Moffett return 1;
444ce5207e1SKyle Moffett }
445ce5207e1SKyle Moffett
446ce5207e1SKyle Moffett /* Parse the arguments */
447ce5207e1SKyle Moffett source = (const void *)simple_strtoul(argv[0], NULL, 16);
448ce5207e1SKyle Moffett offset = simple_strtoul(argv[1], NULL, 0);
449ce5207e1SKyle Moffett length = simple_strtoul(argv[2], NULL, 0);
450ce5207e1SKyle Moffett
451ce5207e1SKyle Moffett /* Acquire the EEPROM */
452ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) {
453*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
454ce5207e1SKyle Moffett return 1;
455ce5207e1SKyle Moffett }
456ce5207e1SKyle Moffett
457ce5207e1SKyle Moffett /* Perform the programming operation */
458472d5460SYork Sun if (e1000_spi_eeprom_program(hw, source, offset, length, true) < 0) {
459*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n");
460ce5207e1SKyle Moffett e1000_release_eeprom(hw);
461ce5207e1SKyle Moffett return 1;
462ce5207e1SKyle Moffett }
463ce5207e1SKyle Moffett
464ce5207e1SKyle Moffett e1000_release_eeprom(hw);
465*eb4e8cebSAlban Bedel printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->name);
466ce5207e1SKyle Moffett return 0;
467ce5207e1SKyle Moffett }
468ce5207e1SKyle Moffett
do_e1000_spi_checksum(cmd_tbl_t * cmdtp,struct e1000_hw * hw,int argc,char * const argv[])469ce5207e1SKyle Moffett static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
470ce5207e1SKyle Moffett int argc, char * const argv[])
471ce5207e1SKyle Moffett {
472deb7282fSAnatolij Gustschin uint16_t i, length, checksum = 0, checksum_reg;
473ce5207e1SKyle Moffett uint16_t *buffer;
474472d5460SYork Sun bool upd;
475ce5207e1SKyle Moffett
476ce5207e1SKyle Moffett if (argc == 0)
477ce5207e1SKyle Moffett upd = 0;
478ce5207e1SKyle Moffett else if ((argc == 1) && !strcmp(argv[0], "update"))
479ce5207e1SKyle Moffett upd = 1;
480ce5207e1SKyle Moffett else {
481ce5207e1SKyle Moffett cmd_usage(cmdtp);
482ce5207e1SKyle Moffett return 1;
483ce5207e1SKyle Moffett }
484ce5207e1SKyle Moffett
485ce5207e1SKyle Moffett /* Allocate a temporary buffer */
486ce5207e1SKyle Moffett length = sizeof(uint16_t) * (EEPROM_CHECKSUM_REG + 1);
487ce5207e1SKyle Moffett buffer = malloc(length);
488ce5207e1SKyle Moffett if (!buffer) {
489*eb4e8cebSAlban Bedel E1000_ERR(hw, "Unable to allocate EEPROM buffer!\n");
490ce5207e1SKyle Moffett return 1;
491ce5207e1SKyle Moffett }
492ce5207e1SKyle Moffett
493ce5207e1SKyle Moffett /* Acquire the EEPROM */
494ce5207e1SKyle Moffett if (e1000_acquire_eeprom(hw)) {
495*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
496ce5207e1SKyle Moffett return 1;
497ce5207e1SKyle Moffett }
498ce5207e1SKyle Moffett
499ce5207e1SKyle Moffett /* Read the EEPROM */
500472d5460SYork Sun if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) {
501*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n");
502ce5207e1SKyle Moffett e1000_release_eeprom(hw);
503ce5207e1SKyle Moffett return 1;
504ce5207e1SKyle Moffett }
505ce5207e1SKyle Moffett
506ce5207e1SKyle Moffett /* Compute the checksum and read the expected value */
507ce5207e1SKyle Moffett for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
508ce5207e1SKyle Moffett checksum += le16_to_cpu(buffer[i]);
509ce5207e1SKyle Moffett checksum = ((uint16_t)EEPROM_SUM) - checksum;
510ce5207e1SKyle Moffett checksum_reg = le16_to_cpu(buffer[i]);
511ce5207e1SKyle Moffett
512ce5207e1SKyle Moffett /* Verify it! */
513ce5207e1SKyle Moffett if (checksum_reg == checksum) {
514ce5207e1SKyle Moffett printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n",
515*eb4e8cebSAlban Bedel hw->name, checksum);
516ce5207e1SKyle Moffett e1000_release_eeprom(hw);
517ce5207e1SKyle Moffett return 0;
518ce5207e1SKyle Moffett }
519ce5207e1SKyle Moffett
520ce5207e1SKyle Moffett /* Hrm, verification failed, print an error */
521*eb4e8cebSAlban Bedel E1000_ERR(hw, "EEPROM checksum is incorrect!\n");
522*eb4e8cebSAlban Bedel E1000_ERR(hw, " ...register was 0x%04hx, calculated 0x%04hx\n",
523ce5207e1SKyle Moffett checksum_reg, checksum);
524ce5207e1SKyle Moffett
525ce5207e1SKyle Moffett /* If they didn't ask us to update it, just return an error */
526ce5207e1SKyle Moffett if (!upd) {
527ce5207e1SKyle Moffett e1000_release_eeprom(hw);
528ce5207e1SKyle Moffett return 1;
529ce5207e1SKyle Moffett }
530ce5207e1SKyle Moffett
531ce5207e1SKyle Moffett /* Ok, correct it! */
532*eb4e8cebSAlban Bedel printf("%s: Reprogramming the EEPROM checksum...\n", hw->name);
533ce5207e1SKyle Moffett buffer[i] = cpu_to_le16(checksum);
534ce5207e1SKyle Moffett if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t),
535472d5460SYork Sun sizeof(uint16_t), true)) {
536*eb4e8cebSAlban Bedel E1000_ERR(hw, "Interrupted!\n");
537ce5207e1SKyle Moffett e1000_release_eeprom(hw);
538ce5207e1SKyle Moffett return 1;
539ce5207e1SKyle Moffett }
540ce5207e1SKyle Moffett
541ce5207e1SKyle Moffett e1000_release_eeprom(hw);
542ce5207e1SKyle Moffett return 0;
543ce5207e1SKyle Moffett }
544ce5207e1SKyle Moffett
do_e1000_spi(cmd_tbl_t * cmdtp,struct e1000_hw * hw,int argc,char * const argv[])545ce5207e1SKyle Moffett int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
546ce5207e1SKyle Moffett int argc, char * const argv[])
547ce5207e1SKyle Moffett {
548ce5207e1SKyle Moffett if (argc < 1) {
549ce5207e1SKyle Moffett cmd_usage(cmdtp);
550ce5207e1SKyle Moffett return 1;
551ce5207e1SKyle Moffett }
552ce5207e1SKyle Moffett
553ce5207e1SKyle Moffett /* Make sure it has an SPI chip */
554ce5207e1SKyle Moffett if (hw->eeprom.type != e1000_eeprom_spi) {
555*eb4e8cebSAlban Bedel E1000_ERR(hw, "No attached SPI EEPROM found (%d)!\n",
556*eb4e8cebSAlban Bedel hw->eeprom.type);
557ce5207e1SKyle Moffett return 1;
558ce5207e1SKyle Moffett }
559ce5207e1SKyle Moffett
560ce5207e1SKyle Moffett /* Check the eeprom sub-sub-command arguments */
561ce5207e1SKyle Moffett if (!strcmp(argv[0], "show"))
562ce5207e1SKyle Moffett return do_e1000_spi_show(cmdtp, hw, argc - 1, argv + 1);
563ce5207e1SKyle Moffett
564ce5207e1SKyle Moffett if (!strcmp(argv[0], "dump"))
565ce5207e1SKyle Moffett return do_e1000_spi_dump(cmdtp, hw, argc - 1, argv + 1);
566ce5207e1SKyle Moffett
567ce5207e1SKyle Moffett if (!strcmp(argv[0], "program"))
568ce5207e1SKyle Moffett return do_e1000_spi_program(cmdtp, hw, argc - 1, argv + 1);
569ce5207e1SKyle Moffett
570ce5207e1SKyle Moffett if (!strcmp(argv[0], "checksum"))
571ce5207e1SKyle Moffett return do_e1000_spi_checksum(cmdtp, hw, argc - 1, argv + 1);
572ce5207e1SKyle Moffett
573ce5207e1SKyle Moffett cmd_usage(cmdtp);
574ce5207e1SKyle Moffett return 1;
575ce5207e1SKyle Moffett }
576ce5207e1SKyle Moffett
577ce5207e1SKyle Moffett #endif /* not CONFIG_CMD_E1000 */
578