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