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> 12689be5f8SIgor Grinberg 13d3f041c0SIgor Grinberg #ifndef CONFIG_SYS_I2C_EEPROM_ADDR 14d3f041c0SIgor Grinberg # define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 15d3f041c0SIgor Grinberg # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 16d3f041c0SIgor Grinberg #endif 17d3f041c0SIgor Grinberg 18689be5f8SIgor Grinberg #define EEPROM_LAYOUT_VER_OFFSET 44 19689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET 20 20689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET_LEGACY 8 21689be5f8SIgor Grinberg #define BOARD_REV_OFFSET 0 22689be5f8SIgor Grinberg #define BOARD_REV_OFFSET_LEGACY 6 23689be5f8SIgor Grinberg #define BOARD_REV_SIZE 2 24689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET 4 25689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET_LEGACY 0 26689be5f8SIgor Grinberg 27689be5f8SIgor Grinberg #define LAYOUT_INVALID 0 28689be5f8SIgor Grinberg #define LAYOUT_LEGACY 0xff 29689be5f8SIgor Grinberg 30689be5f8SIgor Grinberg static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */ 31689be5f8SIgor Grinberg 32689be5f8SIgor Grinberg static int cl_eeprom_read(uint offset, uchar *buf, int len) 33689be5f8SIgor Grinberg { 34*52658fdaSNikita Kiryanov int res; 35*52658fdaSNikita Kiryanov unsigned int current_i2c_bus = i2c_get_bus_num(); 36*52658fdaSNikita Kiryanov 37*52658fdaSNikita Kiryanov res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); 38*52658fdaSNikita Kiryanov if (res < 0) 39*52658fdaSNikita Kiryanov return res; 40*52658fdaSNikita Kiryanov 41*52658fdaSNikita Kiryanov res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset, 42689be5f8SIgor Grinberg CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len); 43*52658fdaSNikita Kiryanov 44*52658fdaSNikita Kiryanov i2c_set_bus_num(current_i2c_bus); 45*52658fdaSNikita Kiryanov 46*52658fdaSNikita Kiryanov return res; 47689be5f8SIgor Grinberg } 48689be5f8SIgor Grinberg 49689be5f8SIgor Grinberg static int cl_eeprom_setup_layout(void) 50689be5f8SIgor Grinberg { 51689be5f8SIgor Grinberg int res; 52689be5f8SIgor Grinberg 53689be5f8SIgor Grinberg if (cl_eeprom_layout != LAYOUT_INVALID) 54689be5f8SIgor Grinberg return 0; 55689be5f8SIgor Grinberg 56689be5f8SIgor Grinberg res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET, 57689be5f8SIgor Grinberg (uchar *)&cl_eeprom_layout, 1); 58689be5f8SIgor Grinberg if (res) { 59689be5f8SIgor Grinberg cl_eeprom_layout = LAYOUT_INVALID; 60689be5f8SIgor Grinberg return res; 61689be5f8SIgor Grinberg } 62689be5f8SIgor Grinberg 63689be5f8SIgor Grinberg if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20) 64689be5f8SIgor Grinberg cl_eeprom_layout = LAYOUT_LEGACY; 65689be5f8SIgor Grinberg 66689be5f8SIgor Grinberg return 0; 67689be5f8SIgor Grinberg } 68689be5f8SIgor Grinberg 69689be5f8SIgor Grinberg void get_board_serial(struct tag_serialnr *serialnr) 70689be5f8SIgor Grinberg { 71689be5f8SIgor Grinberg u32 serial[2]; 72689be5f8SIgor Grinberg uint offset; 73689be5f8SIgor Grinberg 74689be5f8SIgor Grinberg memset(serialnr, 0, sizeof(*serialnr)); 75689be5f8SIgor Grinberg 76689be5f8SIgor Grinberg if (cl_eeprom_setup_layout()) 77689be5f8SIgor Grinberg return; 78689be5f8SIgor Grinberg 79689be5f8SIgor Grinberg offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 80689be5f8SIgor Grinberg BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY; 81689be5f8SIgor Grinberg 82689be5f8SIgor Grinberg if (cl_eeprom_read(offset, (uchar *)serial, 8)) 83689be5f8SIgor Grinberg return; 84689be5f8SIgor Grinberg 85689be5f8SIgor Grinberg if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) { 86689be5f8SIgor Grinberg serialnr->low = serial[0]; 87689be5f8SIgor Grinberg serialnr->high = serial[1]; 88689be5f8SIgor Grinberg } 89689be5f8SIgor Grinberg } 90689be5f8SIgor Grinberg 91689be5f8SIgor Grinberg /* 92689be5f8SIgor Grinberg * Routine: cl_eeprom_read_mac_addr 93689be5f8SIgor Grinberg * Description: read mac address and store it in buf. 94689be5f8SIgor Grinberg */ 95689be5f8SIgor Grinberg int cl_eeprom_read_mac_addr(uchar *buf) 96689be5f8SIgor Grinberg { 97689be5f8SIgor Grinberg uint offset; 98689be5f8SIgor Grinberg 99689be5f8SIgor Grinberg if (cl_eeprom_setup_layout()) 100689be5f8SIgor Grinberg return 0; 101689be5f8SIgor Grinberg 102689be5f8SIgor Grinberg offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 103689be5f8SIgor Grinberg MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY; 104689be5f8SIgor Grinberg 105689be5f8SIgor Grinberg return cl_eeprom_read(offset, buf, 6); 106689be5f8SIgor Grinberg } 107689be5f8SIgor Grinberg 108689be5f8SIgor Grinberg /* 109689be5f8SIgor Grinberg * Routine: cl_eeprom_get_board_rev 110689be5f8SIgor Grinberg * Description: read system revision from eeprom 111689be5f8SIgor Grinberg */ 112689be5f8SIgor Grinberg u32 cl_eeprom_get_board_rev(void) 113689be5f8SIgor Grinberg { 114689be5f8SIgor Grinberg u32 rev = 0; 115689be5f8SIgor Grinberg char str[5]; /* Legacy representation can contain at most 4 digits */ 116689be5f8SIgor Grinberg uint offset = BOARD_REV_OFFSET_LEGACY; 117689be5f8SIgor Grinberg 118689be5f8SIgor Grinberg if (cl_eeprom_setup_layout()) 119689be5f8SIgor Grinberg return 0; 120689be5f8SIgor Grinberg 121689be5f8SIgor Grinberg if (cl_eeprom_layout != LAYOUT_LEGACY) 122689be5f8SIgor Grinberg offset = BOARD_REV_OFFSET; 123689be5f8SIgor Grinberg 124689be5f8SIgor Grinberg if (cl_eeprom_read(offset, (uchar *)&rev, BOARD_REV_SIZE)) 125689be5f8SIgor Grinberg return 0; 126689be5f8SIgor Grinberg 127689be5f8SIgor Grinberg /* 128689be5f8SIgor Grinberg * Convert legacy syntactic representation to semantic 129689be5f8SIgor Grinberg * representation. i.e. for rev 1.00: 0x100 --> 0x64 130689be5f8SIgor Grinberg */ 131689be5f8SIgor Grinberg if (cl_eeprom_layout == LAYOUT_LEGACY) { 132689be5f8SIgor Grinberg sprintf(str, "%x", rev); 133689be5f8SIgor Grinberg rev = simple_strtoul(str, NULL, 10); 134689be5f8SIgor Grinberg } 135689be5f8SIgor Grinberg 136689be5f8SIgor Grinberg return rev; 137689be5f8SIgor Grinberg }; 138