xref: /rk3399_rockchip-uboot/cmd/eeprom.c (revision 2e192b245ed36a63bab0ef576999a95e23f60ecd)
1*2e192b24SSimon Glass /*
2*2e192b24SSimon Glass  * (C) Copyright 2000, 2001
3*2e192b24SSimon Glass  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*2e192b24SSimon Glass  *
5*2e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
6*2e192b24SSimon Glass  */
7*2e192b24SSimon Glass 
8*2e192b24SSimon Glass /*
9*2e192b24SSimon Glass  * Support for read and write access to EEPROM like memory devices. This
10*2e192b24SSimon Glass  * includes regular EEPROM as well as  FRAM (ferroelectic nonvolaile RAM).
11*2e192b24SSimon Glass  * FRAM devices read and write data at bus speed. In particular, there is no
12*2e192b24SSimon Glass  * write delay. Also, there is no limit imposed on the number of bytes that can
13*2e192b24SSimon Glass  * be transferred with a single read or write.
14*2e192b24SSimon Glass  *
15*2e192b24SSimon Glass  * Use the following configuration options to ensure no unneeded performance
16*2e192b24SSimon Glass  * degradation (typical for EEPROM) is incured for FRAM memory:
17*2e192b24SSimon Glass  *
18*2e192b24SSimon Glass  * #define CONFIG_SYS_I2C_FRAM
19*2e192b24SSimon Glass  * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
20*2e192b24SSimon Glass  *
21*2e192b24SSimon Glass  */
22*2e192b24SSimon Glass 
23*2e192b24SSimon Glass #include <common.h>
24*2e192b24SSimon Glass #include <config.h>
25*2e192b24SSimon Glass #include <command.h>
26*2e192b24SSimon Glass #include <i2c.h>
27*2e192b24SSimon Glass 
28*2e192b24SSimon Glass #ifndef	CONFIG_SYS_I2C_SPEED
29*2e192b24SSimon Glass #define	CONFIG_SYS_I2C_SPEED	50000
30*2e192b24SSimon Glass #endif
31*2e192b24SSimon Glass 
32*2e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
33*2e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	0
34*2e192b24SSimon Glass #endif
35*2e192b24SSimon Glass 
36*2e192b24SSimon Glass #ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
37*2e192b24SSimon Glass #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	8
38*2e192b24SSimon Glass #endif
39*2e192b24SSimon Glass 
40*2e192b24SSimon Glass #define	EEPROM_PAGE_SIZE	(1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
41*2e192b24SSimon Glass #define	EEPROM_PAGE_OFFSET(x)	((x) & (EEPROM_PAGE_SIZE - 1))
42*2e192b24SSimon Glass 
43*2e192b24SSimon Glass /*
44*2e192b24SSimon Glass  * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
45*2e192b24SSimon Glass  *   0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
46*2e192b24SSimon Glass  *
47*2e192b24SSimon Glass  * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
48*2e192b24SSimon Glass  *   0x00000nxx for EEPROM address selectors and page number at n.
49*2e192b24SSimon Glass  */
50*2e192b24SSimon Glass #if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
51*2e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || \
52*2e192b24SSimon Glass 	(CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1) || \
53*2e192b24SSimon Glass 	(CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2)
54*2e192b24SSimon Glass #error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2
55*2e192b24SSimon Glass #endif
56*2e192b24SSimon Glass #endif
57*2e192b24SSimon Glass 
58*2e192b24SSimon Glass __weak int eeprom_write_enable(unsigned dev_addr, int state)
59*2e192b24SSimon Glass {
60*2e192b24SSimon Glass 	return 0;
61*2e192b24SSimon Glass }
62*2e192b24SSimon Glass 
63*2e192b24SSimon Glass void eeprom_init(int bus)
64*2e192b24SSimon Glass {
65*2e192b24SSimon Glass 	/* SPI EEPROM */
66*2e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
67*2e192b24SSimon Glass 	spi_init_f();
68*2e192b24SSimon Glass #endif
69*2e192b24SSimon Glass 
70*2e192b24SSimon Glass 	/* I2C EEPROM */
71*2e192b24SSimon Glass #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C_SOFT)
72*2e192b24SSimon Glass #if defined(CONFIG_SYS_I2C)
73*2e192b24SSimon Glass 	if (bus >= 0)
74*2e192b24SSimon Glass 		i2c_set_bus_num(bus);
75*2e192b24SSimon Glass #endif
76*2e192b24SSimon Glass 	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
77*2e192b24SSimon Glass #endif
78*2e192b24SSimon Glass }
79*2e192b24SSimon Glass 
80*2e192b24SSimon Glass static int eeprom_addr(unsigned dev_addr, unsigned offset, uchar *addr)
81*2e192b24SSimon Glass {
82*2e192b24SSimon Glass 	unsigned blk_off;
83*2e192b24SSimon Glass 	int alen;
84*2e192b24SSimon Glass 
85*2e192b24SSimon Glass 	blk_off = offset & 0xff;	/* block offset */
86*2e192b24SSimon Glass #if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1
87*2e192b24SSimon Glass 	addr[0] = offset >> 8;		/* block number */
88*2e192b24SSimon Glass 	addr[1] = blk_off;		/* block offset */
89*2e192b24SSimon Glass 	alen = 2;
90*2e192b24SSimon Glass #else
91*2e192b24SSimon Glass 	addr[0] = offset >> 16;		/* block number */
92*2e192b24SSimon Glass 	addr[1] = offset >>  8;		/* upper address octet */
93*2e192b24SSimon Glass 	addr[2] = blk_off;		/* lower address octet */
94*2e192b24SSimon Glass 	alen = 3;
95*2e192b24SSimon Glass #endif	/* CONFIG_SYS_I2C_EEPROM_ADDR_LEN */
96*2e192b24SSimon Glass 
97*2e192b24SSimon Glass 	addr[0] |= dev_addr;		/* insert device address */
98*2e192b24SSimon Glass 
99*2e192b24SSimon Glass 	return alen;
100*2e192b24SSimon Glass }
101*2e192b24SSimon Glass 
102*2e192b24SSimon Glass static int eeprom_len(unsigned offset, unsigned end)
103*2e192b24SSimon Glass {
104*2e192b24SSimon Glass 	unsigned len = end - offset;
105*2e192b24SSimon Glass 
106*2e192b24SSimon Glass 	/*
107*2e192b24SSimon Glass 	 * For a FRAM device there is no limit on the number of the
108*2e192b24SSimon Glass 	 * bytes that can be ccessed with the single read or write
109*2e192b24SSimon Glass 	 * operation.
110*2e192b24SSimon Glass 	 */
111*2e192b24SSimon Glass #if !defined(CONFIG_SYS_I2C_FRAM)
112*2e192b24SSimon Glass 	unsigned blk_off = offset & 0xff;
113*2e192b24SSimon Glass 	unsigned maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
114*2e192b24SSimon Glass 
115*2e192b24SSimon Glass 	if (maxlen > I2C_RXTX_LEN)
116*2e192b24SSimon Glass 		maxlen = I2C_RXTX_LEN;
117*2e192b24SSimon Glass 
118*2e192b24SSimon Glass 	if (len > maxlen)
119*2e192b24SSimon Glass 		len = maxlen;
120*2e192b24SSimon Glass #endif
121*2e192b24SSimon Glass 
122*2e192b24SSimon Glass 	return len;
123*2e192b24SSimon Glass }
124*2e192b24SSimon Glass 
125*2e192b24SSimon Glass static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
126*2e192b24SSimon Glass 			   uchar *buffer, unsigned len, bool read)
127*2e192b24SSimon Glass {
128*2e192b24SSimon Glass 	int ret = 0;
129*2e192b24SSimon Glass 
130*2e192b24SSimon Glass 	/* SPI */
131*2e192b24SSimon Glass #if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
132*2e192b24SSimon Glass 	if (read)
133*2e192b24SSimon Glass 		spi_read(addr, alen, buffer, len);
134*2e192b24SSimon Glass 	else
135*2e192b24SSimon Glass 		spi_write(addr, alen, buffer, len);
136*2e192b24SSimon Glass #else	/* I2C */
137*2e192b24SSimon Glass 
138*2e192b24SSimon Glass #if defined(CONFIG_SYS_I2C_EEPROM_BUS)
139*2e192b24SSimon Glass 	i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
140*2e192b24SSimon Glass #endif
141*2e192b24SSimon Glass 
142*2e192b24SSimon Glass 	if (read)
143*2e192b24SSimon Glass 		ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
144*2e192b24SSimon Glass 	else
145*2e192b24SSimon Glass 		ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
146*2e192b24SSimon Glass 
147*2e192b24SSimon Glass 	if (ret)
148*2e192b24SSimon Glass 		ret = 1;
149*2e192b24SSimon Glass #endif
150*2e192b24SSimon Glass 	return ret;
151*2e192b24SSimon Glass }
152*2e192b24SSimon Glass 
153*2e192b24SSimon Glass static int eeprom_rw(unsigned dev_addr, unsigned offset, uchar *buffer,
154*2e192b24SSimon Glass 		     unsigned cnt, bool read)
155*2e192b24SSimon Glass {
156*2e192b24SSimon Glass 	unsigned end = offset + cnt;
157*2e192b24SSimon Glass 	unsigned alen, len;
158*2e192b24SSimon Glass 	int rcode = 0;
159*2e192b24SSimon Glass 	uchar addr[3];
160*2e192b24SSimon Glass 
161*2e192b24SSimon Glass 	while (offset < end) {
162*2e192b24SSimon Glass 		alen = eeprom_addr(dev_addr, offset, addr);
163*2e192b24SSimon Glass 
164*2e192b24SSimon Glass 		len = eeprom_len(offset, end);
165*2e192b24SSimon Glass 
166*2e192b24SSimon Glass 		rcode = eeprom_rw_block(offset, addr, alen, buffer, len, read);
167*2e192b24SSimon Glass 
168*2e192b24SSimon Glass 		buffer += len;
169*2e192b24SSimon Glass 		offset += len;
170*2e192b24SSimon Glass 
171*2e192b24SSimon Glass 		if (!read)
172*2e192b24SSimon Glass 			udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
173*2e192b24SSimon Glass 	}
174*2e192b24SSimon Glass 
175*2e192b24SSimon Glass 	return rcode;
176*2e192b24SSimon Glass }
177*2e192b24SSimon Glass 
178*2e192b24SSimon Glass int eeprom_read(unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
179*2e192b24SSimon Glass {
180*2e192b24SSimon Glass 	/*
181*2e192b24SSimon Glass 	 * Read data until done or would cross a page boundary.
182*2e192b24SSimon Glass 	 * We must write the address again when changing pages
183*2e192b24SSimon Glass 	 * because the next page may be in a different device.
184*2e192b24SSimon Glass 	 */
185*2e192b24SSimon Glass 	return eeprom_rw(dev_addr, offset, buffer, cnt, 1);
186*2e192b24SSimon Glass }
187*2e192b24SSimon Glass 
188*2e192b24SSimon Glass int eeprom_write(unsigned dev_addr, unsigned offset,
189*2e192b24SSimon Glass 		 uchar *buffer, unsigned cnt)
190*2e192b24SSimon Glass {
191*2e192b24SSimon Glass 	int ret;
192*2e192b24SSimon Glass 
193*2e192b24SSimon Glass 	eeprom_write_enable(dev_addr, 1);
194*2e192b24SSimon Glass 
195*2e192b24SSimon Glass 	/*
196*2e192b24SSimon Glass 	 * Write data until done or would cross a write page boundary.
197*2e192b24SSimon Glass 	 * We must write the address again when changing pages
198*2e192b24SSimon Glass 	 * because the address counter only increments within a page.
199*2e192b24SSimon Glass 	 */
200*2e192b24SSimon Glass 	ret = eeprom_rw(dev_addr, offset, buffer, cnt, 0);
201*2e192b24SSimon Glass 
202*2e192b24SSimon Glass 	eeprom_write_enable(dev_addr, 0);
203*2e192b24SSimon Glass 	return ret;
204*2e192b24SSimon Glass }
205*2e192b24SSimon Glass 
206*2e192b24SSimon Glass static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
207*2e192b24SSimon Glass {
208*2e192b24SSimon Glass 	const char *const fmt =
209*2e192b24SSimon Glass 		"\nEEPROM @0x%lX %s: addr %08lx  off %04lx  count %ld ... ";
210*2e192b24SSimon Glass 	char * const *args = &argv[2];
211*2e192b24SSimon Glass 	int rcode;
212*2e192b24SSimon Glass 	ulong dev_addr, addr, off, cnt;
213*2e192b24SSimon Glass 	int bus_addr;
214*2e192b24SSimon Glass 
215*2e192b24SSimon Glass 	switch (argc) {
216*2e192b24SSimon Glass #ifdef CONFIG_SYS_DEF_EEPROM_ADDR
217*2e192b24SSimon Glass 	case 5:
218*2e192b24SSimon Glass 		bus_addr = -1;
219*2e192b24SSimon Glass 		dev_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
220*2e192b24SSimon Glass 		break;
221*2e192b24SSimon Glass #endif
222*2e192b24SSimon Glass 	case 6:
223*2e192b24SSimon Glass 		bus_addr = -1;
224*2e192b24SSimon Glass 		dev_addr = simple_strtoul(*args++, NULL, 16);
225*2e192b24SSimon Glass 		break;
226*2e192b24SSimon Glass 	case 7:
227*2e192b24SSimon Glass 		bus_addr = simple_strtoul(*args++, NULL, 16);
228*2e192b24SSimon Glass 		dev_addr = simple_strtoul(*args++, NULL, 16);
229*2e192b24SSimon Glass 		break;
230*2e192b24SSimon Glass 	default:
231*2e192b24SSimon Glass 		return CMD_RET_USAGE;
232*2e192b24SSimon Glass 	}
233*2e192b24SSimon Glass 
234*2e192b24SSimon Glass 	addr = simple_strtoul(*args++, NULL, 16);
235*2e192b24SSimon Glass 	off = simple_strtoul(*args++, NULL, 16);
236*2e192b24SSimon Glass 	cnt = simple_strtoul(*args++, NULL, 16);
237*2e192b24SSimon Glass 
238*2e192b24SSimon Glass 	eeprom_init(bus_addr);
239*2e192b24SSimon Glass 
240*2e192b24SSimon Glass 	if (strcmp(argv[1], "read") == 0) {
241*2e192b24SSimon Glass 		printf(fmt, dev_addr, argv[1], addr, off, cnt);
242*2e192b24SSimon Glass 
243*2e192b24SSimon Glass 		rcode = eeprom_read(dev_addr, off, (uchar *)addr, cnt);
244*2e192b24SSimon Glass 
245*2e192b24SSimon Glass 		puts("done\n");
246*2e192b24SSimon Glass 		return rcode;
247*2e192b24SSimon Glass 	} else if (strcmp(argv[1], "write") == 0) {
248*2e192b24SSimon Glass 		printf(fmt, dev_addr, argv[1], addr, off, cnt);
249*2e192b24SSimon Glass 
250*2e192b24SSimon Glass 		rcode = eeprom_write(dev_addr, off, (uchar *)addr, cnt);
251*2e192b24SSimon Glass 
252*2e192b24SSimon Glass 		puts("done\n");
253*2e192b24SSimon Glass 		return rcode;
254*2e192b24SSimon Glass 	}
255*2e192b24SSimon Glass 
256*2e192b24SSimon Glass 	return CMD_RET_USAGE;
257*2e192b24SSimon Glass }
258*2e192b24SSimon Glass 
259*2e192b24SSimon Glass U_BOOT_CMD(
260*2e192b24SSimon Glass 	eeprom,	7,	1,	do_eeprom,
261*2e192b24SSimon Glass 	"EEPROM sub-system",
262*2e192b24SSimon Glass 	"read  <bus> <devaddr> addr off cnt\n"
263*2e192b24SSimon Glass 	"eeprom write <bus> <devaddr> addr off cnt\n"
264*2e192b24SSimon Glass 	"       - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
265*2e192b24SSimon Glass )
266