]> git.sur5r.net Git - u-boot/blob - board/compulab/common/eeprom.c
compulab: eeprom: add support for obtaining product name
[u-boot] / board / compulab / common / eeprom.c
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 #include "eeprom.h"
13
14 #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
15 # define CONFIG_SYS_I2C_EEPROM_ADDR     0x50
16 # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
17 #endif
18
19 #ifndef CONFIG_SYS_I2C_EEPROM_BUS
20 #define CONFIG_SYS_I2C_EEPROM_BUS       0
21 #endif
22
23 #define EEPROM_LAYOUT_VER_OFFSET        44
24 #define BOARD_SERIAL_OFFSET             20
25 #define BOARD_SERIAL_OFFSET_LEGACY      8
26 #define BOARD_REV_OFFSET                0
27 #define BOARD_REV_OFFSET_LEGACY         6
28 #define BOARD_REV_SIZE                  2
29 #define PRODUCT_NAME_OFFSET             128
30 #define PRODUCT_NAME_SIZE               16
31 #define MAC_ADDR_OFFSET                 4
32 #define MAC_ADDR_OFFSET_LEGACY          0
33
34 #define LAYOUT_INVALID  0
35 #define LAYOUT_LEGACY   0xff
36
37 static int cl_eeprom_bus;
38 static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */
39
40 static int cl_eeprom_read(uint offset, uchar *buf, int len)
41 {
42         int res;
43         unsigned int current_i2c_bus = i2c_get_bus_num();
44
45         res = i2c_set_bus_num(cl_eeprom_bus);
46         if (res < 0)
47                 return res;
48
49         res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset,
50                         CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len);
51
52         i2c_set_bus_num(current_i2c_bus);
53
54         return res;
55 }
56
57 static int cl_eeprom_setup(uint eeprom_bus)
58 {
59         int res;
60
61         /*
62          * We know the setup was already done when the layout is set to a valid
63          * value and we're using the same bus as before.
64          */
65         if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus)
66                 return 0;
67
68         cl_eeprom_bus = eeprom_bus;
69         res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET,
70                              (uchar *)&cl_eeprom_layout, 1);
71         if (res) {
72                 cl_eeprom_layout = LAYOUT_INVALID;
73                 return res;
74         }
75
76         if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20)
77                 cl_eeprom_layout = LAYOUT_LEGACY;
78
79         return 0;
80 }
81
82 void get_board_serial(struct tag_serialnr *serialnr)
83 {
84         u32 serial[2];
85         uint offset;
86
87         memset(serialnr, 0, sizeof(*serialnr));
88
89         if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
90                 return;
91
92         offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
93                 BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY;
94
95         if (cl_eeprom_read(offset, (uchar *)serial, 8))
96                 return;
97
98         if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) {
99                 serialnr->low = serial[0];
100                 serialnr->high = serial[1];
101         }
102 }
103
104 /*
105  * Routine: cl_eeprom_read_mac_addr
106  * Description: read mac address and store it in buf.
107  */
108 int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus)
109 {
110         uint offset;
111         int err;
112
113         err = cl_eeprom_setup(eeprom_bus);
114         if (err)
115                 return err;
116
117         offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
118                         MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY;
119
120         return cl_eeprom_read(offset, buf, 6);
121 }
122
123 static u32 board_rev;
124
125 /*
126  * Routine: cl_eeprom_get_board_rev
127  * Description: read system revision from eeprom
128  */
129 u32 cl_eeprom_get_board_rev(uint eeprom_bus)
130 {
131         char str[5]; /* Legacy representation can contain at most 4 digits */
132         uint offset = BOARD_REV_OFFSET_LEGACY;
133
134         if (board_rev)
135                 return board_rev;
136
137         if (cl_eeprom_setup(eeprom_bus))
138                 return 0;
139
140         if (cl_eeprom_layout != LAYOUT_LEGACY)
141                 offset = BOARD_REV_OFFSET;
142
143         if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE))
144                 return 0;
145
146         /*
147          * Convert legacy syntactic representation to semantic
148          * representation. i.e. for rev 1.00: 0x100 --> 0x64
149          */
150         if (cl_eeprom_layout == LAYOUT_LEGACY) {
151                 sprintf(str, "%x", board_rev);
152                 board_rev = simple_strtoul(str, NULL, 10);
153         }
154
155         return board_rev;
156 };
157
158 /*
159  * Routine: cl_eeprom_get_board_rev
160  * Description: read system revision from eeprom
161  *
162  * @buf: buffer to store the product name
163  * @eeprom_bus: i2c bus num of the eeprom
164  *
165  * @return: 0 on success, < 0 on failure
166  */
167 int cl_eeprom_get_product_name(uchar *buf, uint eeprom_bus)
168 {
169         int err;
170
171         if (buf == NULL)
172                 return -EINVAL;
173
174         err = cl_eeprom_setup(eeprom_bus);
175         if (err)
176                 return err;
177
178         err = cl_eeprom_read(PRODUCT_NAME_OFFSET, buf, PRODUCT_NAME_SIZE);
179         if (!err) /* Protect ourselves from invalid data (unterminated str) */
180                 buf[PRODUCT_NAME_SIZE - 1] = '\0';
181
182         return err;
183 }