xref: /rk3399_rockchip-uboot/drivers/net/e1000_spi.c (revision 1490eb89f4697b02cfb8f826d2f5eaf37edcbd47)
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