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 int err; 109 110 err = cl_eeprom_setup(eeprom_bus); 111 if (err) 112 return err; 113 114 offset = (cl_eeprom_layout != LAYOUT_LEGACY) ? 115 MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY; 116 117 return cl_eeprom_read(offset, buf, 6); 118 } 119 120 static u32 board_rev; 121 122 /* 123 * Routine: cl_eeprom_get_board_rev 124 * Description: read system revision from eeprom 125 */ 126 u32 cl_eeprom_get_board_rev(uint eeprom_bus) 127 { 128 char str[5]; /* Legacy representation can contain at most 4 digits */ 129 uint offset = BOARD_REV_OFFSET_LEGACY; 130 131 if (board_rev) 132 return board_rev; 133 134 if (cl_eeprom_setup(eeprom_bus)) 135 return 0; 136 137 if (cl_eeprom_layout != LAYOUT_LEGACY) 138 offset = BOARD_REV_OFFSET; 139 140 if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE)) 141 return 0; 142 143 /* 144 * Convert legacy syntactic representation to semantic 145 * representation. i.e. for rev 1.00: 0x100 --> 0x64 146 */ 147 if (cl_eeprom_layout == LAYOUT_LEGACY) { 148 sprintf(str, "%x", board_rev); 149 board_rev = simple_strtoul(str, NULL, 10); 150 } 151 152 return board_rev; 153 }; 154