board: gateworks: venice: use common GSC driver
Use the common GSC driver.
This allows us to do some additional cleanup:
 - rename gsc{.c,.h} to eeprom{.c.h} for clarity
 - collapse eeprom_get_dev
 - remove unnecessary header files and alphabatize includes
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
			
			
This commit is contained in:
		
							parent
							
								
									82b16555cf
								
							
						
					
					
						commit
						fb9ec33878
					
				|  | @ -57,6 +57,10 @@ | |||
| 	u-boot,dm-spl; | ||||
| }; | ||||
| 
 | ||||
| &gsc { | ||||
| 	u-boot,dm-spl; | ||||
| }; | ||||
| 
 | ||||
| &i2c2 { | ||||
| 	u-boot,dm-spl; | ||||
| }; | ||||
|  |  | |||
|  | @ -27,6 +27,13 @@ | |||
| 	pinctrl-0 = <&pinctrl_i2c1>; | ||||
| 	status = "okay"; | ||||
| 
 | ||||
| 	gsc: gsc@20 { | ||||
| 		compatible = "gw,gsc"; | ||||
| 		reg = <0x20>; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
| 	}; | ||||
| 
 | ||||
| 	eeprom@51 { | ||||
| 		compatible = "atmel,24c02"; | ||||
| 		reg = <0x51>; | ||||
|  |  | |||
|  | @ -94,6 +94,10 @@ | |||
| 	u-boot,dm-spl; | ||||
| }; | ||||
| 
 | ||||
| &gsc { | ||||
| 	u-boot,dm-spl; | ||||
| }; | ||||
| 
 | ||||
| &i2c2 { | ||||
| 	u-boot,dm-spl; | ||||
| }; | ||||
|  |  | |||
|  | @ -27,6 +27,13 @@ | |||
| 	pinctrl-0 = <&pinctrl_i2c1>; | ||||
| 	status = "okay"; | ||||
| 
 | ||||
| 	gsc: gsc@20 { | ||||
| 		compatible = "gw,gsc"; | ||||
| 		reg = <0x20>; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
| 	}; | ||||
| 
 | ||||
| 	eeprom@51 { | ||||
| 		compatible = "atmel,24c02"; | ||||
| 		reg = <0x51>; | ||||
|  |  | |||
|  | @ -97,6 +97,8 @@ config TARGET_IMX8MM_VENICE | |||
| 	select IMX8MM | ||||
| 	select SUPPORT_SPL | ||||
| 	select IMX8M_LPDDR4 | ||||
| 	select GATEWORKS_SC | ||||
| 	select MISC | ||||
| 
 | ||||
| config TARGET_KONTRON_MX8MM | ||||
| 	bool "Kontron Electronics N80xx" | ||||
|  | @ -143,6 +145,8 @@ config TARGET_IMX8MN_VENICE | |||
| 	select IMX8MN | ||||
| 	select SUPPORT_SPL | ||||
| 	select IMX8M_LPDDR4 | ||||
| 	select GATEWORKS_SC | ||||
| 	select MISC | ||||
| 
 | ||||
| config TARGET_IMX8MP_EVK | ||||
| 	bool "imx8mp LPDDR4 EVK board" | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| # SPDX-License-Identifier: GPL-2.0+
 | ||||
| #
 | ||||
| 
 | ||||
| obj-y += venice.o gsc.o | ||||
| obj-y += venice.o eeprom.o | ||||
| 
 | ||||
| ifdef CONFIG_SPL_BUILD | ||||
| obj-y += spl.o | ||||
|  |  | |||
|  | @ -0,0 +1,353 @@ | |||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * Copyright 2021 Gateworks Corporation | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <gsc.h> | ||||
| #include <hexdump.h> | ||||
| #include <i2c.h> | ||||
| #include <dm/uclass.h> | ||||
| 
 | ||||
| #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 dt>-<som dt>-[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<model>-[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; | ||||
| } | ||||
|  | @ -3,19 +3,8 @@ | |||
|  * Copyright 2021 Gateworks Corporation | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _GSC_H_ | ||||
| #define _GSC_H_ | ||||
| 
 | ||||
