1 /* 2 * (C) Copyright 2011 3 * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <cli_hush.h> 10 #include <i2c.h> 11 #include "common.h" 12 13 static int ivm_calc_crc(unsigned char *buf, int len) 14 { 15 const unsigned short crc_tab[16] = { 16 0x0000, 0xCC01, 0xD801, 0x1400, 17 0xF001, 0x3C00, 0x2800, 0xE401, 18 0xA001, 0x6C00, 0x7800, 0xB401, 19 0x5000, 0x9C01, 0x8801, 0x4400}; 20 21 unsigned short crc = 0; /* final result */ 22 unsigned short r1 = 0; /* temp */ 23 unsigned char byte = 0; /* input buffer */ 24 int i; 25 26 /* calculate CRC from array data */ 27 for (i = 0; i < len; i++) { 28 byte = buf[i]; 29 30 /* lower 4 bits */ 31 r1 = crc_tab[crc & 0xF]; 32 crc = ((crc) >> 4) & 0x0FFF; 33 crc = crc ^ r1 ^ crc_tab[byte & 0xF]; 34 35 /* upper 4 bits */ 36 r1 = crc_tab[crc & 0xF]; 37 crc = (crc >> 4) & 0x0FFF; 38 crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF]; 39 } 40 return crc; 41 } 42 43 static int ivm_set_value(char *name, char *value) 44 { 45 char tempbuf[256]; 46 47 if (value != NULL) { 48 sprintf(tempbuf, "%s=%s", name, value); 49 return set_local_var(tempbuf, 0); 50 } else { 51 unset_local_var(name); 52 } 53 return 0; 54 } 55 56 static int ivm_get_value(unsigned char *buf, int len, char *name, int off, 57 int check) 58 { 59 unsigned short val; 60 unsigned char valbuf[30]; 61 62 if ((buf[off + 0] != buf[off + 2]) && 63 (buf[off + 2] != buf[off + 4])) { 64 printf("%s Error corrupted %s\n", __func__, name); 65 val = -1; 66 } else { 67 val = buf[off + 0] + (buf[off + 1] << 8); 68 if ((val == 0) && (check == 1)) 69 val = -1; 70 } 71 sprintf((char *)valbuf, "%x", val); 72 ivm_set_value(name, (char *)valbuf); 73 return val; 74 } 75 76 #define INV_BLOCKSIZE 0x100 77 #define INV_DATAADDRESS 0x21 78 #define INVENTORYDATASIZE (INV_BLOCKSIZE - INV_DATAADDRESS - 3) 79 80 #define IVM_POS_SHORT_TEXT 0 81 #define IVM_POS_MANU_ID 1 82 #define IVM_POS_MANU_SERIAL 2 83 #define IVM_POS_PART_NUMBER 3 84 #define IVM_POS_BUILD_STATE 4 85 #define IVM_POS_SUPPLIER_PART_NUMBER 5 86 #define IVM_POS_DELIVERY_DATE 6 87 #define IVM_POS_SUPPLIER_BUILD_STATE 7 88 #define IVM_POS_CUSTOMER_ID 8 89 #define IVM_POS_CUSTOMER_PROD_ID 9 90 #define IVM_POS_HISTORY 10 91 #define IVM_POS_SYMBOL_ONLY 11 92 93 static char convert_char(char c) 94 { 95 return (c < ' ' || c > '~') ? '.' : c; 96 } 97 98 static int ivm_findinventorystring(int type, 99 unsigned char *const string, 100 unsigned long maxlen, 101 unsigned char *buf) 102 { 103 int xcode = 0; 104 unsigned long cr = 0; 105 unsigned long addr = INV_DATAADDRESS; 106 unsigned long size = 0; 107 unsigned long nr = type; 108 int stop = 0; /* stop on semicolon */ 109 110 memset(string, '\0', maxlen); 111 switch (type) { 112 case IVM_POS_SYMBOL_ONLY: 113 nr = 0; 114 stop = 1; 115 break; 116 default: 117 nr = type; 118 stop = 0; 119 } 120 121 /* Look for the requested number of CR. */ 122 while ((cr != nr) && (addr < INVENTORYDATASIZE)) { 123 if (buf[addr] == '\r') 124 cr++; 125 addr++; 126 } 127 128 /* 129 * the expected number of CR was found until the end of the IVM 130 * content --> fill string 131 */ 132 if (addr < INVENTORYDATASIZE) { 133 /* Copy the IVM string in the corresponding string */ 134 for (; (buf[addr] != '\r') && 135 ((buf[addr] != ';') || (!stop)) && 136 (size < (maxlen - 1) && 137 (addr < INVENTORYDATASIZE)); addr++) { 138 size += sprintf((char *)string + size, "%c", 139 convert_char (buf[addr])); 140 } 141 142 /* 143 * copy phase is done: check if everything is ok. If not, 144 * the inventory data is most probably corrupted: tell 145 * the world there is a problem! 146 */ 147 if (addr == INVENTORYDATASIZE) { 148 xcode = -1; 149 printf("Error end of string not found\n"); 150 } else if ((size > (maxlen - 1)) && 151 (buf[addr] != '\r')) { 152 xcode = -1; 153 printf("string too long till next CR\n"); 154 } 155 } else { 156 /* 157 * some CR are missing... 158 * the inventory data is most probably corrupted 159 */ 160 xcode = -1; 161 printf("not enough cr found\n"); 162 } 163 return xcode; 164 } 165 166 #define GET_STRING(name, which, len) \ 167 if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \ 168 ivm_set_value(name, (char *)valbuf); \ 169 } 170 171 static int ivm_check_crc(unsigned char *buf, int block) 172 { 173 unsigned long crc; 174 unsigned long crceeprom; 175 176 crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2); 177 crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \ 178 buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256); 179 if (crc != crceeprom) { 180 if (block == 0) 181 printf("Error CRC Block: %d EEprom: calculated: \ 182 %lx EEprom: %lx\n", block, crc, crceeprom); 183 return -1; 184 } 185 return 0; 186 } 187 188 static int calculate_mac_offset(unsigned char *valbuf, unsigned char *buf, 189 int offset) 190 { 191 unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6]; 192 193 if (offset == 0) 194 return 0; 195 196 val += offset; 197 buf[4] = (val >> 16) & 0xff; 198 buf[5] = (val >> 8) & 0xff; 199 buf[6] = val & 0xff; 200 sprintf((char *)valbuf, "%pM", buf + 1); 201 return 0; 202 } 203 204 static int ivm_analyze_block2(unsigned char *buf, int len) 205 { 206 unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; 207 unsigned long count; 208 209 /* IVM_MAC Adress begins at offset 1 */ 210 sprintf((char *)valbuf, "%pM", buf + 1); 211 ivm_set_value("IVM_MacAddress", (char *)valbuf); 212 /* if an offset is defined, add it */ 213 calculate_mac_offset(buf, valbuf, CONFIG_PIGGY_MAC_ADRESS_OFFSET); 214 #ifdef MACH_TYPE_KM_KIRKWOOD 215 setenv((char *)"ethaddr", (char *)valbuf); 216 #else 217 if (getenv("ethaddr") == NULL) 218 setenv((char *)"ethaddr", (char *)valbuf); 219 #endif 220 #ifdef CONFIG_KMVECT1 221 /* KMVECT1 has two ethernet interfaces */ 222 if (getenv("eth1addr") == NULL) { 223 calculate_mac_offset(buf, valbuf, 1); 224 setenv((char *)"eth1addr", (char *)valbuf); 225 } 226 #endif 227 /* IVM_MacCount */ 228 count = (buf[10] << 24) + 229 (buf[11] << 16) + 230 (buf[12] << 8) + 231 buf[13]; 232 if (count == 0xffffffff) 233 count = 1; 234 sprintf((char *)valbuf, "%lx", count); 235 ivm_set_value("IVM_MacCount", (char *)valbuf); 236 return 0; 237 } 238 239 static int ivm_analyze_eeprom(unsigned char *buf, int len) 240 { 241 unsigned short val; 242 unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; 243 unsigned char *tmp; 244 245 if (ivm_check_crc(buf, 0) != 0) 246 return -1; 247 248 ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, 249 "IVM_BoardId", 0, 1); 250 val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, 251 "IVM_HWKey", 6, 1); 252 if (val != 0xffff) { 253 sprintf((char *)valbuf, "%x", ((val / 100) % 10)); 254 ivm_set_value("IVM_HWVariant", (char *)valbuf); 255 sprintf((char *)valbuf, "%x", (val % 100)); 256 ivm_set_value("IVM_HWVersion", (char *)valbuf); 257 } 258 ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, 259 "IVM_Functions", 12, 0); 260 261 GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8) 262 GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64) 263 tmp = (unsigned char *) getenv("IVM_DeviceName"); 264 if (tmp) { 265 int len = strlen((char *)tmp); 266 int i = 0; 267 268 while (i < len) { 269 if (tmp[i] == ';') { 270 ivm_set_value("IVM_ShortText", 271 (char *)&tmp[i + 1]); 272 break; 273 } 274 i++; 275 } 276 if (i >= len) 277 ivm_set_value("IVM_ShortText", NULL); 278 } else { 279 ivm_set_value("IVM_ShortText", NULL); 280 } 281 GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32) 282 GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20) 283 GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32) 284 GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32) 285 GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32) 286 GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32) 287 GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32) 288 GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32) 289 GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32) 290 291 if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0) 292 return 0; 293 ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 294 CONFIG_SYS_IVM_EEPROM_PAGE_LEN); 295 296 return 0; 297 } 298 299 int ivm_read_eeprom(void) 300 { 301 uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN]; 302 int ret; 303 304 i2c_set_bus_num(CONFIG_KM_IVM_BUS); 305 /* add deblocking here */ 306 i2c_make_abort(); 307 308 ret = i2c_read(CONFIG_SYS_IVM_EEPROM_ADR, 0, 1, i2c_buffer, 309 CONFIG_SYS_IVM_EEPROM_MAX_LEN); 310 if (ret != 0) { 311 printf("Error reading EEprom\n"); 312 return -2; 313 } 314 315 return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN); 316 } 317