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 } 184