| /* I2C bus numbers */ | ||||
| #define GSC_BUSNO			0 | ||||
| #define BASEBOARD_EEPROM_BUSNO		1 | ||||
| 
 | ||||
| /* I2C slave addresses */ | ||||
| #define GSC_SC_ADDR             0x20 | ||||
| #define GSC_RTC_ADDR            0x68 | ||||
| #define GSC_HWMON_ADDR          0x29 | ||||
| #define GSC_EEPROM_ADDR         0x51 | ||||
| #define BASEBOARD_EEPROM_ADDR	0x52 | ||||
| #ifndef _VENICE_EEPROM_H_ | ||||
| #define _VENICE_EEPROM_H_ | ||||
| 
 | ||||
| struct venice_board_info { | ||||
| 	u8 mac[6];		/* 0x00: MAC base */ | ||||
|  | @ -35,11 +24,10 @@ struct venice_board_info { | |||
| 	u8 chksum[2];	/* 0x4E */ | ||||
| }; | ||||
| 
 | ||||
| int gsc_init(int quiet); | ||||
| int gsc_hwmon(void); | ||||
| const char *gsc_get_model(void); | ||||
| const char *gsc_get_dtb_name(int level, char *buf, int len); | ||||
| int gsc_getmac(int index, uint8_t *enetaddr); | ||||
| uint32_t gsc_get_serial(void); | ||||
| int eeprom_init(int quiet); | ||||
| const char *eeprom_get_model(void); | ||||
| const char *eeprom_get_dtb_name(int level, char *buf, int len); | ||||
| int eeprom_getmac(int index, uint8_t *enetaddr); | ||||
| uint32_t eeprom_get_serial(void); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,700 +0,0 @@ | |||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * Copyright 2021 Gateworks Corporation | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <command.h> | ||||
| #include <hang.h> | ||||
| #include <hexdump.h> | ||||
| #include <i2c.h> | ||||
| #include <linux/delay.h> | ||||
| #include <dm/uclass.h> | ||||
| 
 | ||||
| #include "gsc.h" | ||||
| 
 | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| 
 | ||||
| struct venice_board_info som_info; | ||||
| struct venice_board_info base_info; | ||||
| char venice_model[32]; | ||||
| uint32_t venice_serial; | ||||
| 
 | ||||
| /* return a mac address from EEPROM info */ | ||||
| int gsc_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; | ||||
| } | ||||
| 
 | ||||
| /* System Controller registers */ | ||||
| enum { | ||||
| 	GSC_SC_CTRL0		= 0, | ||||
| 	GSC_SC_CTRL1		= 1, | ||||
| 	GSC_SC_STATUS		= 10, | ||||
| 	GSC_SC_FWCRC		= 12, | ||||
| 	GSC_SC_FWVER		= 14, | ||||
| 	GSC_SC_WP		= 15, | ||||
| 	GSC_SC_RST_CAUSE	= 16, | ||||
| 	GSC_SC_THERM_PROTECT	= 19, | ||||
| }; | ||||
| 
 | ||||
| /* System Controller Control1 bits */ | ||||
| enum { | ||||
| 	GSC_SC_CTRL1_WDTIME	= 4, /* 1 = 60s timeout, 0 = 30s timeout */ | ||||
| 	GSC_SC_CTRL1_WDEN	= 5, /* 1 = enable, 0 = disable */ | ||||
| 	GSC_SC_CTRL1_BOOT_CHK   = 6, /* 1 = enable alt boot check */ | ||||
| 	GSC_SC_CTRL1_WDDIS	= 7, /* 1 = disable boot watchdog */ | ||||
| }; | ||||
| 
 | ||||
