1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2011 CompuLab, Ltd. <www.compulab.co.il>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Authors: Nikita Kiryanov <nikita@compulab.co.il>
5*4882a593Smuzhiyun * Igor Grinberg <grinberg@compulab.co.il>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <i2c.h>
12*4882a593Smuzhiyun #include <eeprom_layout.h>
13*4882a593Smuzhiyun #include <eeprom_field.h>
14*4882a593Smuzhiyun #include <asm/setup.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include "eeprom.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
19*4882a593Smuzhiyun # define CONFIG_SYS_I2C_EEPROM_ADDR 0x50
20*4882a593Smuzhiyun # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
21*4882a593Smuzhiyun #endif
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #ifndef CONFIG_SYS_I2C_EEPROM_BUS
24*4882a593Smuzhiyun #define CONFIG_SYS_I2C_EEPROM_BUS 0
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define EEPROM_LAYOUT_VER_OFFSET 44
28*4882a593Smuzhiyun #define BOARD_SERIAL_OFFSET 20
29*4882a593Smuzhiyun #define BOARD_SERIAL_OFFSET_LEGACY 8
30*4882a593Smuzhiyun #define BOARD_REV_OFFSET 0
31*4882a593Smuzhiyun #define BOARD_REV_OFFSET_LEGACY 6
32*4882a593Smuzhiyun #define BOARD_REV_SIZE 2
33*4882a593Smuzhiyun #define PRODUCT_NAME_OFFSET 128
34*4882a593Smuzhiyun #define PRODUCT_NAME_SIZE 16
35*4882a593Smuzhiyun #define MAC_ADDR_OFFSET 4
36*4882a593Smuzhiyun #define MAC_ADDR_OFFSET_LEGACY 0
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define LAYOUT_INVALID 0
39*4882a593Smuzhiyun #define LAYOUT_LEGACY 0xff
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun static int cl_eeprom_bus;
42*4882a593Smuzhiyun static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */
43*4882a593Smuzhiyun
cl_eeprom_read(uint offset,uchar * buf,int len)44*4882a593Smuzhiyun static int cl_eeprom_read(uint offset, uchar *buf, int len)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun int res;
47*4882a593Smuzhiyun unsigned int current_i2c_bus = i2c_get_bus_num();
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun res = i2c_set_bus_num(cl_eeprom_bus);
50*4882a593Smuzhiyun if (res < 0)
51*4882a593Smuzhiyun return res;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset,
54*4882a593Smuzhiyun CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun i2c_set_bus_num(current_i2c_bus);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return res;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
cl_eeprom_setup(uint eeprom_bus)61*4882a593Smuzhiyun static int cl_eeprom_setup(uint eeprom_bus)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun int res;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * We know the setup was already done when the layout is set to a valid
67*4882a593Smuzhiyun * value and we're using the same bus as before.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus)
70*4882a593Smuzhiyun return 0;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun cl_eeprom_bus = eeprom_bus;
73*4882a593Smuzhiyun res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET,
74*4882a593Smuzhiyun (uchar *)&cl_eeprom_layout, 1);
75*4882a593Smuzhiyun if (res) {
76*4882a593Smuzhiyun cl_eeprom_layout = LAYOUT_INVALID;
77*4882a593Smuzhiyun return res;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20)
81*4882a593Smuzhiyun cl_eeprom_layout = LAYOUT_LEGACY;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
get_board_serial(struct tag_serialnr * serialnr)86*4882a593Smuzhiyun void get_board_serial(struct tag_serialnr *serialnr)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun u32 serial[2];
89*4882a593Smuzhiyun uint offset;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun memset(serialnr, 0, sizeof(*serialnr));
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
94*4882a593Smuzhiyun return;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
97*4882a593Smuzhiyun BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (cl_eeprom_read(offset, (uchar *)serial, 8))
100*4882a593Smuzhiyun return;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) {
103*4882a593Smuzhiyun serialnr->low = serial[0];
104*4882a593Smuzhiyun serialnr->high = serial[1];
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * Routine: cl_eeprom_read_mac_addr
110*4882a593Smuzhiyun * Description: read mac address and store it in buf.
111*4882a593Smuzhiyun */
cl_eeprom_read_mac_addr(uchar * buf,uint eeprom_bus)112*4882a593Smuzhiyun int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun uint offset;
115*4882a593Smuzhiyun int err;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun err = cl_eeprom_setup(eeprom_bus);
118*4882a593Smuzhiyun if (err)
119*4882a593Smuzhiyun return err;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
122*4882a593Smuzhiyun MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return cl_eeprom_read(offset, buf, 6);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun static u32 board_rev;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun * Routine: cl_eeprom_get_board_rev
131*4882a593Smuzhiyun * Description: read system revision from eeprom
132*4882a593Smuzhiyun */
cl_eeprom_get_board_rev(uint eeprom_bus)133*4882a593Smuzhiyun u32 cl_eeprom_get_board_rev(uint eeprom_bus)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun char str[5]; /* Legacy representation can contain at most 4 digits */
136*4882a593Smuzhiyun uint offset = BOARD_REV_OFFSET_LEGACY;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (board_rev)
139*4882a593Smuzhiyun return board_rev;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (cl_eeprom_setup(eeprom_bus))
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (cl_eeprom_layout != LAYOUT_LEGACY)
145*4882a593Smuzhiyun offset = BOARD_REV_OFFSET;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE))
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun * Convert legacy syntactic representation to semantic
152*4882a593Smuzhiyun * representation. i.e. for rev 1.00: 0x100 --> 0x64
153*4882a593Smuzhiyun */
154*4882a593Smuzhiyun if (cl_eeprom_layout == LAYOUT_LEGACY) {
155*4882a593Smuzhiyun sprintf(str, "%x", board_rev);
156*4882a593Smuzhiyun board_rev = simple_strtoul(str, NULL, 10);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun return board_rev;
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun * Routine: cl_eeprom_get_board_rev
164*4882a593Smuzhiyun * Description: read system revision from eeprom
165*4882a593Smuzhiyun *
166*4882a593Smuzhiyun * @buf: buffer to store the product name
167*4882a593Smuzhiyun * @eeprom_bus: i2c bus num of the eeprom
168*4882a593Smuzhiyun *
169*4882a593Smuzhiyun * @return: 0 on success, < 0 on failure
170*4882a593Smuzhiyun */
cl_eeprom_get_product_name(uchar * buf,uint eeprom_bus)171*4882a593Smuzhiyun int cl_eeprom_get_product_name(uchar *buf, uint eeprom_bus)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun int err;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (buf == NULL)
176*4882a593Smuzhiyun return -EINVAL;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun err = cl_eeprom_setup(eeprom_bus);
179*4882a593Smuzhiyun if (err)
180*4882a593Smuzhiyun return err;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun err = cl_eeprom_read(PRODUCT_NAME_OFFSET, buf, PRODUCT_NAME_SIZE);
183*4882a593Smuzhiyun if (!err) /* Protect ourselves from invalid data (unterminated str) */
184*4882a593Smuzhiyun buf[PRODUCT_NAME_SIZE - 1] = '\0';
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return err;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun #ifdef CONFIG_CMD_EEPROM_LAYOUT
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun * eeprom_field_print_bin_ver() - print a "version field" which contains binary
192*4882a593Smuzhiyun * data
193*4882a593Smuzhiyun *
194*4882a593Smuzhiyun * Treat the field data as simple binary data, and print it formatted as a
195*4882a593Smuzhiyun * version number (2 digits after decimal point).
196*4882a593Smuzhiyun * The field size must be exactly 2 bytes.
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * Sample output:
199*4882a593Smuzhiyun * Field Name 123.45
200*4882a593Smuzhiyun *
201*4882a593Smuzhiyun * @field: an initialized field to print
202*4882a593Smuzhiyun */
eeprom_field_print_bin_ver(const struct eeprom_field * field)203*4882a593Smuzhiyun void eeprom_field_print_bin_ver(const struct eeprom_field *field)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun if ((field->buf[0] == 0xff) && (field->buf[1] == 0xff)) {
206*4882a593Smuzhiyun field->buf[0] = 0;
207*4882a593Smuzhiyun field->buf[1] = 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun printf(PRINT_FIELD_SEGMENT, field->name);
211*4882a593Smuzhiyun int major = (field->buf[1] << 8 | field->buf[0]) / 100;
212*4882a593Smuzhiyun int minor = (field->buf[1] << 8 | field->buf[0]) - major * 100;
213*4882a593Smuzhiyun printf("%d.%02d\n", major, minor);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /**
217*4882a593Smuzhiyun * eeprom_field_update_bin_ver() - update a "version field" which contains
218*4882a593Smuzhiyun * binary data
219*4882a593Smuzhiyun *
220*4882a593Smuzhiyun * This function takes a version string in the form of x.y (x and y are both
221*4882a593Smuzhiyun * decimal values, y is limited to two digits), translates it to the binary
222*4882a593Smuzhiyun * form, then writes it to the field. The field size must be exactly 2 bytes.
223*4882a593Smuzhiyun *
224*4882a593Smuzhiyun * This function strictly enforces the data syntax, and will not update the
225*4882a593Smuzhiyun * field if there's any deviation from it. It also protects from overflow.
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun * @field: an initialized field
228*4882a593Smuzhiyun * @value: a version string
229*4882a593Smuzhiyun *
230*4882a593Smuzhiyun * Returns 0 on success, -1 on failure.
231*4882a593Smuzhiyun */
eeprom_field_update_bin_ver(struct eeprom_field * field,char * value)232*4882a593Smuzhiyun int eeprom_field_update_bin_ver(struct eeprom_field *field, char *value)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun char *endptr;
235*4882a593Smuzhiyun char *tok = strtok(value, ".");
236*4882a593Smuzhiyun if (tok == NULL)
237*4882a593Smuzhiyun return -1;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun int num = simple_strtol(tok, &endptr, 0);
240*4882a593Smuzhiyun if (*endptr != '\0')
241*4882a593Smuzhiyun return -1;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun tok = strtok(NULL, "");
244*4882a593Smuzhiyun if (tok == NULL)
245*4882a593Smuzhiyun return -1;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun int remainder = simple_strtol(tok, &endptr, 0);
248*4882a593Smuzhiyun if (*endptr != '\0')
249*4882a593Smuzhiyun return -1;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun num = num * 100 + remainder;
252*4882a593Smuzhiyun if (num >> 16)
253*4882a593Smuzhiyun return -1;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun field->buf[0] = (unsigned char)num;
256*4882a593Smuzhiyun field->buf[1] = num >> 8;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun return 0;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
262*4882a593Smuzhiyun "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /**
265*4882a593Smuzhiyun * eeprom_field_print_date() - print a field which contains date data
266*4882a593Smuzhiyun *
267*4882a593Smuzhiyun * Treat the field data as simple binary data, and print it formatted as a date.
268*4882a593Smuzhiyun * Sample output:
269*4882a593Smuzhiyun * Field Name 07/Feb/2014
270*4882a593Smuzhiyun * Field Name 56/BAD/9999
271*4882a593Smuzhiyun *
272*4882a593Smuzhiyun * @field: an initialized field to print
273*4882a593Smuzhiyun */
eeprom_field_print_date(const struct eeprom_field * field)274*4882a593Smuzhiyun void eeprom_field_print_date(const struct eeprom_field *field)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun printf(PRINT_FIELD_SEGMENT, field->name);
277*4882a593Smuzhiyun printf("%02d/", field->buf[0]);
278*4882a593Smuzhiyun if (field->buf[1] >= 1 && field->buf[1] <= 12)
279*4882a593Smuzhiyun printf("%s", months[field->buf[1] - 1]);
280*4882a593Smuzhiyun else
281*4882a593Smuzhiyun printf("BAD");
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun printf("/%d\n", field->buf[3] << 8 | field->buf[2]);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
validate_date(unsigned char day,unsigned char month,unsigned int year)286*4882a593Smuzhiyun static int validate_date(unsigned char day, unsigned char month,
287*4882a593Smuzhiyun unsigned int year)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int days_in_february;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun switch (month) {
292*4882a593Smuzhiyun case 0:
293*4882a593Smuzhiyun case 2:
294*4882a593Smuzhiyun case 4:
295*4882a593Smuzhiyun case 6:
296*4882a593Smuzhiyun case 7:
297*4882a593Smuzhiyun case 9:
298*4882a593Smuzhiyun case 11:
299*4882a593Smuzhiyun if (day > 31)
300*4882a593Smuzhiyun return -1;
301*4882a593Smuzhiyun break;
302*4882a593Smuzhiyun case 3:
303*4882a593Smuzhiyun case 5:
304*4882a593Smuzhiyun case 8:
305*4882a593Smuzhiyun case 10:
306*4882a593Smuzhiyun if (day > 30)
307*4882a593Smuzhiyun return -1;
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun case 1:
310*4882a593Smuzhiyun days_in_february = 28;
311*4882a593Smuzhiyun if (year % 4 == 0) {
312*4882a593Smuzhiyun if (year % 100 != 0)
313*4882a593Smuzhiyun days_in_february = 29;
314*4882a593Smuzhiyun else if (year % 400 == 0)
315*4882a593Smuzhiyun days_in_february = 29;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (day > days_in_february)
319*4882a593Smuzhiyun return -1;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun break;
322*4882a593Smuzhiyun default:
323*4882a593Smuzhiyun return -1;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /**
330*4882a593Smuzhiyun * eeprom_field_update_date() - update a date field which contains binary data
331*4882a593Smuzhiyun *
332*4882a593Smuzhiyun * This function takes a date string in the form of x/Mon/y (x and y are both
333*4882a593Smuzhiyun * decimal values), translates it to the binary representation, then writes it
334*4882a593Smuzhiyun * to the field.
335*4882a593Smuzhiyun *
336*4882a593Smuzhiyun * This function strictly enforces the data syntax, and will not update the
337*4882a593Smuzhiyun * field if there's any deviation from it. It also protects from overflow in the
338*4882a593Smuzhiyun * year value, and checks the validity of the date.
339*4882a593Smuzhiyun *
340*4882a593Smuzhiyun * @field: an initialized field
341*4882a593Smuzhiyun * @value: a date string
342*4882a593Smuzhiyun *
343*4882a593Smuzhiyun * Returns 0 on success, -1 on failure.
344*4882a593Smuzhiyun */
eeprom_field_update_date(struct eeprom_field * field,char * value)345*4882a593Smuzhiyun int eeprom_field_update_date(struct eeprom_field *field, char *value)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun char *endptr;
348*4882a593Smuzhiyun char *tok1 = strtok(value, "/");
349*4882a593Smuzhiyun char *tok2 = strtok(NULL, "/");
350*4882a593Smuzhiyun char *tok3 = strtok(NULL, "/");
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (tok1 == NULL || tok2 == NULL || tok3 == NULL) {
353*4882a593Smuzhiyun printf("%s: syntax error\n", field->name);
354*4882a593Smuzhiyun return -1;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun unsigned char day = (unsigned char)simple_strtol(tok1, &endptr, 0);
358*4882a593Smuzhiyun if (*endptr != '\0' || day == 0) {
359*4882a593Smuzhiyun printf("%s: invalid day\n", field->name);
360*4882a593Smuzhiyun return -1;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun unsigned char month;
364*4882a593Smuzhiyun for (month = 1; month <= 12; month++)
365*4882a593Smuzhiyun if (!strcmp(tok2, months[month - 1]))
366*4882a593Smuzhiyun break;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun unsigned int year = simple_strtol(tok3, &endptr, 0);
369*4882a593Smuzhiyun if (*endptr != '\0') {
370*4882a593Smuzhiyun printf("%s: invalid year\n", field->name);
371*4882a593Smuzhiyun return -1;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (validate_date(day, month - 1, year)) {
375*4882a593Smuzhiyun printf("%s: invalid date\n", field->name);
376*4882a593Smuzhiyun return -1;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (year >> 16) {
380*4882a593Smuzhiyun printf("%s: year overflow\n", field->name);
381*4882a593Smuzhiyun return -1;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun field->buf[0] = day;
385*4882a593Smuzhiyun field->buf[1] = month;
386*4882a593Smuzhiyun field->buf[2] = (unsigned char)year;
387*4882a593Smuzhiyun field->buf[3] = (unsigned char)(year >> 8);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun #define LAYOUT_VERSION_LEGACY 1
393*4882a593Smuzhiyun #define LAYOUT_VERSION_VER1 2
394*4882a593Smuzhiyun #define LAYOUT_VERSION_VER2 3
395*4882a593Smuzhiyun #define LAYOUT_VERSION_VER3 4
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun extern struct eeprom_field layout_unknown[1];
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun #define DEFINE_PRINT_UPDATE(x) eeprom_field_print_##x, eeprom_field_update_##x
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun #ifdef CONFIG_CM_T3X
402*4882a593Smuzhiyun struct eeprom_field layout_legacy[5] = {
403*4882a593Smuzhiyun { "MAC address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
404*4882a593Smuzhiyun { "Board Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin) },
405*4882a593Smuzhiyun { "Serial Number", 8, NULL, DEFINE_PRINT_UPDATE(bin) },
406*4882a593Smuzhiyun { "Board Configuration", 64, NULL, DEFINE_PRINT_UPDATE(ascii) },
407*4882a593Smuzhiyun { RESERVED_FIELDS, 176, NULL, eeprom_field_print_reserved,
408*4882a593Smuzhiyun eeprom_field_update_ascii },
409*4882a593Smuzhiyun };
410*4882a593Smuzhiyun #else
411*4882a593Smuzhiyun #define layout_legacy layout_unknown
412*4882a593Smuzhiyun #endif
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun #if defined(CONFIG_CM_T3X) || defined(CONFIG_CM_T3517)
415*4882a593Smuzhiyun struct eeprom_field layout_v1[12] = {
416*4882a593Smuzhiyun { "Major Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
417*4882a593Smuzhiyun { "Minor Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
418*4882a593Smuzhiyun { "1st MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
419*4882a593Smuzhiyun { "2nd MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
420*4882a593Smuzhiyun { "Production Date", 4, NULL, DEFINE_PRINT_UPDATE(date) },
421*4882a593Smuzhiyun { "Serial Number", 12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
422*4882a593Smuzhiyun { RESERVED_FIELDS, 96, NULL, DEFINE_PRINT_UPDATE(reserved) },
423*4882a593Smuzhiyun { "Product Name", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
424*4882a593Smuzhiyun { "Product Options #1", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
425*4882a593Smuzhiyun { "Product Options #2", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
426*4882a593Smuzhiyun { "Product Options #3", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
427*4882a593Smuzhiyun { RESERVED_FIELDS, 64, NULL, eeprom_field_print_reserved,
428*4882a593Smuzhiyun eeprom_field_update_ascii },
429*4882a593Smuzhiyun };
430*4882a593Smuzhiyun #else
431*4882a593Smuzhiyun #define layout_v1 layout_unknown
432*4882a593Smuzhiyun #endif
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun struct eeprom_field layout_v2[15] = {
435*4882a593Smuzhiyun { "Major Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
436*4882a593Smuzhiyun { "Minor Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
437*4882a593Smuzhiyun { "1st MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
438*4882a593Smuzhiyun { "2nd MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
439*4882a593Smuzhiyun { "Production Date", 4, NULL, DEFINE_PRINT_UPDATE(date) },
440*4882a593Smuzhiyun { "Serial Number", 12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
441*4882a593Smuzhiyun { "3rd MAC Address (WIFI)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
442*4882a593Smuzhiyun { "4th MAC Address (Bluetooth)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
443*4882a593Smuzhiyun { "Layout Version", 1, NULL, DEFINE_PRINT_UPDATE(bin) },
444*4882a593Smuzhiyun { RESERVED_FIELDS, 83, NULL, DEFINE_PRINT_UPDATE(reserved) },
445*4882a593Smuzhiyun { "Product Name", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
446*4882a593Smuzhiyun { "Product Options #1", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
447*4882a593Smuzhiyun { "Product Options #2", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
448*4882a593Smuzhiyun { "Product Options #3", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
449*4882a593Smuzhiyun { RESERVED_FIELDS, 64, NULL, eeprom_field_print_reserved,
450*4882a593Smuzhiyun eeprom_field_update_ascii },
451*4882a593Smuzhiyun };
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun struct eeprom_field layout_v3[16] = {
454*4882a593Smuzhiyun { "Major Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
455*4882a593Smuzhiyun { "Minor Revision", 2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
456*4882a593Smuzhiyun { "1st MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
457*4882a593Smuzhiyun { "2nd MAC Address", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
458*4882a593Smuzhiyun { "Production Date", 4, NULL, DEFINE_PRINT_UPDATE(date) },
459*4882a593Smuzhiyun { "Serial Number", 12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
460*4882a593Smuzhiyun { "3rd MAC Address (WIFI)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
461*4882a593Smuzhiyun { "4th MAC Address (Bluetooth)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
462*4882a593Smuzhiyun { "Layout Version", 1, NULL, DEFINE_PRINT_UPDATE(bin) },
463*4882a593Smuzhiyun { "CompuLab EEPROM ID", 3, NULL, DEFINE_PRINT_UPDATE(bin) },
464*4882a593Smuzhiyun { RESERVED_FIELDS, 80, NULL, DEFINE_PRINT_UPDATE(reserved) },
465*4882a593Smuzhiyun { "Product Name", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
466*4882a593Smuzhiyun { "Product Options #1", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
467*4882a593Smuzhiyun { "Product Options #2", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
468*4882a593Smuzhiyun { "Product Options #3", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
469*4882a593Smuzhiyun { RESERVED_FIELDS, 64, NULL, eeprom_field_print_reserved,
470*4882a593Smuzhiyun eeprom_field_update_ascii },
471*4882a593Smuzhiyun };
472*4882a593Smuzhiyun
eeprom_layout_assign(struct eeprom_layout * layout,int layout_version)473*4882a593Smuzhiyun void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun switch (layout->layout_version) {
476*4882a593Smuzhiyun case LAYOUT_VERSION_LEGACY:
477*4882a593Smuzhiyun layout->fields = layout_legacy;
478*4882a593Smuzhiyun layout->num_of_fields = ARRAY_SIZE(layout_legacy);
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun case LAYOUT_VERSION_VER1:
481*4882a593Smuzhiyun layout->fields = layout_v1;
482*4882a593Smuzhiyun layout->num_of_fields = ARRAY_SIZE(layout_v1);
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun case LAYOUT_VERSION_VER2:
485*4882a593Smuzhiyun layout->fields = layout_v2;
486*4882a593Smuzhiyun layout->num_of_fields = ARRAY_SIZE(layout_v2);
487*4882a593Smuzhiyun break;
488*4882a593Smuzhiyun case LAYOUT_VERSION_VER3:
489*4882a593Smuzhiyun layout->fields = layout_v3;
490*4882a593Smuzhiyun layout->num_of_fields = ARRAY_SIZE(layout_v3);
491*4882a593Smuzhiyun break;
492*4882a593Smuzhiyun default:
493*4882a593Smuzhiyun __eeprom_layout_assign(layout, layout_version);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
eeprom_parse_layout_version(char * str)497*4882a593Smuzhiyun int eeprom_parse_layout_version(char *str)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun if (!strcmp(str, "legacy"))
500*4882a593Smuzhiyun return LAYOUT_VERSION_LEGACY;
501*4882a593Smuzhiyun else if (!strcmp(str, "v1"))
502*4882a593Smuzhiyun return LAYOUT_VERSION_VER1;
503*4882a593Smuzhiyun else if (!strcmp(str, "v2"))
504*4882a593Smuzhiyun return LAYOUT_VERSION_VER2;
505*4882a593Smuzhiyun else if (!strcmp(str, "v3"))
506*4882a593Smuzhiyun return LAYOUT_VERSION_VER3;
507*4882a593Smuzhiyun else
508*4882a593Smuzhiyun return LAYOUT_VERSION_UNRECOGNIZED;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
eeprom_layout_detect(unsigned char * data)511*4882a593Smuzhiyun int eeprom_layout_detect(unsigned char *data)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun switch (data[EEPROM_LAYOUT_VER_OFFSET]) {
514*4882a593Smuzhiyun case 0xff:
515*4882a593Smuzhiyun case 0:
516*4882a593Smuzhiyun return LAYOUT_VERSION_VER1;
517*4882a593Smuzhiyun case 2:
518*4882a593Smuzhiyun return LAYOUT_VERSION_VER2;
519*4882a593Smuzhiyun case 3:
520*4882a593Smuzhiyun return LAYOUT_VERSION_VER3;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun if (data[EEPROM_LAYOUT_VER_OFFSET] >= 0x20)
524*4882a593Smuzhiyun return LAYOUT_VERSION_LEGACY;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun return LAYOUT_VERSION_UNRECOGNIZED;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun #endif
529