xref: /rk3399_rockchip-uboot/board/gateworks/gw_ventana/eeprom.c (revision 1622559066d890f1b7622be0ede8a5d64de66ef3)
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