| /* System Controller Interrupt bits */ | ||||
| enum { | ||||
| 	GSC_SC_IRQ_PB		= 0, /* Pushbutton switch */ | ||||
| 	GSC_SC_IRQ_SECURE	= 1, /* Secure Key erase operation complete */ | ||||
| 	GSC_SC_IRQ_EEPROM_WP	= 2, /* EEPROM write violation */ | ||||
| 	GSC_SC_IRQ_GPIO		= 4, /* GPIO change */ | ||||
| 	GSC_SC_IRQ_TAMPER	= 5, /* Tamper detect */ | ||||
| 	GSC_SC_IRQ_WATCHDOG	= 6, /* Watchdog trip */ | ||||
| 	GSC_SC_IRQ_PBLONG	= 7, /* Pushbutton long hold */ | ||||
| }; | ||||
| 
 | ||||
| /* System Controller WP bits */ | ||||
| enum { | ||||
| 	GSC_SC_WP_ALL		= 0, /* Write Protect All EEPROM regions */ | ||||
| 	GSC_SC_WP_BOARDINFO	= 1, /* Write Protect Board Info region */ | ||||
| }; | ||||
| 
 | ||||
| /* System Controller Reset Cause */ | ||||
| enum { | ||||
| 	GSC_SC_RST_CAUSE_VIN		= 0, | ||||
| 	GSC_SC_RST_CAUSE_PB		= 1, | ||||
| 	GSC_SC_RST_CAUSE_WDT		= 2, | ||||
| 	GSC_SC_RST_CAUSE_CPU		= 3, | ||||
| 	GSC_SC_RST_CAUSE_TEMP_LOCAL	= 4, | ||||
| 	GSC_SC_RST_CAUSE_TEMP_REMOTE	= 5, | ||||
| 	GSC_SC_RST_CAUSE_SLEEP		= 6, | ||||
| 	GSC_SC_RST_CAUSE_BOOT_WDT	= 7, | ||||
| 	GSC_SC_RST_CAUSE_BOOT_WDT_MAN	= 8, | ||||
| 	GSC_SC_RST_CAUSE_SOFT_PWR	= 9, | ||||
| 	GSC_SC_RST_CAUSE_MAX		= 10, | ||||
| }; | ||||
| 
 | ||||
