1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2021 Gateworks Corporation 4 */ 5 6#include <common.h> 7#include <gsc.h> 8#include <hexdump.h> 9#include <i2c.h> 10#include <dm/uclass.h> 11 12#include "eeprom.h" 13 14/* I2C */ 15#define SOM_EEPROM_BUSNO 0 16#define SOM_EEPROM_ADDR 0x51 17#define BASEBOARD_EEPROM_BUSNO 1 18#define BASEBOARD_EEPROM_ADDR 0x52 19 20struct venice_board_info som_info; 21struct venice_board_info base_info; 22char venice_model[32]; 23char venice_baseboard_model[32]; 24u32 venice_serial; 25 26/* return a mac address from EEPROM info */ 27int eeprom_getmac(int index, uint8_t *address) 28{ 29 int i, j; 30 u32 maclow, machigh; 31 u64 mac; 32 33 j = 0; 34 if (som_info.macno) { 35 maclow = som_info.mac[5]; 36 maclow |= som_info.mac[4] << 8; 37 maclow |= som_info.mac[3] << 16; 38 maclow |= som_info.mac[2] << 24; 39 machigh = som_info.mac[1]; 40 machigh |= som_info.mac[0] << 8; 41 mac = machigh; 42 mac <<= 32; 43 mac |= maclow; 44 for (i = 0; i < som_info.macno; i++, j++) { 45 if (index == j) 46 goto out; 47 } 48 } 49 50 maclow = base_info.mac[5]; 51 maclow |= base_info.mac[4] << 8; 52 maclow |= base_info.mac[3] << 16; 53 maclow |= base_info.mac[2] << 24; 54 machigh = base_info.mac[1]; 55 machigh |= base_info.mac[0] << 8; 56 mac = machigh; 57 mac <<= 32; 58 mac |= maclow; 59 for (i = 0; i < base_info.macno; i++, j++) { 60 if (index == j) 61 goto out; 62 } 63 64 return -EINVAL; 65 66out: 67 mac += i; 68 address[0] = (mac >> 40) & 0xff; 69 address[1] = (mac >> 32) & 0xff; 70 address[2] = (mac >> 24) & 0xff; 71 address[3] = (mac >> 16) & 0xff; 72 address[4] = (mac >> 8) & 0xff; 73 address[5] = (mac >> 0) & 0xff; 74 75 return 0; 76} 77 78static int eeprom_read(int busno, int slave, int alen, struct venice_board_info *info) 79{ 80 int i; 81 int chksum; 82 unsigned char *buf = (unsigned char *)info; 83 struct udevice *dev, *bus; 84 int ret; 85 86 /* probe device */ 87 ret = uclass_get_device_by_seq(UCLASS_I2C, busno, &bus); 88 if (ret) 89 return ret; 90 ret = dm_i2c_probe(bus, slave, 0, &dev); 91 if (ret) 92 return ret; 93 94 /* read eeprom config section */ 95 memset(info, 0, sizeof(*info)); 96 ret = i2c_set_chip_offset_len(dev, alen); 97 if (ret) { 98 puts("EEPROM: Failed to set alen\n"); 99 return ret; 100 } 101 ret = dm_i2c_read(dev, 0x00, buf, sizeof(*info)); 102 if (ret) { 103 if (slave == SOM_EEPROM_ADDR) 104 printf("EEPROM: Failed to read EEPROM\n"); 105 return ret; 106 } 107 108 /* validate checksum */ 109 for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) 110 chksum += buf[i]; 111 if ((info->chksum[0] != chksum >> 8) || 112 (info->chksum[1] != (chksum & 0xff))) { 113 printf("EEPROM: I2C%d@0x%02x: Invalid Checksum\n", busno, slave); 114 print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); 115 memset(info, 0, sizeof(*info)); 116 return -EINVAL; 117 } 118 119 /* sanity check valid model */ 120 if (info->model[0] != 'G' || info->model[1] != 'W') { 121 printf("EEPROM: I2C%d@0x%02x: Invalid Model in EEPROM\n", busno, slave); 122 print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); 123 memset(info, 0, sizeof(*info)); 124 return -EINVAL; 125 } 126 127 return 0; 128} 129 130/* determine BOM revision from model */ 131int get_bom_rev(const char *str) 132{ 133 int rev_bom = 0; 134 int i; 135 136 for (i = strlen(str) - 1; i > 0; i--) { 137 if (str[i] == '-') 138 break; 139 if (str[i] >= '1' && str[i] <= '9') { 140 rev_bom = str[i] - '0'; 141 break; 142 } 143 } 144 return rev_bom; 145} 146 147/* determine PCB revision from model */ 148char get_pcb_rev(const char *str) 149{ 150 char rev_pcb = 'A'; 151 int i; 152 153 for (i = strlen(str) - 1; i > 0; i--) { 154 if (str[i] == '-') 155 break; 156 if (str[i] >= 'A') { 157 rev_pcb = str[i]; 158 break; 159 } 160 } 161 return rev_pcb; 162} 163 164/* 165 * get dt name based on model and detail level: 166 * 167 * For boards that are a combination of a SoM plus a Baseboard: 168 * Venice SoM part numbers are GW70xx where xx is: 169 * 7000-7019: same PCB with som dt of '0x' 170 * 7020-7039: same PCB with som dt of '2x' 171 * 7040-7059: same PCB with som dt of '4x' 172 * 7060-7079: same PCB with som dt of '6x' 173 * 7080-7099: same PCB with som dt of '8x' 174 * Venice Baseboard part numbers are GW7xxx where xxx is: 175 * 7100-7199: same PCB with base dt of '71xx' 176 * 7200-7299: same PCB with base dt of '72xx' 177 * 7300-7399: same PCB with base dt of '73xx' 178 * 7400-7499: same PCB with base dt of '74xx' 179 * 7500-7599: same PCB with base dt of '75xx' 180 * 7600-7699: same PCB with base dt of '76xx' 181 * 7700-7799: same PCB with base dt of '77xx' 182 * 7800-7899: same PCB with base dt of '78xx' 183 * DT name is comprised of: 184 * gw<base dt>-<som dt>-[base-pcb-rev][base-bom-rev][som-pcb-rev][som-bom-rev] 185 * 186 * For board models from 7900-7999 each PCB is unique with its own dt: 187 * DT name is comprised: 188 * gw<model>-[pcb-rev][bom-rev] 189 * 190 */ 191#define snprintfcat(dest, sz, fmt, ...) \ 192 snprintf((dest) + strlen(dest), (sz) - strlen(dest), fmt, ##__VA_ARGS__) 193const char *eeprom_get_dtb_name(int level, char *buf, int sz) 194{ 195#ifdef CONFIG_IMX8MM 196 const char *pre = "imx8mm-venice-gw"; 197#elif CONFIG_IMX8MN 198 const char *pre = "imx8mn-venice-gw"; 199#elif CONFIG_IMX8MP 200 const char *pre = "imx8mp-venice-gw"; 201#endif 202 int model, rev_pcb, rev_bom; 203 204 model = ((som_info.model[2] - '0') * 1000) 205 + ((som_info.model[3] - '0') * 100) 206 + ((som_info.model[4] - '0') * 10) 207 + (som_info.model[5] - '0'); 208 rev_pcb = tolower(get_pcb_rev(som_info.model)); 209 rev_bom = get_bom_rev(som_info.model); 210 211 /* som + baseboard*/ 212 if (base_info.model[0]) { 213 /* baseboard id: 7100-7199->71; 7200-7299->72; etc */ 214 int base = ((base_info.model[2] - '0') * 10) + (base_info.model[3] - '0'); 215 /* som id: 7000-7019->1; 7020-7039->2; etc */ 216 int som = ((model % 100) / 20) * 2; 217 int rev_base_pcb = tolower(get_pcb_rev(base_info.model)); 218 int rev_base_bom = get_bom_rev(base_info.model); 219 220 snprintf(buf, sz, "%s%2dxx-%dx", pre, base, som); 221 /* GW79xx baseboards have no build options */ 222 if (base == 79) { 223 base = (int)strtoul(base_info.model + 2, NULL, 10); 224 snprintf(buf, sz, "%s%4d-%dx", pre, base, som); 225 } 226 switch (level) { 227 case 0: /* full model (ie gw73xx-0x-a1a1) */ 228 if (rev_base_bom) 229 snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom); 230 else 231 snprintfcat(buf, sz, "-%c", rev_base_pcb); 232 if (rev_bom) 233 snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom); 234 else 235 snprintfcat(buf, sz, "%c", rev_pcb); 236 break; 237 case 1: /* don't care about SoM revision */ 238 if (rev_base_bom) 239 snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom); 240 else 241 snprintfcat(buf, sz, "-%c", rev_base_pcb); 242 snprintfcat(buf, sz, "xx"); 243 break; 244 case 2: /* don't care about baseboard revision */ 245 snprintfcat(buf, sz, "-xx"); 246 if (rev_bom) 247 snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom); 248 else 249 snprintfcat(buf, sz, "%c", rev_pcb); 250 break; 251 case 3: /* don't care about SoM/baseboard revision */ 252 break; 253 default: 254 return NULL; 255 } 256 } else { 257 snprintf(buf, sz, "%s%04d", pre, model); 258 switch (level) { 259 case 0: /* full model wth PCB and BOM revision first (ie gw7901-a1) */ 260 if (rev_bom) 261 snprintfcat(buf, sz, "-%c%d", rev_pcb, rev_bom); 262 else 263 snprintfcat(buf, sz, "-%c", rev_pcb); 264 break; 265 case 1: /* don't care about BOM revision */ 266 snprintfcat(buf, sz, "-%c", rev_pcb); 267 break; 268 case 2: /* don't care about PCB or BOM revision */ 269 break; 270 case 3: /* don't care about last digit of model */ 271 buf[strlen(buf) - 1] = 'x'; 272 break; 273 case 4: /* don't care about last two digits of model */ 274 buf[strlen(buf) - 1] = 'x'; 275 buf[strlen(buf) - 2] = 'x'; 276 break; 277 default: 278 return NULL; 279 break; 280 } 281 } 282 283 return buf; 284} 285 286static int eeprom_info(bool verbose) 287{ 288 printf("Model : %s\n", venice_model); 289 printf("Serial : %d\n", som_info.serial); 290 printf("MFGDate : %02x-%02x-%02x%02x\n", 291 som_info.mfgdate[0], som_info.mfgdate[1], 292 som_info.mfgdate[2], som_info.mfgdate[3]); 293 if (base_info.model[0] && verbose) { 294 printf("SOM : %s %d %02x-%02x-%02x%02x\n", 295 som_info.model, som_info.serial, 296 som_info.mfgdate[0], som_info.mfgdate[1], 297 som_info.mfgdate[2], som_info.mfgdate[3]); 298 printf("BASE : %s %d %02x-%02x-%02x%02x\n", 299 base_info.model, base_info.serial, 300 base_info.mfgdate[0], base_info.mfgdate[1], 301 base_info.mfgdate[2], base_info.mfgdate[3]); 302 } 303 304 return 0; 305} 306 307int venice_eeprom_init(int quiet) 308{ 309 char rev_pcb; 310 int rev_bom; 311 int ret; 312 313 ret = eeprom_read(SOM_EEPROM_BUSNO, SOM_EEPROM_ADDR, 1, &som_info); 314 if (ret) { 315 puts("ERROR: Failed to probe EEPROM\n"); 316 memset(&som_info, 0, sizeof(som_info)); 317 return 0; 318 } 319 320 /* read optional baseboard EEPROM */ 321 eeprom_read(BASEBOARD_EEPROM_BUSNO, BASEBOARD_EEPROM_ADDR, 2, &base_info); 322 323 /* create model strings */ 324 if (base_info.model[0]) { 325 sprintf(venice_model, "GW%c%c%c%c-%c%c-", 326 som_info.model[2], /* family */ 327 base_info.model[3], /* baseboard */ 328 base_info.model[4], base_info.model[5], /* subload of baseboard */ 329 som_info.model[4], som_info.model[5]); /* last 2digits of SOM */ 330 strlcpy(venice_baseboard_model, base_info.model, sizeof(venice_baseboard_model)); 331 332 /* baseboard revision */ 333 rev_pcb = get_pcb_rev(base_info.model); 334 rev_bom = get_bom_rev(base_info.model); 335 if (rev_bom) 336 sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom); 337 else 338 sprintf(venice_model + strlen(venice_model), "%c", rev_pcb); 339 /* som revision */ 340 rev_pcb = get_pcb_rev(som_info.model); 341 rev_bom = get_bom_rev(som_info.model); 342 if (rev_bom) 343 sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom); 344 else 345 sprintf(venice_model + strlen(venice_model), "%c", rev_pcb); 346 } else { 347 strcpy(venice_model, som_info.model); 348 } 349 venice_serial = som_info.serial; 350 351 if (!quiet) 352 eeprom_info(false); 353 354 return (16 << som_info.sdram_size); 355} 356 357void board_gsc_info(void) 358{ 359 eeprom_info(true); 360} 361 362const char *eeprom_get_model(void) 363{ 364 return venice_model; 365} 366 367const char *eeprom_get_baseboard_model(void) 368{ 369 return venice_baseboard_model; 370} 371 372u32 eeprom_get_serial(void) 373{ 374 return venice_serial; 375} 376