11badf2f4STim Harvey /*
21badf2f4STim Harvey * Copyright (C) 2014 Gateworks Corporation
31badf2f4STim Harvey * Author: Tim Harvey <tharvey@gateworks.com>
41badf2f4STim Harvey *
51badf2f4STim Harvey * SPDX-License-Identifier: GPL-2.0+
61badf2f4STim Harvey */
71badf2f4STim Harvey
81badf2f4STim Harvey #include <common.h>
99c0fe83eSTim Harvey #include <errno.h>
101badf2f4STim Harvey #include <i2c.h>
119c0fe83eSTim Harvey #include <malloc.h>
129c0fe83eSTim Harvey #include <asm/bitops.h>
131badf2f4STim Harvey
141badf2f4STim Harvey #include "gsc.h"
151badf2f4STim Harvey #include "ventana_eeprom.h"
161badf2f4STim Harvey
171badf2f4STim Harvey /* read ventana EEPROM, check for validity, and return baseboard type */
181badf2f4STim Harvey int
read_eeprom(int bus,struct ventana_board_info * info)191badf2f4STim Harvey read_eeprom(int bus, struct ventana_board_info *info)
201badf2f4STim Harvey {
211badf2f4STim Harvey int i;
221badf2f4STim Harvey int chksum;
231badf2f4STim Harvey char baseboard;
241badf2f4STim Harvey int type;
251badf2f4STim Harvey unsigned char *buf = (unsigned char *)info;
261badf2f4STim Harvey
271badf2f4STim Harvey memset(info, 0, sizeof(*info));
281badf2f4STim Harvey
291badf2f4STim Harvey /*
301badf2f4STim Harvey * On a board with a missing/depleted backup battery for GSC, the
311badf2f4STim Harvey * board may be ready to probe the GSC before its firmware is
321badf2f4STim Harvey * running. We will wait here indefinately for the GSC/EEPROM.
331badf2f4STim Harvey */
341badf2f4STim Harvey while (1) {
351badf2f4STim Harvey if (0 == i2c_set_bus_num(bus) &&
361badf2f4STim Harvey 0 == i2c_probe(GSC_EEPROM_ADDR))
371badf2f4STim Harvey break;
381badf2f4STim Harvey mdelay(1);
391badf2f4STim Harvey }
401badf2f4STim Harvey
411badf2f4STim Harvey /* read eeprom config section */
421badf2f4STim Harvey if (gsc_i2c_read(GSC_EEPROM_ADDR, 0x00, 1, buf, sizeof(*info))) {
431badf2f4STim Harvey puts("EEPROM: Failed to read EEPROM\n");
441badf2f4STim Harvey return GW_UNKNOWN;
451badf2f4STim Harvey }
461badf2f4STim Harvey
471badf2f4STim Harvey /* sanity checks */
481badf2f4STim Harvey if (info->model[0] != 'G' || info->model[1] != 'W') {
491badf2f4STim Harvey puts("EEPROM: Invalid Model in EEPROM\n");
501badf2f4STim Harvey return GW_UNKNOWN;
511badf2f4STim Harvey }
521badf2f4STim Harvey
531badf2f4STim Harvey /* validate checksum */
541badf2f4STim Harvey for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
551badf2f4STim Harvey chksum += buf[i];
561badf2f4STim Harvey if ((info->chksum[0] != chksum>>8) ||
571badf2f4STim Harvey (info->chksum[1] != (chksum&0xff))) {
581badf2f4STim Harvey puts("EEPROM: Failed EEPROM checksum\n");
591badf2f4STim Harvey return GW_UNKNOWN;
601badf2f4STim Harvey }
611badf2f4STim Harvey
621badf2f4STim Harvey /* original GW5400-A prototype */
631badf2f4STim Harvey baseboard = info->model[3];
641badf2f4STim Harvey if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0)
651badf2f4STim Harvey baseboard = '0';
661badf2f4STim Harvey
678d1a6ff8STim Harvey type = GW_UNKNOWN;
681badf2f4STim Harvey switch (baseboard) {
691badf2f4STim Harvey case '0': /* original GW5400-A prototype */
701badf2f4STim Harvey type = GW54proto;
711badf2f4STim Harvey break;
721badf2f4STim Harvey case '1':
731badf2f4STim Harvey type = GW51xx;
741badf2f4STim Harvey break;
751badf2f4STim Harvey case '2':
761badf2f4STim Harvey type = GW52xx;
771badf2f4STim Harvey break;
781badf2f4STim Harvey case '3':
791badf2f4STim Harvey type = GW53xx;
801badf2f4STim Harvey break;
811badf2f4STim Harvey case '4':
821badf2f4STim Harvey type = GW54xx;
831badf2f4STim Harvey break;
843aa22674STim Harvey case '5':
8575f21e31STim Harvey if (info->model[4] == '1') {
8675f21e31STim Harvey type = GW551x;
8775f21e31STim Harvey break;
8875f21e31STim Harvey } else if (info->model[4] == '2') {
893aa22674STim Harvey type = GW552x;
903aa22674STim Harvey break;
91385575bcSTim Harvey } else if (info->model[4] == '3') {
92385575bcSTim Harvey type = GW553x;
93385575bcSTim Harvey break;
9475f21e31STim Harvey }
958d1a6ff8STim Harvey break;
9694a1d6c6STim Harvey case '6':
9794a1d6c6STim Harvey if (info->model[4] == '0')
9894a1d6c6STim Harvey type = GW560x;
9994a1d6c6STim Harvey break;
1008d1a6ff8STim Harvey case '9':
101*214fb19bSTim Harvey if (info->model[4] == '0' && info->model[5] == '3')
102*214fb19bSTim Harvey type = GW5903;
1038d1a6ff8STim Harvey if (info->model[4] == '0' && info->model[5] == '4')
1048d1a6ff8STim Harvey type = GW5904;
1051badf2f4STim Harvey break;
1061badf2f4STim Harvey }
1071badf2f4STim Harvey return type;
1081badf2f4STim Harvey }
1099c0fe83eSTim Harvey
1109c0fe83eSTim Harvey /* list of config bits that the bootloader will remove from dtb if not set */
1119c0fe83eSTim Harvey struct ventana_eeprom_config econfig[] = {
1129c0fe83eSTim Harvey { "eth0", "ethernet0", EECONFIG_ETH0 },
1139c0fe83eSTim Harvey { "usb0", NULL, EECONFIG_USB0 },
1149c0fe83eSTim Harvey { "usb1", NULL, EECONFIG_USB1 },
1159c0fe83eSTim Harvey { "mmc0", NULL, EECONFIG_SD0 },
1169c0fe83eSTim Harvey { "mmc1", NULL, EECONFIG_SD1 },
1179c0fe83eSTim Harvey { "mmc2", NULL, EECONFIG_SD2 },
1189c0fe83eSTim Harvey { "mmc3", NULL, EECONFIG_SD3 },
1199c0fe83eSTim Harvey { /* Sentinel */ }
1209c0fe83eSTim Harvey };
1219c0fe83eSTim Harvey
1229c0fe83eSTim Harvey #ifdef CONFIG_CMD_EECONFIG
get_config(const char * name)1239c0fe83eSTim Harvey static struct ventana_eeprom_config *get_config(const char *name)
1249c0fe83eSTim Harvey {
1259c0fe83eSTim Harvey struct ventana_eeprom_config *cfg = econfig;
1269c0fe83eSTim Harvey
1279c0fe83eSTim Harvey while (cfg->name) {
1289c0fe83eSTim Harvey if (0 == strcmp(name, cfg->name))
1299c0fe83eSTim Harvey return cfg;
1309c0fe83eSTim Harvey cfg++;
1319c0fe83eSTim Harvey }
1329c0fe83eSTim Harvey return NULL;
1339c0fe83eSTim Harvey }
1349c0fe83eSTim Harvey
1359c0fe83eSTim Harvey static u8 econfig_bytes[sizeof(ventana_info.config)];
1369c0fe83eSTim Harvey static int econfig_init = -1;
1379c0fe83eSTim Harvey
do_econfig(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1389c0fe83eSTim Harvey int do_econfig(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1399c0fe83eSTim Harvey {
1409c0fe83eSTim Harvey struct ventana_eeprom_config *cfg;
1419c0fe83eSTim Harvey struct ventana_board_info *info = &ventana_info;
1429c0fe83eSTim Harvey int i;
1439c0fe83eSTim Harvey
1449c0fe83eSTim Harvey if (argc < 2)
1459c0fe83eSTim Harvey return CMD_RET_USAGE;
1469c0fe83eSTim Harvey
1479c0fe83eSTim Harvey /* initialize */
1489c0fe83eSTim Harvey if (econfig_init != 1) {
1499c0fe83eSTim Harvey memcpy(econfig_bytes, info->config, sizeof(econfig_bytes));
1509c0fe83eSTim Harvey econfig_init = 1;
1519c0fe83eSTim Harvey }
1529c0fe83eSTim Harvey
1539c0fe83eSTim Harvey /* list configs */
1549c0fe83eSTim Harvey if ((strncmp(argv[1], "list", 4) == 0)) {
1559c0fe83eSTim Harvey cfg = econfig;
1569c0fe83eSTim Harvey while (cfg->name) {
1579c0fe83eSTim Harvey printf("%s: %d\n", cfg->name,
1589c0fe83eSTim Harvey test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
1599c0fe83eSTim Harvey cfg++;
1609c0fe83eSTim Harvey }
1619c0fe83eSTim Harvey }
1629c0fe83eSTim Harvey
1639c0fe83eSTim Harvey /* save */
1649c0fe83eSTim Harvey else if ((strncmp(argv[1], "save", 4) == 0)) {
1659c0fe83eSTim Harvey unsigned char *buf = (unsigned char *)info;
1669c0fe83eSTim Harvey int chksum;
1679c0fe83eSTim Harvey
1689c0fe83eSTim Harvey /* calculate new checksum */
1699c0fe83eSTim Harvey memcpy(info->config, econfig_bytes, sizeof(econfig_bytes));
1709c0fe83eSTim Harvey for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
1719c0fe83eSTim Harvey chksum += buf[i];
1729c0fe83eSTim Harvey debug("old chksum:0x%04x\n",
1739c0fe83eSTim Harvey (info->chksum[0] << 8) | info->chksum[1]);
1749c0fe83eSTim Harvey debug("new chksum:0x%04x\n", chksum);
1759c0fe83eSTim Harvey info->chksum[0] = chksum >> 8;
1769c0fe83eSTim Harvey info->chksum[1] = chksum & 0xff;
1779c0fe83eSTim Harvey
1789c0fe83eSTim Harvey /* write new config data */
1799c0fe83eSTim Harvey if (gsc_i2c_write(GSC_EEPROM_ADDR, info->config - (u8 *)info,
1809c0fe83eSTim Harvey 1, econfig_bytes, sizeof(econfig_bytes))) {
1819c0fe83eSTim Harvey printf("EEPROM: Failed updating config\n");
1829c0fe83eSTim Harvey return CMD_RET_FAILURE;
1839c0fe83eSTim Harvey }
1849c0fe83eSTim Harvey
1859c0fe83eSTim Harvey /* write new config data */
1869c0fe83eSTim Harvey if (gsc_i2c_write(GSC_EEPROM_ADDR, info->chksum - (u8 *)info,
1879c0fe83eSTim Harvey 1, info->chksum, 2)) {
1889c0fe83eSTim Harvey printf("EEPROM: Failed updating checksum\n");
1899c0fe83eSTim Harvey return CMD_RET_FAILURE;
1909c0fe83eSTim Harvey }
1919c0fe83eSTim Harvey
1929c0fe83eSTim Harvey printf("Config saved to EEPROM\n");
1939c0fe83eSTim Harvey }
1949c0fe83eSTim Harvey
1959c0fe83eSTim Harvey /* get config */
1969c0fe83eSTim Harvey else if (argc == 2) {
1979c0fe83eSTim Harvey cfg = get_config(argv[1]);
1989c0fe83eSTim Harvey if (cfg) {
1999c0fe83eSTim Harvey printf("%s: %d\n", cfg->name,
2009c0fe83eSTim Harvey test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
2019c0fe83eSTim Harvey } else {
2029c0fe83eSTim Harvey printf("invalid config: %s\n", argv[1]);
2039c0fe83eSTim Harvey return CMD_RET_FAILURE;
2049c0fe83eSTim Harvey }
2059c0fe83eSTim Harvey }
2069c0fe83eSTim Harvey
2079c0fe83eSTim Harvey /* set config */
2089c0fe83eSTim Harvey else if (argc == 3) {
2099c0fe83eSTim Harvey cfg = get_config(argv[1]);
2109c0fe83eSTim Harvey if (cfg) {
2119c0fe83eSTim Harvey if (simple_strtol(argv[2], NULL, 10)) {
2129c0fe83eSTim Harvey test_and_set_bit(cfg->bit, econfig_bytes);
2139c0fe83eSTim Harvey printf("Enabled %s\n", cfg->name);
2149c0fe83eSTim Harvey } else {
2159c0fe83eSTim Harvey test_and_clear_bit(cfg->bit, econfig_bytes);
2169c0fe83eSTim Harvey printf("Disabled %s\n", cfg->name);
2179c0fe83eSTim Harvey }
2189c0fe83eSTim Harvey } else {
2199c0fe83eSTim Harvey printf("invalid config: %s\n", argv[1]);
2209c0fe83eSTim Harvey return CMD_RET_FAILURE;
2219c0fe83eSTim Harvey }
2229c0fe83eSTim Harvey }
2239c0fe83eSTim Harvey
2249c0fe83eSTim Harvey else
2259c0fe83eSTim Harvey return CMD_RET_USAGE;
2269c0fe83eSTim Harvey
2279c0fe83eSTim Harvey return CMD_RET_SUCCESS;
2289c0fe83eSTim Harvey }
2299c0fe83eSTim Harvey
2309c0fe83eSTim Harvey U_BOOT_CMD(
2319c0fe83eSTim Harvey econfig, 3, 0, do_econfig,
2329c0fe83eSTim Harvey "EEPROM configuration",
2339c0fe83eSTim Harvey "list - list config\n"
2349c0fe83eSTim Harvey "save - save config to EEPROM\n"
2359c0fe83eSTim Harvey "<name> - get config 'name'\n"
2369c0fe83eSTim Harvey "<name> [0|1] - set config 'name' to value\n"
2379c0fe83eSTim Harvey );
2389c0fe83eSTim Harvey
2399c0fe83eSTim Harvey #endif /* CONFIG_CMD_EECONFIG */
240