// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2021 Gateworks Corporation */ #include #include #include #include #include #include "eeprom.h" /* I2C */ #define SOM_EEPROM_BUSNO 0 #define SOM_EEPROM_ADDR 0x51 #define BASEBOARD_EEPROM_BUSNO 1 #define BASEBOARD_EEPROM_ADDR 0x52 struct venice_board_info som_info; struct venice_board_info base_info; char venice_model[32]; u32 venice_serial; /* return a mac address from EEPROM info */ int eeprom_getmac(int index, uint8_t *address) { int i, j; u32 maclow, machigh; u64 mac; j = 0; if (som_info.macno) { maclow = som_info.mac[5]; maclow |= som_info.mac[4] << 8; maclow |= som_info.mac[3] << 16; maclow |= som_info.mac[2] << 24; machigh = som_info.mac[1]; machigh |= som_info.mac[0] << 8; mac = machigh; mac <<= 32; mac |= maclow; for (i = 0; i < som_info.macno; i++, j++) { if (index == j) goto out; } } maclow = base_info.mac[5]; maclow |= base_info.mac[4] << 8; maclow |= base_info.mac[3] << 16; maclow |= base_info.mac[2] << 24; machigh = base_info.mac[1]; machigh |= base_info.mac[0] << 8; mac = machigh; mac <<= 32; mac |= maclow; for (i = 0; i < base_info.macno; i++, j++) { if (index == j) goto out; } return -EINVAL; out: mac += i; address[0] = (mac >> 40) & 0xff; address[1] = (mac >> 32) & 0xff; address[2] = (mac >> 24) & 0xff; address[3] = (mac >> 16) & 0xff; address[4] = (mac >> 8) & 0xff; address[5] = (mac >> 0) & 0xff; return 0; } static int eeprom_read(int busno, int slave, int alen, struct venice_board_info *info) { int i; int chksum; unsigned char *buf = (unsigned char *)info; struct udevice *dev, *bus; int ret; /* probe device */ ret = uclass_get_device_by_seq(UCLASS_I2C, busno, &bus); if (ret) return ret; ret = dm_i2c_probe(bus, slave, 0, &dev); if (ret) return ret; /* read eeprom config section */ memset(info, 0, sizeof(*info)); ret = i2c_set_chip_offset_len(dev, alen); if (ret) { puts("EEPROM: Failed to set alen\n"); return ret; } ret = dm_i2c_read(dev, 0x00, buf, sizeof(*info)); if (ret) { if (slave == SOM_EEPROM_ADDR) printf("EEPROM: Failed to read EEPROM\n"); return ret; } /* validate checksum */ for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) chksum += buf[i]; if ((info->chksum[0] != chksum >> 8) || (info->chksum[1] != (chksum & 0xff))) { printf("EEPROM: I2C%d@0x%02x: Invalid Checksum\n", busno, slave); print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); memset(info, 0, sizeof(*info)); return -EINVAL; } /* sanity check valid model */ if (info->model[0] != 'G' || info->model[1] != 'W') { printf("EEPROM: I2C%d@0x%02x: Invalid Model in EEPROM\n", busno, slave); print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); memset(info, 0, sizeof(*info)); return -EINVAL; } return 0; } /* determine BOM revision from model */ int get_bom_rev(const char *str) { int rev_bom = 0; int i; for (i = strlen(str) - 1; i > 0; i--) { if (str[i] == '-') break; if (str[i] >= '1' && str[i] <= '9') { rev_bom = str[i] - '0'; break; } } return rev_bom; } /* determine PCB revision from model */ char get_pcb_rev(const char *str) { char rev_pcb = 'A'; int i; for (i = strlen(str) - 1; i > 0; i--) { if (str[i] == '-') break; if (str[i] >= 'A') { rev_pcb = str[i]; break; } } return rev_pcb; } /* * get dt name based on model and detail level: * * For boards that are a combination of a SoM plus a Baseboard: * Venice SoM part numbers are GW70xx where xx is: * 7000-7019: same PCB with som dt of '0x' * 7020-7039: same PCB with som dt of '2x' * 7040-7059: same PCB with som dt of '4x' * 7060-7079: same PCB with som dt of '6x' * 7080-7099: same PCB with som dt of '8x' * Venice Baseboard part numbers are GW7xxx where xxx is: * 7100-7199: same PCB with base dt of '71xx' * 7200-7299: same PCB with base dt of '72xx' * 7300-7399: same PCB with base dt of '73xx' * 7400-7499: same PCB with base dt of '74xx' * 7500-7599: same PCB with base dt of '75xx' * 7600-7699: same PCB with base dt of '76xx' * 7700-7799: same PCB with base dt of '77xx' * 7800-7899: same PCB with base dt of '78xx' * DT name is comprised of: * gw--[base-pcb-rev][base-bom-rev][som-pcb-rev][som-bom-rev] * * For board models from 7900-7999 each PCB is unique with its own dt: * DT name is comprised: * gw-[pcb-rev][bom-rev] * */ #define snprintfcat(dest, sz, fmt, ...) \ snprintf((dest) + strlen(dest), (sz) - strlen(dest), fmt, ##__VA_ARGS__) const char *eeprom_get_dtb_name(int level, char *buf, int sz) { #ifdef CONFIG_IMX8MM const char *pre = "imx8mm-venice-gw"; #else const char *pre = "imx8mn-venice-gw"; #endif int model, rev_pcb, rev_bom; model = ((som_info.model[2] - '0') * 1000) + ((som_info.model[3] - '0') * 100) + ((som_info.model[4] - '0') * 10) + (som_info.model[5] - '0'); rev_pcb = tolower(get_pcb_rev(som_info.model)); rev_bom = get_bom_rev(som_info.model); /* som + baseboard*/ if (base_info.model[0]) { /* baseboard id: 7100-7199->71; 7200-7299->72; etc */ int base = ((base_info.model[2] - '0') * 10) + (base_info.model[3] - '0'); /* som id: 7000-7019->1; 7020-7039->2; etc */ int som = ((model % 100) / 20) * 2; int rev_base_pcb = tolower(get_pcb_rev(base_info.model)); int rev_base_bom = get_bom_rev(base_info.model); snprintf(buf, sz, "%s%2dxx-%dx", pre, base, som); switch (level) { case 0: /* full model (ie gw73xx-0x-a1a1) */ if (rev_base_bom) snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom); else snprintfcat(buf, sz, "-%c", rev_base_pcb); if (rev_bom) snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom); else snprintfcat(buf, sz, "%c", rev_pcb); break; case 1: /* don't care about SoM revision */ if (rev_base_bom) snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom); else snprintfcat(buf, sz, "-%c", rev_base_pcb); snprintfcat(buf, sz, "xx"); break; case 2: /* don't care about baseboard revision */ snprintfcat(buf, sz, "-xx"); if (rev_bom) snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom); else snprintfcat(buf, sz, "%c", rev_pcb); break; case 3: /* don't care about SoM/baseboard revision */ break; default: return NULL; } } else { snprintf(buf, sz, "%s%04d", pre, model); switch (level) { case 0: /* full model wth PCB and BOM revision first (ie gw7901-a1) */ if (rev_bom) snprintfcat(buf, sz, "-%c%d", rev_pcb, rev_bom); else snprintfcat(buf, sz, "-%c", rev_pcb); break; case 1: /* don't care about BOM revision */ snprintfcat(buf, sz, "-%c", rev_pcb); break; case 2: /* don't care about PCB or BOM revision */ break; default: return NULL; } } return buf; } static int eeprom_info(bool verbose) { printf("Model : %s\n", venice_model); printf("Serial : %d\n", som_info.serial); printf("MFGDate : %02x-%02x-%02x%02x\n", som_info.mfgdate[0], som_info.mfgdate[1], som_info.mfgdate[2], som_info.mfgdate[3]); if (base_info.model[0] && verbose) { printf("SOM : %s %d %02x-%02x-%02x%02x\n", som_info.model, som_info.serial, som_info.mfgdate[0], som_info.mfgdate[1], som_info.mfgdate[2], som_info.mfgdate[3]); printf("BASE : %s %d %02x-%02x-%02x%02x\n", base_info.model, base_info.serial, base_info.mfgdate[0], base_info.mfgdate[1], base_info.mfgdate[2], base_info.mfgdate[3]); } return 0; } int eeprom_init(int quiet) { char rev_pcb; int rev_bom; int ret; ret = eeprom_read(SOM_EEPROM_BUSNO, SOM_EEPROM_ADDR, 1, &som_info); if (ret) { puts("ERROR: Failed to probe EEPROM\n"); memset(&som_info, 0, sizeof(som_info)); return 0; } /* read optional baseboard EEPROM */ eeprom_read(BASEBOARD_EEPROM_BUSNO, BASEBOARD_EEPROM_ADDR, 2, &base_info); /* create model strings */ if (base_info.model[0]) { sprintf(venice_model, "GW%c%c%c%c-%c%c-", som_info.model[2], /* family */ base_info.model[3], /* baseboard */ base_info.model[4], base_info.model[5], /* subload of baseboard */ som_info.model[4], som_info.model[5]); /* last 2digits of SOM */ /* baseboard revision */ rev_pcb = get_pcb_rev(base_info.model); rev_bom = get_bom_rev(base_info.model); if (rev_bom) sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom); else sprintf(venice_model + strlen(venice_model), "%c", rev_pcb); /* som revision */ rev_pcb = get_pcb_rev(som_info.model); rev_bom = get_bom_rev(som_info.model); if (rev_bom) sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom); else sprintf(venice_model + strlen(venice_model), "%c", rev_pcb); } else { strcpy(venice_model, som_info.model); } venice_serial = som_info.serial; if (!quiet) eeprom_info(false); return (16 << som_info.sdram_size); } void board_gsc_info(void) { eeprom_info(true); } const char *eeprom_get_model(void) { return venice_model; } u32 eeprom_get_serial(void) { return venice_serial; }