1193326Sed// SPDX-License-Identifier: GPL-2.0-or-later 2193326Sed/* 3193326Sed * Copyright (C) 2023 PHYTEC Messtechnik GmbH 4193326Sed * Author: Teresa Remmet <t.remmet@phytec.de> 5193326Sed */ 6193326Sed 7193326Sed#include <common.h> 8193326Sed#include <dm/device.h> 9193326Sed#include <dm/uclass.h> 10193326Sed#include <i2c.h> 11193326Sed#include <u-boot/crc.h> 12193326Sed#include <malloc.h> 13193326Sed#include <extension_board.h> 14193326Sed 15249423Sdim#include "phytec_som_detection.h" 16193326Sed 17193326Sedstruct phytec_eeprom_data eeprom_data; 18193326Sed 19234353Sdim#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) 20193326Sed 21249423Sdimint phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data, 22249423Sdim int bus_num, int addr, int addr_fallback) 23249423Sdim{ 24249423Sdim int ret; 25193326Sed 26193326Sed ret = phytec_eeprom_data_init(data, bus_num, addr); 27193326Sed if (ret) { 28193326Sed pr_err("%s: init failed. Trying fall back address 0x%x\n", 29193326Sed __func__, addr_fallback); 30193326Sed ret = phytec_eeprom_data_init(data, bus_num, addr_fallback); 31193326Sed } 32193326Sed 33199990Srdivacky if (ret) 34193326Sed pr_err("%s: EEPROM data init failed\n", __func__); 35193326Sed 36218893Sdim return ret; 37288943Sdim} 38208600Srdivacky 39226633Sdimint phytec_eeprom_data_setup(struct phytec_eeprom_data *data, 40226633Sdim int bus_num, int addr) 41226633Sdim{ 42226633Sdim int ret; 43226633Sdim 44226633Sdim ret = phytec_eeprom_data_init(data, bus_num, addr); 45226633Sdim if (ret) 46226633Sdim pr_err("%s: EEPROM data init failed\n", __func__); 47226633Sdim 48208600Srdivacky return ret; 49226633Sdim} 50226633Sdim 51208600Srdivackyint phytec_eeprom_data_init(struct phytec_eeprom_data *data, 52296417Sdim int bus_num, int addr) 53296417Sdim{ 54208600Srdivacky int ret, i; 55208600Srdivacky unsigned int crc; 56218893Sdim u8 *ptr; 57218893Sdim const unsigned int payload_size = sizeof(struct phytec_eeprom_payload); 58218893Sdim 59218893Sdim if (!data) 60239462Sdim data = &eeprom_data; 61239462Sdim 62239462Sdim#if CONFIG_IS_ENABLED(DM_I2C) 63239462Sdim struct udevice *dev; 64218893Sdim 65193326Sed ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev); 66288943Sdim if (ret) { 67288943Sdim pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret); 68288943Sdim goto err; 69193326Sed } 70193326Sed 71193326Sed ret = dm_i2c_read(dev, 0, (uint8_t *)data, payload_size); 72193326Sed if (ret) { 73193326Sed pr_err("%s: Unable to read EEPROM data: %i\n", __func__, ret); 74193326Sed goto err; 75193326Sed } 76193326Sed#else 77193326Sed i2c_set_bus_num(bus_num); 78193326Sed ret = i2c_read(addr, 0, 2, (uint8_t *)data, 79193326Sed sizeof(struct phytec_eeprom_data)); 80239462Sdim#endif 81296417Sdim 82239462Sdim if (data->payload.api_rev == 0xff) { 83239462Sdim pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__); 84193326Sed ret = -EINVAL; 85226633Sdim goto err; 86208600Srdivacky } 87296417Sdim 88234353Sdim ptr = (u8 *)data; 89234353Sdim for (i = 0; i < payload_size; ++i) 90226633Sdim if (ptr[i] != 0x0) 91234353Sdim break; 92226633Sdim 93226633Sdim if (i == payload_size) { 94226633Sdim pr_err("%s: EEPROM data is all zero. Erased?\n", __func__); 95226633Sdim ret = -EINVAL; 96208600Srdivacky goto err; 97208600Srdivacky } 98193326Sed 99193326Sed /* We are done here for early revisions */ 100193326Sed if (data->payload.api_rev <= PHYTEC_API_REV1) { 101198092Srdivacky data->valid = true; 102288943Sdim return 0; 103288943Sdim } 104288943Sdim 105288943Sdim crc = crc8(0, (const unsigned char *)&data->payload, payload_size); 106288943Sdim debug("%s: crc: %x\n", __func__, crc); 107193326Sed 108193326Sed if (crc) { 109193326Sed pr_err("%s: CRC mismatch. EEPROM data is not usable.\n", 110193326Sed __func__); 111221345Sdim ret = -EINVAL; 112221345Sdim goto err; 113221345Sdim } 114193326Sed 115224145Sdim data->valid = true; 116224145Sdim return 0; 117224145Sdimerr: 118193326Sed data->valid = false; 119193326Sed return ret; 120234353Sdim} 121234353Sdim 122234353Sdimvoid __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data) 123234353Sdim{ 124234353Sdim struct phytec_api2_data *api2; 125234353Sdim char pcb_sub_rev; 126234353Sdim unsigned int ksp_no, sub_som_type1, sub_som_type2; 127234353Sdim 128234353Sdim if (!data) 129234353Sdim data = &eeprom_data; 130239462Sdim 131234353Sdim if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2) 132234353Sdim return; 133234353Sdim 134234353Sdim api2 = &data->payload.data.data_api2; 135234353Sdim 136234353Sdim /* Calculate PCB subrevision */ 137234353Sdim pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f; 138193326Sed pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' '; 139193326Sed 140193326Sed /* print standard product string */ 141224145Sdim if (api2->som_type <= 1) { 142193326Sed printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n", 143193326Sed phytec_som_type_str[api2->som_type], api2->som_no, 144193326Sed api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev); 145193326Sed return; 146198092Srdivacky } 147193326Sed /* print KSP/KSM string */ 148198092Srdivacky if (api2->som_type <= 3) { 149193326Sed ksp_no = (api2->ksp_no << 8) | api2->som_no; 150198092Srdivacky printf("SoM: %s-%u ", 151193326Sed phytec_som_type_str[api2->som_type], ksp_no); 152193326Sed /* print standard product based KSP/KSM strings */ 153193326Sed } else { 154198398Srdivacky switch (api2->som_type) { 155193326Sed case 4: 156193326Sed sub_som_type1 = 0; 157193326Sed sub_som_type2 = 3; 158193326Sed break; 159193326Sed case 5: 160193326Sed sub_som_type1 = 0; 161193326Sed sub_som_type2 = 2; 162198092Srdivacky break; 163288943Sdim case 6: 164218893Sdim sub_som_type1 = 1; 165198092Srdivacky sub_som_type2 = 3; 166193326Sed break; 167201361Srdivacky case 7: 168288943Sdim sub_som_type1 = 1; 169193326Sed sub_som_type2 = 2; 170193326Sed break; 171193326Sed default: 172251662Sdim pr_err("%s: Invalid SoM type: %i", __func__, api2->som_type); 173251662Sdim return; 174251662Sdim }; 175251662Sdim 176193326Sed printf("SoM: %s-%03u-%s-%03u ", 177193326Sed phytec_som_type_str[sub_som_type1], 178234353Sdim api2->som_no, phytec_som_type_str[sub_som_type2], 179261991Sdim api2->ksp_no); 180218893Sdim } 181210299Sed 182199482Srdivacky printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt, 183224145Sdim api2->bom_rev, api2->pcb_rev, pcb_sub_rev); 184218893Sdim} 185218893Sdim 186234353Sdimchar * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data) 187234353Sdim{ 188234353Sdim char *opt; 189239462Sdim 190234353Sdim if (!data) 191234353Sdim data = &eeprom_data; 192234353Sdim 193234353Sdim if (!data->valid) 194234353Sdim return NULL; 195193326Sed 196193326Sed if (data->payload.api_rev < PHYTEC_API_REV2) 197224145Sdim opt = data->payload.data.data_api0.opt; 198224145Sdim else 199193326Sed opt = data->payload.data.data_api2.opt; 200200583Srdivacky 201226633Sdim return opt; 202296417Sdim} 203296417Sdim 204226633Sdimu8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data) 205193326Sed{ 206193326Sed struct phytec_api2_data *api2; 207193326Sed 208193326Sed if (!data) 209193326Sed data = &eeprom_data; 210193326Sed 211193326Sed if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2) 212193326Sed return PHYTEC_EEPROM_INVAL; 213193326Sed 214193326Sed api2 = &data->payload.data.data_api2; 215193326Sed 216193326Sed return api2->pcb_rev; 217249423Sdim} 218249423Sdim 219288943Sdimu8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data) 220261991Sdim{ 221249423Sdim if (!data) 222249423Sdim data = &eeprom_data; 223249423Sdim 224239462Sdim if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2) 225193326Sed return PHYTEC_EEPROM_INVAL; 226193326Sed 227208600Srdivacky return data->payload.data.data_api2.som_type; 228208600Srdivacky} 229208600Srdivacky 230208600Srdivacky#if IS_ENABLED(CONFIG_CMD_EXTENSION) 231208600Srdivackystruct extension *phytec_add_extension(const char *name, const char *overlay, 232208600Srdivacky const char *other) 233208600Srdivacky{ 234208600Srdivacky struct extension *extension; 235208600Srdivacky 236249423Sdim if (strlen(overlay) > sizeof(extension->overlay)) { 237208600Srdivacky pr_err("Overlay name %s is longer than %lu.\n", overlay, 238208600Srdivacky sizeof(extension->overlay)); 239208600Srdivacky return NULL; 240208600Srdivacky } 241208600Srdivacky 242208600Srdivacky extension = calloc(1, sizeof(struct extension)); 243208600Srdivacky snprintf(extension->name, sizeof(extension->name), name); 244226633Sdim snprintf(extension->overlay, sizeof(extension->overlay), overlay); 245226633Sdim snprintf(extension->other, sizeof(extension->other), other); 246208600Srdivacky snprintf(extension->owner, sizeof(extension->owner), "PHYTEC"); 247208600Srdivacky 248208600Srdivacky return extension; 249226633Sdim} 250226633Sdim#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */ 251226633Sdim 252226633Sdim#else 253226633Sdim 254239462Sdiminline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data, 255226633Sdim int bus_num, int addr) 256226633Sdim{ 257226633Sdim return PHYTEC_EEPROM_INVAL; 258226633Sdim} 259226633Sdim 260210299Sedinline int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data, 261226633Sdim int bus_num, int addr, 262239462Sdim int addr_fallback) 263296417Sdim{ 264296417Sdim return PHYTEC_EEPROM_INVAL; 265208600Srdivacky} 266208600Srdivacky 267193326Sedinline int phytec_eeprom_data_init(struct phytec_eeprom_data *data, 268296417Sdim int bus_num, int addr) 269239462Sdim{ 270296417Sdim return PHYTEC_EEPROM_INVAL; 271239462Sdim} 272239462Sdim 273193326Sedinline void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data) 274239462Sdim{ 275239462Sdim} 276218893Sdim 277239462Sdiminline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data *data) 278239462Sdim{ 279239462Sdim return NULL; 280239462Sdim} 281239462Sdim 282212904Sdimu8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data) 283239462Sdim{ 284239462Sdim return PHYTEC_EEPROM_INVAL; 285239462Sdim} 286239462Sdim 287239462Sdimu8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data) 288193326Sed{ 289239462Sdim return PHYTEC_EEPROM_INVAL; 290239462Sdim} 291239462Sdim 292239462Sdim#if IS_ENABLED(CONFIG_CMD_EXTENSION) 293239462Sdiminline struct extension *phytec_add_extension(const char *name, 294239462Sdim const char *overlay, 295239462Sdim const char *other) 296239462Sdim{ 297239462Sdim return NULL; 298198092Srdivacky} 299296417Sdim#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */ 300296417Sdim 301239462Sdim#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */ 302198092Srdivacky