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 187d2f669bSNikita Kiryanov #ifndef CONFIG_SYS_I2C_EEPROM_BUS 197d2f669bSNikita Kiryanov #define CONFIG_SYS_I2C_EEPROM_BUS 0 207d2f669bSNikita Kiryanov #endif 217d2f669bSNikita Kiryanov 22689be5f8SIgor Grinberg #define EEPROM_LAYOUT_VER_OFFSET 44 23689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET 20 24689be5f8SIgor Grinberg #define BOARD_SERIAL_OFFSET_LEGACY 8 25689be5f8SIgor Grinberg #define BOARD_REV_OFFSET 0 26689be5f8SIgor Grinberg #define BOARD_REV_OFFSET_LEGACY 6 27689be5f8SIgor Grinberg #define BOARD_REV_SIZE 2 28689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET 4 29689be5f8SIgor Grinberg #define MAC_ADDR_OFFSET_LEGACY 0 30689be5f8SIgor Grinberg 31689be5f8SIgor Grinberg #define LAYOUT_INVALID 0 32689be5f8SIgor Grinberg #define LAYOUT_LEGACY 0xff 33689be5f8SIgor Grinberg 34e7a2447bSNikita Kiryanov static int cl_eeprom_bus; 35689be5f8SIgor Grinberg static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */ 36689be5f8SIgor Grinberg 37689be5f8SIgor Grinberg static int cl_eeprom_read(uint offset, uchar *buf, int len) 38689be5f8SIgor Grinberg { 3952658fdaSNikita Kiryanov int res; 4052658fdaSNikita Kiryanov unsigned int current_i2c_bus = i2c_get_bus_num(); 4152658fdaSNikita Kiryanov 42e7a2447bSNikita Kiryanov res = i2c_set_bus_num(cl_eeprom_bus); 4352658fdaSNikita Kiryanov if (res < 0) 4452658fdaSNikita Kiryanov return res; 4552658fdaSNikita Kiryanov 4652658fdaSNikita Kiryanov res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset, 47689be5f8SIgor Grinberg CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len); 4852658fdaSNikita Kiryanov 4952658fdaSNikita Kiryanov i2c_set_bus_num(current_i2c_bus); 5052658fdaSNikita Kiryanov 5152658fdaSNikita Kiryanov return res; 52689be5f8SIgor Grinberg } 53689be5f8SIgor Grinberg 54e7a2447bSNikita Kiryanov static int cl_eeprom_setup(uint eeprom_bus) 55689be5f8SIgor Grinberg { 56689be5f8SIgor Grinberg int res; 57689be5f8SIgor Grinberg 58e7a2447bSNikita Kiryanov /* 59e7a2447bSNikita Kiryanov * We know the setup was already done when the layout is set to a valid 60e7a2447bSNikita Kiryanov * value and we're using the same bus as before. 61e7a2447bSNikita Kiryanov */ 62e7a2447bSNikita Kiryanov if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus) 63689be5f8SIgor Grinberg return 0; 64689be5f8SIgor Grinberg 65e7a2447bSNikita Kiryanov cl_eeprom_bus = eeprom_bus; 66689be5f8SIgor Grinberg res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET, 67689be5f8SIgor Grinberg (uchar *)&cl_eeprom_layout, 1); 68689be5f8SIgor Grinberg if (res) { 69689be5f8SIgor Grinberg cl_eeprom_layout = LAYOUT_INVALID; 70689be5f8SIgor Grinberg return res; 71689be5f8SIgor Grinberg } 72689be5f8SIgor Grinberg 73689be5f8SIgor Grinberg if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20) 74689be5f8SIgor Grinberg cl_eeprom_layout = LAYOUT_LEGACY; 75689be5f8SIgor Grinberg 76689be5f8SIgor Grinberg return 0; 77689be5f8SIgor Grinberg } 78689be5f8SIgor Grinberg 79689be5f8SIgor Grinberg void get_board_serial(struct tag_serialnr *serialnr) 80689be5f8SIgor Grinberg { 81689be5f8SIgor Grinberg u32 serial[2]; 82689be5f8SIgor Grinberg uint offset; 83689be5f8SIgor Grinberg 84689be5f8SIgor Grinberg memset(serialnr, 0, sizeof(*serialnr)); 85689be5f8SIgor Grinberg 86e7a2447bSNikita Kiryanov if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS)) 87689be5f8SIgor Grinberg return; 88689be5f8SIgor Grinberg 89689be5f8SIgor Grinberg offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 90689be5f8SIgor Grinberg BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY; 91689be5f8SIgor Grinberg 92689be5f8SIgor Grinberg if (cl_eeprom_read(offset, (uchar *)serial, 8)) 93689be5f8SIgor Grinberg return; 94689be5f8SIgor Grinberg 95689be5f8SIgor Grinberg if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) { 96689be5f8SIgor Grinberg serialnr->low = serial[0]; 97689be5f8SIgor Grinberg serialnr->high = serial[1]; 98689be5f8SIgor Grinberg } 99689be5f8SIgor Grinberg } 100689be5f8SIgor Grinberg 101689be5f8SIgor Grinberg /* 102689be5f8SIgor Grinberg * Routine: cl_eeprom_read_mac_addr 103689be5f8SIgor Grinberg * Description: read mac address and store it in buf. 104689be5f8SIgor Grinberg */ 105e7a2447bSNikita Kiryanov int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus) 106689be5f8SIgor Grinberg { 107689be5f8SIgor Grinberg uint offset; 108*e93e809fSNikita Kiryanov int err; 109689be5f8SIgor Grinberg 110*e93e809fSNikita Kiryanov err = cl_eeprom_setup(eeprom_bus); 111*e93e809fSNikita Kiryanov if (err) 112*e93e809fSNikita Kiryanov return err; 113689be5f8SIgor Grinberg 114689be5f8SIgor Grinberg offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 115689be5f8SIgor Grinberg MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY; 116689be5f8SIgor Grinberg 117689be5f8SIgor Grinberg return cl_eeprom_read(offset, buf, 6); 118689be5f8SIgor Grinberg } 119689be5f8SIgor Grinberg 120a937fd16SIgor Grinberg static u32 board_rev; 121a937fd16SIgor Grinberg 122689be5f8SIgor Grinberg /* 123689be5f8SIgor Grinberg * Routine: cl_eeprom_get_board_rev 124689be5f8SIgor Grinberg * Description: read system revision from eeprom 125689be5f8SIgor Grinberg */ 12672898ac7SNikita Kiryanov u32 cl_eeprom_get_board_rev(uint eeprom_bus) 127689be5f8SIgor Grinberg { 128689be5f8SIgor Grinberg char str[5]; /* Legacy representation can contain at most 4 digits */ 129689be5f8SIgor Grinberg uint offset = BOARD_REV_OFFSET_LEGACY; 130689be5f8SIgor Grinberg 131a937fd16SIgor Grinberg if (board_rev) 132a937fd16SIgor Grinberg return board_rev; 133a937fd16SIgor Grinberg 13472898ac7SNikita Kiryanov if (cl_eeprom_setup(eeprom_bus)) 135689be5f8SIgor Grinberg return 0; 136689be5f8SIgor Grinberg 137689be5f8SIgor Grinberg if (cl_eeprom_layout != LAYOUT_LEGACY) 138689be5f8SIgor Grinberg offset = BOARD_REV_OFFSET; 139689be5f8SIgor Grinberg 140a937fd16SIgor Grinberg if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE)) 141689be5f8SIgor Grinberg return 0; 142689be5f8SIgor Grinberg 143689be5f8SIgor Grinberg /* 144689be5f8SIgor Grinberg * Convert legacy syntactic representation to semantic 145689be5f8SIgor Grinberg * representation. i.e. for rev 1.00: 0x100 --> 0x64 146689be5f8SIgor Grinberg */ 147689be5f8SIgor Grinberg if (cl_eeprom_layout == LAYOUT_LEGACY) { 148a937fd16SIgor Grinberg sprintf(str, "%x", board_rev); 149a937fd16SIgor Grinberg board_rev = simple_strtoul(str, NULL, 10); 150689be5f8SIgor Grinberg } 151689be5f8SIgor Grinberg 152a937fd16SIgor Grinberg return board_rev; 153689be5f8SIgor Grinberg }; 154