xref: /openbmc/u-boot/board/compulab/common/eeprom.c (revision fd697ecf)
1 /*
2  * (C) Copyright 2011 CompuLab, Ltd. <www.compulab.co.il>
3  *
4  * Authors: Nikita Kiryanov <nikita@compulab.co.il>
5  *	    Igor Grinberg <grinberg@compulab.co.il>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <i2c.h>
12 
13 #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
14 # define CONFIG_SYS_I2C_EEPROM_ADDR	0x50
15 # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
16 #endif
17 
18 #ifndef CONFIG_SYS_I2C_EEPROM_BUS
19 #define CONFIG_SYS_I2C_EEPROM_BUS	0
20 #endif
21 
22 #define EEPROM_LAYOUT_VER_OFFSET	44
23 #define BOARD_SERIAL_OFFSET		20
24 #define BOARD_SERIAL_OFFSET_LEGACY	8
25 #define BOARD_REV_OFFSET		0
26 #define BOARD_REV_OFFSET_LEGACY		6
27 #define BOARD_REV_SIZE			2
28 #define MAC_ADDR_OFFSET			4
29 #define MAC_ADDR_OFFSET_LEGACY		0
30 
31 #define LAYOUT_INVALID	0
32 #define LAYOUT_LEGACY	0xff
33 
34 static int cl_eeprom_bus;
35 static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */
36 
37 static int cl_eeprom_read(uint offset, uchar *buf, int len)
38 {
39 	int res;
40 	unsigned int current_i2c_bus = i2c_get_bus_num();
41 
42 	res = i2c_set_bus_num(cl_eeprom_bus);
43 	if (res < 0)
44 		return res;
45 
46 	res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset,
47 			CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len);
48 
49 	i2c_set_bus_num(current_i2c_bus);
50 
51 	return res;
52 }
53 
54 static int cl_eeprom_setup(uint eeprom_bus)
55 {
56 	int res;
57 
58 	/*
59 	 * We know the setup was already done when the layout is set to a valid
60 	 * value and we're using the same bus as before.
61 	 */
62 	if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus)
63 		return 0;
64 
65 	cl_eeprom_bus = eeprom_bus;
66 	res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET,
67 			     (uchar *)&cl_eeprom_layout, 1);
68 	if (res) {
69 		cl_eeprom_layout = LAYOUT_INVALID;
70 		return res;
71 	}
72 
73 	if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20)
74 		cl_eeprom_layout = LAYOUT_LEGACY;
75 
76 	return 0;
77 }
78 
79 void get_board_serial(struct tag_serialnr *serialnr)
80 {
81 	u32 serial[2];
82 	uint offset;
83 
84 	memset(serialnr, 0, sizeof(*serialnr));
85 
86 	if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
87 		return;
88 
89 	offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
90 		BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY;
91 
92 	if (cl_eeprom_read(offset, (uchar *)serial, 8))
93 		return;
94 
95 	if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) {
96 		serialnr->low = serial[0];
97 		serialnr->high = serial[1];
98 	}
99 }
100 
101 /*
102  * Routine: cl_eeprom_read_mac_addr
103  * Description: read mac address and store it in buf.
104  */
105 int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus)
106 {
107 	uint offset;
108 
109 	if (cl_eeprom_setup(eeprom_bus))
110 		return 0;
111 
112 	offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
113 			MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY;
114 
115 	return cl_eeprom_read(offset, buf, 6);
116 }
117 
118 static u32 board_rev;
119 
120 /*
121  * Routine: cl_eeprom_get_board_rev
122  * Description: read system revision from eeprom
123  */
124 u32 cl_eeprom_get_board_rev(void)
125 {
126 	char str[5]; /* Legacy representation can contain at most 4 digits */
127 	uint offset = BOARD_REV_OFFSET_LEGACY;
128 
129 	if (board_rev)
130 		return board_rev;
131 
132 	if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
133 		return 0;
134 
135 	if (cl_eeprom_layout != LAYOUT_LEGACY)
136 		offset = BOARD_REV_OFFSET;
137 
138 	if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE))
139 		return 0;
140 
141 	/*
142 	 * Convert legacy syntactic representation to semantic
143 	 * representation. i.e. for rev 1.00: 0x100 --> 0x64
144 	 */
145 	if (cl_eeprom_layout == LAYOUT_LEGACY) {
146 		sprintf(str, "%x", board_rev);
147 		board_rev = simple_strtoul(str, NULL, 10);
148 	}
149 
150 	return board_rev;
151 };
152