| #include <dm/device.h> | ||||
| static struct udevice *gsc_get_dev(int busno, int slave) | ||||
| { | ||||
| 	struct udevice *dev, *bus; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = uclass_get_device_by_seq(UCLASS_I2C, busno, &bus); | ||||
| 	if (ret) { | ||||
| 		printf("GSC     : failed I2C%d probe: %d\n", busno, ret); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	ret = dm_i2c_probe(bus, slave, 0, &dev); | ||||
| 	if (ret) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	return dev; | ||||
| } | ||||
| 
 | ||||
| static int gsc_read_eeprom(int bus, int slave, int alen, struct venice_board_info *info) | ||||
| { | ||||
| 	int i; | ||||
| 	int chksum; | ||||
| 	unsigned char *buf = (unsigned char *)info; | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* probe device */ | ||||
| 	dev = gsc_get_dev(bus, slave); | ||||
| 	if (!dev) { | ||||
| 		if (slave == GSC_EEPROM_ADDR) | ||||
| 			puts("ERROR: Failed to probe EEPROM\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* 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 == GSC_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", bus, 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", bus, slave); | ||||
| 		print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); | ||||
| 		memset(info, 0, sizeof(*info)); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const char *gsc_get_rst_cause(struct udevice *dev) | ||||
| { | ||||
| 	static char str[64]; | ||||
| 	static const char * const names[] = { | ||||
| 		"VIN", | ||||
| 		"PB", | ||||
| 		"WDT", | ||||
| 		"CPU", | ||||
| 		"TEMP_L", | ||||
| 		"TEMP_R", | ||||
| 		"SLEEP", | ||||
| 		"BOOT_WDT1", | ||||
| 		"BOOT_WDT2", | ||||
| 		"SOFT_PWR", | ||||
| 	}; | ||||
| 	unsigned char reg; | ||||
| 
 | ||||
| 	/* reset cause */ | ||||
| 	str[0] = 0; | ||||
| 	if (!dm_i2c_read(dev, GSC_SC_RST_CAUSE, ®, 1)) { | ||||
| 		if (reg < ARRAY_SIZE(names)) | ||||
| 			sprintf(str, "%s", names[reg]); | ||||
| 		else | ||||
| 			sprintf(str, "0x%02x", reg); | ||||
| 	} | ||||
| 
 | ||||
| 	/* thermal protection */ | ||||
| 	if (!dm_i2c_read(dev, GSC_SC_THERM_PROTECT, ®, 1)) { | ||||
| 		strcat(str, " Thermal Protection "); | ||||
| 		if (reg & BIT(0)) | ||||
| 			strcat(str, "Enabled"); | ||||
| 		else | ||||
| 			strcat(str, "Disabled"); | ||||
| 	} | ||||
| 
 | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* display hardware monitor ADC channels */ | ||||
| int gsc_hwmon(void) | ||||
| { | ||||
| 	const void *fdt = gd->fdt_blob; | ||||
| 	struct udevice *dev; | ||||
| 	int node, reg, mode, len, val, offset; | ||||
| 	const char *label; | ||||
| 	u8 buf[2]; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	node = fdt_node_offset_by_compatible(fdt, -1, "gw,gsc-adc"); | ||||
| 	if (node <= 0) | ||||
| 		return node; | ||||
| 
 | ||||
| 	/* probe device */ | ||||
| 	dev = gsc_get_dev(GSC_BUSNO, GSC_HWMON_ADDR); | ||||
| 	if (!dev) { | ||||
| 		puts("ERROR: Failed to probe GSC HWMON\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* iterate over hwmon nodes */ | ||||
| 	node = fdt_first_subnode(fdt, node); | ||||
| 	while (node > 0) { | ||||
| 		reg = fdtdec_get_int(fdt, node, "reg", -1); | ||||
| 		mode = fdtdec_get_int(fdt, node, "gw,mode", -1); | ||||
| 		offset = fdtdec_get_int(fdt, node, "gw,voltage-offset-microvolt", 0); | ||||
| 		label = fdt_stringlist_get(fdt, node, "label", 0, NULL); | ||||
| 
 | ||||
| 		if ((reg == -1) || (mode == -1) || !label) | ||||
| 			printf("invalid dt:%s\n", fdt_get_name(fdt, node, NULL)); | ||||
| 
 | ||||
| 		memset(buf, 0, sizeof(buf)); | ||||
| 		ret = dm_i2c_read(dev, reg, buf, sizeof(buf)); | ||||
| 		if (ret) { | ||||
| 			printf("i2c error: %d\n", ret); | ||||
| 			continue; | ||||
| 		} | ||||
| 		val = buf[0] | buf[1] << 8; | ||||
| 		if (val >= 0) { | ||||
| 			const u32 *div; | ||||
| 			int r[2]; | ||||
| 
 | ||||
| 			switch (mode) { | ||||
| 			case 0: /* temperature (C*10) */ | ||||
| 				if (val > 0x8000) | ||||
| 					val -= 0xffff; | ||||
| 				printf("%-8s: %d.%ldC\n", label, val / 10, abs(val % 10)); | ||||
| 				break; | ||||
| 			case 1: /* prescaled voltage */ | ||||
| 				if (val != 0xffff) | ||||
| 					printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000); | ||||
| 				break; | ||||
| 			case 2: /* scaled based on ref volt and resolution */ | ||||
| 				val *= 2500; | ||||
| 				val /= 1 << 12; | ||||
| 
 | ||||
| 				/* apply pre-scaler voltage divider */ | ||||
| 				div  = fdt_getprop(fdt, node, "gw,voltage-divider-ohms", &len); | ||||
| 				if (div && (len == sizeof(uint32_t) * 2)) { | ||||
| 					r[0] = fdt32_to_cpu(div[0]); | ||||
| 					r[1] = fdt32_to_cpu(div[1]); | ||||
| 					if (r[0] && r[1]) { | ||||
| 						val *= (r[0] + r[1]); | ||||
| 						val /= r[1]; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				/* adjust by offset */ | ||||
| 				val += (offset / 1000); | ||||
| 
 | ||||
| 				printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		node = fdt_next_subnode(fdt, node); | ||||
| 	} | ||||
| 
 | ||||
| 	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 dt>-<som dt>-[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<model>-[pcb-rev][bom-rev] | ||||
|  * | ||||
|  */ | ||||
| #define snprintfcat(dest, sz, fmt, ...) \ | ||||
| 	snprintf((dest) + strlen(dest), (sz) - strlen(dest), fmt, ##__VA_ARGS__) | ||||
| const char *gsc_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 gsc_read(void) | ||||
| { | ||||
| 	char rev_pcb; | ||||
| 	int rev_bom; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = gsc_read_eeprom(GSC_BUSNO, GSC_EEPROM_ADDR, 1, &som_info); | ||||
| 	if (ret) { | ||||
| 		memset(&som_info, 0, sizeof(som_info)); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* read optional baseboard EEPROM */ | ||||
| 	gsc_read_eeprom(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; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int gsc_info(int verbose) | ||||
| { | ||||
| 	struct udevice *dev; | ||||
| 	unsigned char buf[16]; | ||||
| 
 | ||||
| 	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 > 1) { | ||||
| 		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]); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Display RTC */ | ||||
| 	puts("RTC     : "); | ||||
| 	dev = gsc_get_dev(GSC_BUSNO, GSC_RTC_ADDR); | ||||
| 	if (!dev) { | ||||
| 		puts("Failed to probe GSC RTC\n"); | ||||
| 	} else { | ||||
| 		dm_i2c_read(dev, 0, buf, 6); | ||||
| 		printf("%d\n", buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Display hwmon */ | ||||
| 	gsc_hwmon(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int gsc_init(int quiet) | ||||
| { | ||||
| 	unsigned char buf[16]; | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * On a board with a missing/depleted backup battery for GSC, the | ||||
| 	 * board may be ready to probe the GSC before its firmware is | ||||
| 	 * running.  We will wait here indefinately for the GSC/EEPROM. | ||||
| 	 */ | ||||
| #ifdef CONFIG_IMX8MN | ||||
| 	// TODO:
 | ||||
| 	//   IMX8MN boots quicker than IMX8MM and exposes issue
 | ||||
| 	//   where because GSC I2C state machine isn't running and its
 | ||||
| 	//   SCL/SDA are driven low spams i2c errors
 | ||||
| 	//
 | ||||
| 	//   Put a loop here that somehow waits for I2C CLK/DAT to be high
 | ||||
| 	mdelay(40); | ||||
| #endif | ||||
| 	while (1) { | ||||
| 		/* probe device */ | ||||
| 		dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR); | ||||
| 		if (dev) | ||||
| 			break; | ||||
| 		mdelay(1); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); | ||||
| 	if (ret) { | ||||
| 		puts("ERROR: Failed reading GSC\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	gsc_read(); | ||||
| 
 | ||||
| 	/* banner */ | ||||
| 	if (!quiet) { | ||||
| 		printf("GSC     : v%d 0x%04x", buf[GSC_SC_FWVER], | ||||
| 		       buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC + 1] << 8); | ||||
| 		printf(" RST:%s", gsc_get_rst_cause(dev)); | ||||
| 		printf("\n"); | ||||
| 		gsc_info(1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		hang(); | ||||
| 
 | ||||
| 	return (16 << som_info.sdram_size); | ||||
| } | ||||
| 
 | ||||
| const char *gsc_get_model(void) | ||||
| { | ||||
| 	return venice_model; | ||||
| } | ||||
| 
 | ||||
| uint32_t gsc_get_serial(void) | ||||
| { | ||||
| 	return venice_serial; | ||||
| } | ||||
| 
 | ||||
| #if !(IS_ENABLED(CONFIG_SPL_BUILD)) | ||||
| static int gsc_sleep(unsigned long secs) | ||||
| { | ||||
| 	unsigned char reg; | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* probe device */ | ||||
| 	dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR); | ||||
| 	if (!dev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	printf("GSC Sleeping for %ld seconds\n", secs); | ||||
| 	reg = (secs >> 24) & 0xff; | ||||
| 	ret = dm_i2c_write(dev, 9, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg = (secs >> 16) & 0xff; | ||||
| 	ret = dm_i2c_write(dev, 8, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg = (secs >> 8) & 0xff; | ||||
| 	ret = dm_i2c_write(dev, 7, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg = secs & 0xff; | ||||
| 	ret = dm_i2c_write(dev, 6, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	ret = dm_i2c_read(dev, GSC_SC_CTRL1, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg |= (1 << 2); | ||||
| 	ret = dm_i2c_write(dev, GSC_SC_CTRL1, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg &= ~(1 << 2); | ||||
| 	reg |= 0x3; | ||||
| 	ret = dm_i2c_write(dev, GSC_SC_CTRL1, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	printf("i2c error\n"); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int gsc_boot_wd_disable(void) | ||||
| { | ||||
| 	u8 reg; | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* probe device */ | ||||
| 	dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR); | ||||
| 	if (!dev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	ret = dm_i2c_read(dev, GSC_SC_CTRL1, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	reg |= (1 << GSC_SC_CTRL1_WDDIS); | ||||
| 	reg &= ~(1 << GSC_SC_CTRL1_BOOT_CHK); | ||||
| 	ret = dm_i2c_write(dev, GSC_SC_CTRL1, ®, 1); | ||||
| 	if (ret) | ||||
| 		goto err; | ||||
| 	puts("GSC     : boot watchdog disabled\n"); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	printf("i2c error"); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int do_gsc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) | ||||
| { | ||||
| 	if (argc < 2) | ||||
| 		return gsc_info(2); | ||||
| 
 | ||||
| 	if (strcasecmp(argv[1], "sleep") == 0) { | ||||
| 		if (argc < 3) | ||||
| 			return CMD_RET_USAGE; | ||||
| 		if (!gsc_sleep(dectoul(argv[2], NULL))) | ||||
| 			return CMD_RET_SUCCESS; | ||||
| 	} else if (strcasecmp(argv[1], "hwmon") == 0) { | ||||
| 		if (!gsc_hwmon()) | ||||
| 			return CMD_RET_SUCCESS; | ||||
| 	} else if (strcasecmp(argv[1], "wd-disable") == 0) { | ||||
| 		if (!gsc_boot_wd_disable()) | ||||
| 			return CMD_RET_SUCCESS; | ||||
| 	} | ||||
| 
 | ||||
| 	return CMD_RET_USAGE; | ||||
| } | ||||
| 
 | ||||
| U_BOOT_CMD(gsc, 4, 1, do_gsc, "Gateworks System Controller", | ||||
| 	   "[sleep <secs>]|[hwmon]|[wd-disable]\n"); | ||||
| #endif | ||||
|  | @ -7,13 +7,9 @@ | |||
| #include <cpu_func.h> | ||||
| #include <hang.h> | ||||
| #include <i2c.h> | ||||
| #include <image.h> | ||||
| #include <init.h> | ||||
| #include <log.h> | ||||
| #include <spl.h> | ||||
| #include <asm/io.h> | ||||
| #include <asm/mach-imx/gpio.h> | ||||
| #include <asm/mach-imx/iomux-v3.h> | ||||
| #include <asm/arch/clock.h> | ||||
| #include <asm/arch/imx8mm_pins.h> | ||||
| #include <asm/arch/imx8mn_pins.h> | ||||
|  | @ -21,22 +17,17 @@ | |||
| #include <asm/mach-imx/boot_mode.h> | ||||
| #include <asm/arch/ddr.h> | ||||
| #include <asm-generic/gpio.h> | ||||
| 
 | ||||
| #include <dm/uclass.h> | ||||
| #include <dm/device.h> | ||||
| #include <dm/uclass-internal.h> | ||||
| #include <dm/device-internal.h> | ||||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <power/bd71837.h> | ||||
| #include <power/mp5416.h> | ||||
| 
 | ||||
| #include "gsc.h" | ||||
| #include "eeprom.h" | ||||
| #include "lpddr4_timing.h" | ||||
| 
 | ||||
| #define PCIE_RSTN IMX_GPIO_NR(4, 6) | ||||
| 
 | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| 
 | ||||
| static void spl_dram_init(int size) | ||||
| { | ||||
| 	struct dram_timing_info *dram_timing; | ||||
|  | @ -65,8 +56,8 @@ static void spl_dram_init(int size) | |||
| 		dram_timing = &dram_timing_1gb_single_die; | ||||
| 		break; | ||||
| 	case 2048: | ||||
| 		if (!strcmp(gsc_get_model(), "GW7902-SP466-A") || | ||||
| 		    !strcmp(gsc_get_model(), "GW7902-SP466-B")) { | ||||
| 		if (!strcmp(eeprom_get_model(), "GW7902-SP466-A") || | ||||
| 		    !strcmp(eeprom_get_model(), "GW7902-SP466-B")) { | ||||
| 			dram_timing = &dram_timing_2gb_dual_die; | ||||
| 		} else { | ||||
| 			dram_timing = &dram_timing_2gb_single_die; | ||||
|  | @ -149,7 +140,7 @@ static int dm_i2c_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) | |||
| 
 | ||||
| static int power_init_board(void) | ||||
| { | ||||
| 	const char *model = gsc_get_model(); | ||||
| 	const char *model = eeprom_get_model(); | ||||
| 	struct udevice *bus; | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
|  | @ -243,22 +234,36 @@ void board_init_f(ulong dummy) | |||
| 		hang(); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = uclass_get_device_by_name(UCLASS_CLK, | ||||
| 					"clock-controller@30380000", | ||||
| 					&dev); | ||||
| 	if (ret < 0) { | ||||
| 		printf("Failed to find clock node. Check device tree\n"); | ||||
| 		hang(); | ||||
| 	} | ||||
| 
 | ||||
| 	enable_tzc380(); | ||||
| 
 | ||||
| 	/* need to hold PCIe switch in reset otherwise it can lock i2c bus EEPROM is on */ | ||||
| 	gpio_request(PCIE_RSTN, "perst#"); | ||||
| 	gpio_direction_output(PCIE_RSTN, 0); | ||||
| 
 | ||||
| 	/* GSC */ | ||||
| 	dram_sz = gsc_init(0); | ||||
| 	/*
 | ||||
| 	 * probe GSC device | ||||
| 	 * | ||||
| 	 * On a board with a missing/depleted backup battery for GSC, the | ||||
| 	 * board may be ready to probe the GSC before its firmware is | ||||
| 	 * running. We will wait here indefinately for the GSC EEPROM. | ||||
| 	 */ | ||||
| #ifdef CONFIG_IMX8MN | ||||
| 	/*
 | ||||
| 	 * IMX8MN boots quicker than IMX8MM and exposes issue | ||||
| 	 * where because GSC I2C state machine isn't running and its | ||||
| 	 * SCL/SDA are driven low the I2C driver spams 'Arbitration lost' | ||||
| 	 * I2C errors. | ||||
| 	 * | ||||
| 	 * TODO: Put a loop here that somehow waits for I2C CLK/DAT to be high | ||||
| 	 */ | ||||
| 	mdelay(50); | ||||
| #endif | ||||
| 	while (1) { | ||||
| 		if (!uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(gsc), &dev)) | ||||
| 			break; | ||||
| 		mdelay(1); | ||||
| 	} | ||||
| 	dram_sz = eeprom_init(0); | ||||
| 
 | ||||
| 	/* PMIC */ | ||||
| 	power_init_board(); | ||||
|  |  | |||
|  | @ -3,21 +3,12 @@ | |||
|  * Copyright 2021 Gateworks Corporation | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <init.h> | ||||
| #include <led.h> | ||||
| #include <linux/delay.h> | ||||
| #include <miiphy.h> | ||||
| #include <netdev.h> | ||||
| 
 | ||||
| #include <asm/arch/clock.h> | ||||
| #include <asm/arch/sys_proto.h> | ||||
| #include <asm/io.h> | ||||
| #include <asm/unaligned.h> | ||||
| 
 | ||||
| #include "gsc.h" | ||||
| 
 | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| #include "eeprom.h" | ||||
| 
 | ||||
| int board_phys_sdram_size(phys_size_t *size) | ||||
| { | ||||
|  | @ -37,7 +28,7 @@ int board_fit_config_name_match(const char *name) | |||
| 	char buf[32]; | ||||
| 
 | ||||
| 	do { | ||||
| 		dtb = gsc_get_dtb_name(i++, buf, sizeof(buf)); | ||||
| 		dtb = eeprom_get_dtb_name(i++, buf, sizeof(buf)); | ||||
| 		if (!strcmp(dtb, name)) { | ||||
| 			if (!init++) | ||||
| 				printf("DTB     : %s\n", name); | ||||
|  | @ -100,13 +91,11 @@ int board_phy_config(struct phy_device *phydev) | |||
| 
 | ||||
| int board_init(void) | ||||
| { | ||||
| 	gsc_init(1); | ||||
| 	eeprom_init(1); | ||||
| 
 | ||||
| 	if (IS_ENABLED(CONFIG_FEC_MXC)) | ||||
| 		setup_fec(); | ||||
| 
 | ||||
| 	gsc_hwmon(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -122,13 +111,13 @@ int board_late_init(void) | |||
| 
 | ||||
| 	/* Set board serial/model */ | ||||
| 	if (!env_get("serial#")) | ||||
| 		env_set_ulong("serial#", gsc_get_serial()); | ||||
| 	env_set("model", gsc_get_model()); | ||||
| 		env_set_ulong("serial#", eeprom_get_serial()); | ||||
| 	env_set("model", eeprom_get_model()); | ||||
| 
 | ||||
| 	/* Set fdt_file vars */ | ||||
| 	i = 0; | ||||
| 	do { | ||||
| 		str = gsc_get_dtb_name(i, fdt, sizeof(fdt)); | ||||
| 		str = eeprom_get_dtb_name(i, fdt, sizeof(fdt)); | ||||
| 		if (str) { | ||||
| 			sprintf(env, "fdt_file%d", i + 1); | ||||
| 			strcat(fdt, ".dtb"); | ||||
|  | @ -146,7 +135,7 @@ int board_late_init(void) | |||
| 			sprintf(env, "ethaddr"); | ||||
| 		str = env_get(env); | ||||
| 		if (!str) { | ||||
| 			ret = gsc_getmac(i, enetaddr); | ||||
| 			ret = eeprom_getmac(i, enetaddr); | ||||
| 			if (!ret) | ||||
| 				eth_env_set_enetaddr(env, enetaddr); | ||||
| 		} | ||||
|  | @ -166,7 +155,7 @@ int ft_board_setup(void *blob, struct bd_info *bd) | |||
| 	int off; | ||||
| 
 | ||||
| 	/* set board model dt prop */ | ||||
| 	fdt_setprop_string(blob, 0, "board", gsc_get_model()); | ||||
| 	fdt_setprop_string(blob, 0, "board", eeprom_get_model()); | ||||
| 
 | ||||
| 	/* update temp thresholds */ | ||||
| 	off = fdt_path_offset(blob, "/thermal-zones/cpu-thermal/trips"); | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ CONFIG_SPL_TEXT_BASE=0x912000 | |||
| CONFIG_TARGET_IMX8MN_VENICE=y | ||||
| CONFIG_SPL_MMC=y | ||||
| CONFIG_SPL_SERIAL=y | ||||
| CONFIG_SPL_DRIVERS_MISC=y | ||||
| CONFIG_SPL=y | ||||
| CONFIG_ENV_OFFSET_REDUND=0xff8000 | ||||
| CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue