xref: /rk3399_rockchip-uboot/board/compulab/common/eeprom.c (revision 53af877fd2b509bed0ba84fc0fb2845e0c149e34)
1689be5f8SIgor Grinberg /*
2689be5f8SIgor Grinberg  * (C) Copyright 2011 CompuLab, Ltd. <www.compulab.co.il>
3689be5f8SIgor Grinberg  *
4689be5f8SIgor Grinberg  * Authors: Nikita Kiryanov <nikita@compulab.co.il>
5689be5f8SIgor Grinberg  *	    Igor Grinberg <grinberg@compulab.co.il>
6689be5f8SIgor Grinberg  *
7689be5f8SIgor Grinberg  * SPDX-License-Identifier:	GPL-2.0+
8689be5f8SIgor Grinberg  */
9689be5f8SIgor Grinberg 
10689be5f8SIgor Grinberg #include <common.h>
11689be5f8SIgor Grinberg #include <i2c.h>
12*53af877fSNikita Kiryanov #include "eeprom.h"
13689be5f8SIgor Grinberg 
14d3f041c0SIgor Grinberg #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
15d3f041c0SIgor Grinberg # define CONFIG_SYS_I2C_EEPROM_ADDR	0x50
16d3f041c0SIgor Grinberg # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
17d3f041c0SIgor Grinberg #endif
18d3f041c0SIgor Grinberg 
197d2f669bSNikita Kiryanov #ifndef CONFIG_SYS_I2C_EEPROM_BUS
207d2f669bSNikita Kiryanov #define CONFIG_SYS_I2C_EEPROM_BUS	0
217d2f669bSNikita Kiryanov #endif
227d2f669bSNikita Kiryanov 
23689be5f8SIgor Grinberg #define EEPROM_LAYOUT_VER_OFFSET	44
24689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET		20
25689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET_LEGACY	8
26689be5f8SIgor Grinberg #define BOARD_REV_OFFSET		0
27689be5f8SIgor Grinberg #define BOARD_REV_OFFSET_LEGACY		6
28689be5f8SIgor Grinberg #define BOARD_REV_SIZE			2
29*53af877fSNikita Kiryanov #define PRODUCT_NAME_OFFSET		128
30*53af877fSNikita Kiryanov #define PRODUCT_NAME_SIZE		16
31689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET			4
32689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET_LEGACY		0
33689be5f8SIgor Grinberg 
34689be5f8SIgor Grinberg #define LAYOUT_INVALID	0
35689be5f8SIgor Grinberg #define LAYOUT_LEGACY	0xff
36689be5f8SIgor Grinberg 
37e7a2447bSNikita Kiryanov static int cl_eeprom_bus;
38689be5f8SIgor Grinberg static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */
39689be5f8SIgor Grinberg 
40689be5f8SIgor Grinberg static int cl_eeprom_read(uint offset, uchar *buf, int len)
41689be5f8SIgor Grinberg {
4252658fdaSNikita Kiryanov 	int res;
4352658fdaSNikita Kiryanov 	unsigned int current_i2c_bus = i2c_get_bus_num();
4452658fdaSNikita Kiryanov 
45e7a2447bSNikita Kiryanov 	res = i2c_set_bus_num(cl_eeprom_bus);
4652658fdaSNikita Kiryanov 	if (res < 0)
4752658fdaSNikita Kiryanov 		return res;
4852658fdaSNikita Kiryanov 
4952658fdaSNikita Kiryanov 	res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset,
50689be5f8SIgor Grinberg 			CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len);
5152658fdaSNikita Kiryanov 
5252658fdaSNikita Kiryanov 	i2c_set_bus_num(current_i2c_bus);
5352658fdaSNikita Kiryanov 
5452658fdaSNikita Kiryanov 	return res;
55689be5f8SIgor Grinberg }
56689be5f8SIgor Grinberg 
57e7a2447bSNikita Kiryanov static int cl_eeprom_setup(uint eeprom_bus)
58689be5f8SIgor Grinberg {
59689be5f8SIgor Grinberg 	int res;
60689be5f8SIgor Grinberg 
61e7a2447bSNikita Kiryanov 	/*
62e7a2447bSNikita Kiryanov 	 * We know the setup was already done when the layout is set to a valid
63e7a2447bSNikita Kiryanov 	 * value and we're using the same bus as before.
64e7a2447bSNikita Kiryanov 	 */
65e7a2447bSNikita Kiryanov 	if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus)
66689be5f8SIgor Grinberg 		return 0;
67689be5f8SIgor Grinberg 
68e7a2447bSNikita Kiryanov 	cl_eeprom_bus = eeprom_bus;
69689be5f8SIgor Grinberg 	res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET,
70689be5f8SIgor Grinberg 			     (uchar *)&cl_eeprom_layout, 1);
71689be5f8SIgor Grinberg 	if (res) {
72689be5f8SIgor Grinberg 		cl_eeprom_layout = LAYOUT_INVALID;
73689be5f8SIgor Grinberg 		return res;
74689be5f8SIgor Grinberg 	}
75689be5f8SIgor Grinberg 
76689be5f8SIgor Grinberg 	if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20)
77689be5f8SIgor Grinberg 		cl_eeprom_layout = LAYOUT_LEGACY;
78689be5f8SIgor Grinberg 
79689be5f8SIgor Grinberg 	return 0;
80689be5f8SIgor Grinberg }
81689be5f8SIgor Grinberg 
82689be5f8SIgor Grinberg void get_board_serial(struct tag_serialnr *serialnr)
83689be5f8SIgor Grinberg {
84689be5f8SIgor Grinberg 	u32 serial[2];
85689be5f8SIgor Grinberg 	uint offset;
86689be5f8SIgor Grinberg 
87689be5f8SIgor Grinberg 	memset(serialnr, 0, sizeof(*serialnr));
88689be5f8SIgor Grinberg 
89e7a2447bSNikita Kiryanov 	if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
90689be5f8SIgor Grinberg 		return;
91689be5f8SIgor Grinberg 
92689be5f8SIgor Grinberg 	offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
93689be5f8SIgor Grinberg 		BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY;
94689be5f8SIgor Grinberg 
95689be5f8SIgor Grinberg 	if (cl_eeprom_read(offset, (uchar *)serial, 8))
96689be5f8SIgor Grinberg 		return;
97689be5f8SIgor Grinberg 
98689be5f8SIgor Grinberg 	if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) {
99689be5f8SIgor Grinberg 		serialnr->low = serial[0];
100689be5f8SIgor Grinberg 		serialnr->high = serial[1];
101689be5f8SIgor Grinberg 	}
102689be5f8SIgor Grinberg }
103689be5f8SIgor Grinberg 
104689be5f8SIgor Grinberg /*
105689be5f8SIgor Grinberg  * Routine: cl_eeprom_read_mac_addr
106689be5f8SIgor Grinberg  * Description: read mac address and store it in buf.
107689be5f8SIgor Grinberg  */
108e7a2447bSNikita Kiryanov int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus)
109689be5f8SIgor Grinberg {
110689be5f8SIgor Grinberg 	uint offset;
111e93e809fSNikita Kiryanov 	int err;
112689be5f8SIgor Grinberg 
113e93e809fSNikita Kiryanov 	err = cl_eeprom_setup(eeprom_bus);
114e93e809fSNikita Kiryanov 	if (err)
115e93e809fSNikita Kiryanov 		return err;
116689be5f8SIgor Grinberg 
117689be5f8SIgor Grinberg 	offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
118689be5f8SIgor Grinberg 			MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY;
119689be5f8SIgor Grinberg 
120689be5f8SIgor Grinberg 	return cl_eeprom_read(offset, buf, 6);
121689be5f8SIgor Grinberg }
122689be5f8SIgor Grinberg 
123a937fd16SIgor Grinberg static u32 board_rev;
124a937fd16SIgor Grinberg 
125689be5f8SIgor Grinberg /*
126689be5f8SIgor Grinberg  * Routine: cl_eeprom_get_board_rev
127689be5f8SIgor Grinberg  * Description: read system revision from eeprom
128689be5f8SIgor Grinberg  */
12972898ac7SNikita Kiryanov u32 cl_eeprom_get_board_rev(uint eeprom_bus)
130689be5f8SIgor Grinberg {
131689be5f8SIgor Grinberg 	char str[5]; /* Legacy representation can contain at most 4 digits */
132689be5f8SIgor Grinberg 	uint offset = BOARD_REV_OFFSET_LEGACY;
133689be5f8SIgor Grinberg 
134a937fd16SIgor Grinberg 	if (board_rev)
135a937fd16SIgor Grinberg 		return board_rev;
136a937fd16SIgor Grinberg 
13772898ac7SNikita Kiryanov 	if (cl_eeprom_setup(eeprom_bus))
138689be5f8SIgor Grinberg 		return 0;
139689be5f8SIgor Grinberg 
140689be5f8SIgor Grinberg 	if (cl_eeprom_layout != LAYOUT_LEGACY)
141689be5f8SIgor Grinberg 		offset = BOARD_REV_OFFSET;
142689be5f8SIgor Grinberg 
143a937fd16SIgor Grinberg 	if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE))
144689be5f8SIgor Grinberg 		return 0;
145689be5f8SIgor Grinberg 
146689be5f8SIgor Grinberg 	/*
147689be5f8SIgor Grinberg 	 * Convert legacy syntactic representation to semantic
148689be5f8SIgor Grinberg 	 * representation. i.e. for rev 1.00: 0x100 --> 0x64
149689be5f8SIgor Grinberg 	 */
150689be5f8SIgor Grinberg 	if (cl_eeprom_layout == LAYOUT_LEGACY) {
151a937fd16SIgor Grinberg 		sprintf(str, "%x", board_rev);
152a937fd16SIgor Grinberg 		board_rev = simple_strtoul(str, NULL, 10);
153689be5f8SIgor Grinberg 	}
154689be5f8SIgor Grinberg 
155a937fd16SIgor Grinberg 	return board_rev;
156689be5f8SIgor Grinberg };
157*53af877fSNikita Kiryanov 
158*53af877fSNikita Kiryanov /*
159*53af877fSNikita Kiryanov  * Routine: cl_eeprom_get_board_rev
160*53af877fSNikita Kiryanov  * Description: read system revision from eeprom
161*53af877fSNikita Kiryanov  *
162*53af877fSNikita Kiryanov  * @buf: buffer to store the product name
163*53af877fSNikita Kiryanov  * @eeprom_bus: i2c bus num of the eeprom
164*53af877fSNikita Kiryanov  *
165*53af877fSNikita Kiryanov  * @return: 0 on success, < 0 on failure
166*53af877fSNikita Kiryanov  */
167*53af877fSNikita Kiryanov int cl_eeprom_get_product_name(uchar *buf, uint eeprom_bus)
168*53af877fSNikita Kiryanov {
169*53af877fSNikita Kiryanov 	int err;
170*53af877fSNikita Kiryanov 
171*53af877fSNikita Kiryanov 	if (buf == NULL)
172*53af877fSNikita Kiryanov 		return -EINVAL;
173*53af877fSNikita Kiryanov 
174*53af877fSNikita Kiryanov 	err = cl_eeprom_setup(eeprom_bus);
175*53af877fSNikita Kiryanov 	if (err)
176*53af877fSNikita Kiryanov 		return err;
177*53af877fSNikita Kiryanov 
178*53af877fSNikita Kiryanov 	err = cl_eeprom_read(PRODUCT_NAME_OFFSET, buf, PRODUCT_NAME_SIZE);
179*53af877fSNikita Kiryanov 	if (!err) /* Protect ourselves from invalid data (unterminated str) */
180*53af877fSNikita Kiryanov 		buf[PRODUCT_NAME_SIZE - 1] = '\0';
181*53af877fSNikita Kiryanov 
182*53af877fSNikita Kiryanov 	return err;
183*53af877fSNikita Kiryanov }
184