diff options
author | Teresa Remmet <t.remmet@phytec.de> | 2023-08-17 10:57:06 +0200 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2023-10-16 11:27:58 +0200 |
commit | dc22188cdc843d212cda1423a924a0a90ca83784 (patch) | |
tree | 83d5c2353d71f63e2d510c162eea4dbefa3a80a9 /board/phytec/common/phytec_som_detection.c | |
parent | 7b9c99b2d928881c89bb2abe6eaf4b0228ba7ad9 (diff) |
board: phytec: Add common PHYTEC SoM detection
Recent shipped PHYTEC SoMs come with an i2c EEPROM containing
information about the hardware such as board revision and variant.
This can be used for RAM detection and loading device tree overlays
during kernel start.
Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
Reviewed-by: Yannic Moog <y.moog@phytec.de>
Tested-by: Yannic Moog <y.moog@phytec.de>
Reviewed-by: Fabio Estevam <festevam@gmail.com>
Diffstat (limited to 'board/phytec/common/phytec_som_detection.c')
-rw-r--r-- | board/phytec/common/phytec_som_detection.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/board/phytec/common/phytec_som_detection.c b/board/phytec/common/phytec_som_detection.c new file mode 100644 index 0000000000..366bdd4ace --- /dev/null +++ b/board/phytec/common/phytec_som_detection.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 PHYTEC Messtechnik GmbH + * Author: Teresa Remmet <t.remmet@phytec.de> + */ + +#include <common.h> +#include <asm/mach-imx/mxc_i2c.h> +#include <asm/arch/sys_proto.h> +#include <dm/device.h> +#include <dm/uclass.h> +#include <i2c.h> +#include <u-boot/crc.h> + +#include "phytec_som_detection.h" + +struct phytec_eeprom_data eeprom_data; + +int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data, + int bus_num, int addr, int addr_fallback) +{ + int ret; + + ret = phytec_eeprom_data_init(data, bus_num, addr); + if (ret) { + pr_err("%s: init failed. Trying fall back address 0x%x\n", + __func__, addr_fallback); + ret = phytec_eeprom_data_init(data, bus_num, addr_fallback); + } + + if (ret) + pr_err("%s: EEPROM data init failed\n", __func__); + + return ret; +} + +int phytec_eeprom_data_setup(struct phytec_eeprom_data *data, + int bus_num, int addr) +{ + int ret; + + ret = phytec_eeprom_data_init(data, bus_num, addr); + if (ret) + pr_err("%s: EEPROM data init failed\n", __func__); + + return ret; +} + +int phytec_eeprom_data_init(struct phytec_eeprom_data *data, + int bus_num, int addr) +{ + int ret, i; + unsigned int crc; + int *ptr; + + if (!data) + data = &eeprom_data; + +#if CONFIG_IS_ENABLED(DM_I2C) + struct udevice *dev; + + ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev); + if (ret) { + pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret); + return ret; + } + + ret = dm_i2c_read(dev, 0, (uint8_t *)data, + sizeof(struct phytec_eeprom_data)); + if (ret) { + pr_err("%s: Unable to read EEPROM data\n", __func__); + return ret; + } +#else + i2c_set_bus_num(bus_num); + ret = i2c_read(addr, 0, 2, (uint8_t *)data, + sizeof(struct phytec_eeprom_data)); +#endif + + if (data->api_rev == 0xff) { + pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__); + return -EINVAL; + } + + ptr = (int *)data; + for (i = 0; i < sizeof(struct phytec_eeprom_data); i += sizeof(ptr)) + if (*ptr != 0x0) + break; + + if (i == sizeof(struct phytec_eeprom_data)) { + pr_err("%s: EEPROM data is all zero. Erased?\n", __func__); + return -EINVAL; + } + + /* We are done here for early revisions */ + if (data->api_rev <= PHYTEC_API_REV1) + return 0; + + crc = crc8(0, (const unsigned char *)data, + sizeof(struct phytec_eeprom_data)); + debug("%s: crc: %x\n", __func__, crc); + + if (crc) { + pr_err("%s: CRC mismatch. EEPROM data is not usable\n", + __func__); + return -EINVAL; + } + + return 0; +} + +void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data) +{ + struct phytec_api2_data *api2; + char pcb_sub_rev; + unsigned int ksp_no, sub_som_type1, sub_som_type2; + + if (!data) + data = &eeprom_data; + + if (data->api_rev < PHYTEC_API_REV2) + return; + + api2 = &data->data.data_api2; + + /* Calculate PCB subrevision */ + pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f; + pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' '; + + /* print standard product string */ + if (api2->som_type <= 1) { + printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n", + phytec_som_type_str[api2->som_type], api2->som_no, + api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev); + return; + } + /* print KSP/KSM string */ + if (api2->som_type <= 3) { + ksp_no = (api2->ksp_no << 8) | api2->som_no; + printf("SoM: %s-%u ", + phytec_som_type_str[api2->som_type], ksp_no); + /* print standard product based KSP/KSM strings */ + } else { + switch (api2->som_type) { + case 4: + sub_som_type1 = 0; + sub_som_type2 = 3; + break; + case 5: + sub_som_type1 = 0; + sub_som_type2 = 2; + break; + case 6: + sub_som_type1 = 1; + sub_som_type2 = 3; + break; + case 7: + sub_som_type1 = 1; + sub_som_type2 = 2; + break; + default: + break; + }; + + printf("SoM: %s-%03u-%s-%03u ", + phytec_som_type_str[sub_som_type1], + api2->som_no, phytec_som_type_str[sub_som_type2], + api2->ksp_no); + } + + printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt, + api2->bom_rev, api2->pcb_rev, pcb_sub_rev); +} + +char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data) +{ + char *opt; + + if (!data) + data = &eeprom_data; + + if (data->api_rev < PHYTEC_API_REV2) + opt = data->data.data_api0.opt; + else + opt = data->data.data_api2.opt; + + return opt; +} |