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 13 #ifndef CONFIG_SYS_I2C_EEPROM_ADDR 14 # define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 15 # define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 16 #endif 17 18 #ifndef CONFIG_SYS_I2C_EEPROM_BUS 19 #define CONFIG_SYS_I2C_EEPROM_BUS 0 20 #endif 21 22 #define EEPROM_LAYOUT_VER_OFFSET 44 23 #define BOARD_SERIAL_OFFSET 20 24 #define BOARD_SERIAL_OFFSET_LEGACY 8 25 #define BOARD_REV_OFFSET 0 26 #define BOARD_REV_OFFSET_LEGACY 6 27 #define BOARD_REV_SIZE 2 28 #define MAC_ADDR_OFFSET 4 29 #define MAC_ADDR_OFFSET_LEGACY 0 30 31 #define LAYOUT_INVALID 0 32 #define LAYOUT_LEGACY 0xff 33 34 static int cl_eeprom_bus; 35 static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */ 36 37 static int cl_eeprom_read(uint offset, uchar *buf, int len) 38 { 39 int res; 40 unsigned int current_i2c_bus = i2c_get_bus_num(); 41 42 res = i2c_set_bus_num(cl_eeprom_bus); 43 if (res < 0) 44 return res; 45 46 res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset, 47 CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len); 48 49 i2c_set_bus_num(current_i2c_bus); 50 51 return res; 52 } 53 54 static int cl_eeprom_setup(uint eeprom_bus) 55 { 56 int res; 57 58 /* 59 * We know the setup was already done when the layout is set to a valid 60 * value and we're using the same bus as before. 61 */ 62 if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus) 63 return 0; 64 65 cl_eeprom_bus = eeprom_bus; 66 res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET, 67 (uchar *)&cl_eeprom_layout, 1); 68 if (res) { 69 cl_eeprom_layout = LAYOUT_INVALID; 70 return res; 71 } 72 73 if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20) 74 cl_eeprom_layout = LAYOUT_LEGACY; 75 76 return 0; 77 } 78 79 void get_board_serial(struct tag_serialnr *serialnr) 80 { 81 u32 serial[2]; 82 uint offset; 83 84 memset(serialnr, 0, sizeof(*serialnr)); 85 86 if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS)) 87 return; 88 89 offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 90 BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY; 91 92 if (cl_eeprom_read(offset, (uchar *)serial, 8)) 93 return; 94 95 if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) { 96 serialnr->low = serial[0]; 97 serialnr->high = serial[1]; 98 } 99 } 100 101 /* 102 * Routine: cl_eeprom_read_mac_addr 103 * Description: read mac address and store it in buf. 104 */ 105 int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus) 106 { 107 uint offset; 108 109 if (cl_eeprom_setup(eeprom_bus)) 110 return 0; 111 112 offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 113 MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY; 114 115 return cl_eeprom_read(offset, buf, 6); 116 } 117 118 static u32 board_rev; 119 120 /* 121 * Routine: cl_eeprom_get_board_rev 122 * Description: read system revision from eeprom 123 */ 124 u32 cl_eeprom_get_board_rev(void) 125 { 126 char str[5]; /* Legacy representation can contain at most 4 digits */ 127 uint offset = BOARD_REV_OFFSET_LEGACY; 128 129 if (board_rev) 130 return board_rev; 131 132 if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS)) 133 return 0; 134 135 if (cl_eeprom_layout != LAYOUT_LEGACY) 136 offset = BOARD_REV_OFFSET; 137 138 if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE)) 139 return 0; 140 141 /* 142 * Convert legacy syntactic representation to semantic 143 * representation. i.e. for rev 1.00: 0x100 --> 0x64 144 */ 145 if (cl_eeprom_layout == LAYOUT_LEGACY) { 146 sprintf(str, "%x", board_rev); 147 board_rev = simple_strtoul(str, NULL, 10); 148 } 149 150 return board_rev; 151 }; 152