1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2018 NXP 4 * Copyright 2020 Linaro 5 */ 6 7#include <common.h> 8#include <efi.h> 9#include <efi_loader.h> 10#include <env.h> 11#include <extension_board.h> 12#include <hang.h> 13#include <i2c.h> 14#include <init.h> 15#include <miiphy.h> 16#include <netdev.h> 17#include <i2c_eeprom.h> 18#include <i2c.h> 19 20#include <asm/arch/clock.h> 21#include <asm/arch/imx8mm_pins.h> 22#include <asm/arch/sys_proto.h> 23#include <asm/global_data.h> 24#include <asm/io.h> 25#include <asm/mach-imx/gpio.h> 26#include <asm/mach-imx/mxc_i2c.h> 27#include <asm/sections.h> 28#include <linux/kernel.h> 29 30#include "ddr/ddr.h" 31 32DECLARE_GLOBAL_DATA_PTR; 33 34#if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) 35struct efi_fw_image fw_images[] = { 36#if defined(CONFIG_TARGET_IMX8MM_CL_IOT_GATE) 37 { 38 .image_type_id = IMX8MM_CL_IOT_GATE_FIT_IMAGE_GUID, 39 .fw_name = u"IMX8MM-CL-IOT-GATE-FIT", 40 .image_index = 1, 41 }, 42#elif defined(CONFIG_TARGET_IMX8MM_CL_IOT_GATE_OPTEE) 43 { 44 .image_type_id = IMX8MM_CL_IOT_GATE_OPTEE_FIT_IMAGE_GUID, 45 .fw_name = u"IMX8MM-CL-IOT-GATE-FIT", 46 .image_index = 1, 47 }, 48#endif 49}; 50 51struct efi_capsule_update_info update_info = { 52 .dfu_string = "mmc 2=flash-bin raw 0x42 0x1D00 mmcpart 1", 53 .num_images = ARRAY_SIZE(fw_images), 54 .images = fw_images, 55}; 56 57#endif /* EFI_HAVE_CAPSULE_SUPPORT */ 58 59int board_phys_sdram_size(phys_size_t *size) 60{ 61 struct lpddr4_tcm_desc *lpddr4_tcm_desc = 62 (struct lpddr4_tcm_desc *)TCM_DATA_CFG; 63 64 switch (lpddr4_tcm_desc->size) { 65 case 4096: 66 case 2048: 67 case 1024: 68 *size = (1L << 20) * lpddr4_tcm_desc->size; 69 break; 70 default: 71 printf("%s: DRAM size %uM is not supported\n", 72 __func__, 73 lpddr4_tcm_desc->size); 74 hang(); 75 break; 76 }; 77 78 return 0; 79} 80 81/* IOT_GATE-iMX8 extension boards ID */ 82typedef enum { 83 IOT_GATE_EXT_EMPTY, /* No extension */ 84 IOT_GATE_EXT_CAN, /* CAN bus */ 85 IOT_GATE_EXT_IED, /* Bridge */ 86 IOT_GATE_EXT_POE, /* POE */ 87 IOT_GATE_EXT_POEV2, /* POEv2 */ 88} iot_gate_imx8_ext; 89 90typedef enum { 91 IOT_GATE_IMX8_CARD_ID_EMPTY = 0, /* card id - uninhabited */ 92 IOT_GATE_IMX8_CARD_ID_DI4O4 = 1, /* Card ID - IED-DI4O4 */ 93 IOT_GATE_IMX8_CARD_ID_RS_485 = 2, /* Card ID - IED-RS485 */ 94 IOT_GATE_IMX8_CARD_ID_TPM = 3, /* Card ID - IED-TPM */ 95 IOT_GATE_IMX8_CARD_ID_CAN = 4, /* Card ID - IED-CAN */ 96 IOT_GATE_IMX8_CARD_ID_CL420 = 5, /* Card ID - IED-CL420 */ 97 IOT_GATE_IMX8_CARD_ID_RS_232 = 6, /* Card ID - IED-RS232 */ 98} iot_gate_imx8_ied_ext; 99 100static int setup_fec(void) 101{ 102 if (IS_ENABLED(CONFIG_FEC_MXC)) { 103 struct iomuxc_gpr_base_regs *gpr = 104 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR; 105 106 /* Use 125M anatop REF_CLK1 for ENET1, not from external */ 107 clrsetbits_le32(&gpr->gpr[1], 0x2000, 0); 108 } 109 110 return 0; 111} 112 113int board_phy_config(struct phy_device *phydev) 114{ 115 if (IS_ENABLED(CONFIG_FEC_MXC)) { 116 /* enable rgmii rxc skew and phy mode select to RGMII copper */ 117 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); 118 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8); 119 120 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00); 121 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee); 122 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); 123 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 124 125 if (phydev->drv->config) 126 phydev->drv->config(phydev); 127 } 128 return 0; 129} 130 131int board_init(void) 132{ 133 if (IS_ENABLED(CONFIG_FEC_MXC)) 134 setup_fec(); 135 136 return 0; 137} 138 139int board_mmc_get_env_dev(int devno) 140{ 141 return devno; 142} 143 144#define IOT_GATE_IMX8_EXT_I2C 3 /* I2C ID of the extension board */ 145#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM 0x54 /* I2C address of the EEPROM */ 146 147/* I2C address of the EEPROM in the POE extension */ 148#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE 0x50 149#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2 0x51 150#define IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO 0x22 /* I2C address of the GPIO 151 extender */ 152 153static int iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY; /* Extension board ID */ 154static int iot_gate_imx8_ext_ied_id [3] = { 155 IOT_GATE_IMX8_CARD_ID_EMPTY, 156 IOT_GATE_IMX8_CARD_ID_EMPTY, 157 IOT_GATE_IMX8_CARD_ID_EMPTY }; 158 159/* 160 * iot_gate_imx8_detect_ext() - extended board detection 161 * The detection is done according to the detected I2C devices. 162 */ 163static void iot_gate_imx8_detect_ext(void) 164{ 165 int ret; 166 struct udevice *i2c_bus, *i2c_dev; 167 168 ret = uclass_get_device_by_seq(UCLASS_I2C, IOT_GATE_IMX8_EXT_I2C, 169 &i2c_bus); 170 if (ret) { 171 printf("%s: Failed getting i2c device\n", __func__); 172 return; 173 } 174 175 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE, 0, 176 &i2c_dev); 177 if (!ret) { 178 iot_gate_imx8_ext_id = IOT_GATE_EXT_POE; 179 return; 180 } 181 182 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2, 0, 183 &i2c_dev); 184 if (!ret) { 185 iot_gate_imx8_ext_id = IOT_GATE_EXT_POEV2; 186 return; 187 } 188 189 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM, 0, 190 &i2c_dev); 191 if (ret){ 192 iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY; 193 return; 194 } 195 /* Only the bridge extension includes the GPIO extender */ 196 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO, 0, 197 &i2c_dev); 198 if (ret) /* GPIO extender not detected */ 199 iot_gate_imx8_ext_id = IOT_GATE_EXT_CAN; 200 else /* GPIO extender detected */ 201 iot_gate_imx8_ext_id = IOT_GATE_EXT_IED; 202} 203 204static iomux_v3_cfg_t const iot_gate_imx8_ext_ied_pads[] = { 205 IMX8MM_PAD_NAND_ALE_GPIO3_IO0 | MUX_PAD_CTRL(PAD_CTL_PE), 206 IMX8MM_PAD_NAND_CE0_B_GPIO3_IO1 | MUX_PAD_CTRL(PAD_CTL_PE), 207 IMX8MM_PAD_NAND_DATA00_GPIO3_IO6 | MUX_PAD_CTRL(PAD_CTL_PE), 208 IMX8MM_PAD_NAND_DATA01_GPIO3_IO7 | MUX_PAD_CTRL(PAD_CTL_PE), 209 IMX8MM_PAD_NAND_DATA02_GPIO3_IO8 | MUX_PAD_CTRL(PAD_CTL_PE), 210 IMX8MM_PAD_NAND_DATA03_GPIO3_IO9 | MUX_PAD_CTRL(PAD_CTL_PE), 211}; 212 213static iomux_v3_cfg_t const iot_gate_imx8_ext_poev2_pads[] = { 214 IMX8MM_PAD_SAI3_TXD_GPIO5_IO1 | MUX_PAD_CTRL(PAD_CTL_PE | 215 PAD_CTL_PUE), 216}; 217 218/* Extension board bridge GPIOs */ 219#define IOT_GATE_IMX8_GPIO_EXT_IED_I0 IMX_GPIO_NR(3, 0) /* IN 0 */ 220#define IOT_GATE_IMX8_GPIO_EXT_IED_I1 IMX_GPIO_NR(3, 1) /* IN 1 */ 221#define IOT_GATE_IMX8_GPIO_EXT_IED_I2 IMX_GPIO_NR(3, 6) /* IN 2 */ 222#define IOT_GATE_IMX8_GPIO_EXT_IED_I3 IMX_GPIO_NR(3, 7) /* IN 3 */ 223#define IOT_GATE_IMX8_GPIO_EXT_IED_O0 IMX_GPIO_NR(3, 8) /* OUT 0 */ 224#define IOT_GATE_IMX8_GPIO_EXT_IED_O1 IMX_GPIO_NR(3, 9) /* OUT 1 */ 225#define IOT_GATE_IMX8_GPIO_EXT_IED_O2 IMX_GPIO_NR(6, 9) /* OUT 2 */ 226#define IOT_GATE_IMX8_GPIO_EXT_IED_O3 IMX_GPIO_NR(6, 10)/* OUT 3 */ 227 228/* Extension board POE GPIOs */ 229#define IOT_GATE_IMX8_GPIO_EXT_POE_MUX IMX_GPIO_NR(5, 1)/* USB_MUX */ 230 231/* 232 * iot_gate_imx8_update_pinmux() - update the pinmux 233 * Update the pinmux according to the detected extended board. 234 */ 235static void iot_gate_imx8_update_pinmux(void) 236{ 237 if (iot_gate_imx8_ext_id == IOT_GATE_EXT_POEV2) { 238 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_poev2_pads, 239 ARRAY_SIZE(iot_gate_imx8_ext_poev2_pads)); 240 gpio_request(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, "poev2_usb-mux"); 241 /* Update USB MUX state */ 242 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, 1); 243 244 return; 245 } 246 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED) 247 return; 248 249 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_ied_pads, 250 ARRAY_SIZE(iot_gate_imx8_ext_ied_pads)); 251 252 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I0, "ied-di4o4_i0"); 253 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I0); 254 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I1, "ied-di4o4_i1"); 255 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I1); 256 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I2, "ied-di4o4_i2"); 257 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I2); 258 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I3, "ied-di4o4_i3"); 259 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I3); 260 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O0, "ied-di4o4_o0"); 261 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O0, 0); 262 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O1, "ied-di4o4_o1"); 263 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O1, 0); 264 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O2, "ied-di4o4_o2"); 265 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O2, 0); 266 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O3, "ied-di4o4_o3"); 267 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O3, 0); 268} 269 270#define IOT_GATE_IMX8_GPIO_S0B0 IMX_GPIO_NR(6, 0) /* Slot ID slot 0 bit 0 */ 271#define IOT_GATE_IMX8_GPIO_S0B1 IMX_GPIO_NR(6, 1) /* Slot ID slot 0 bit 1 */ 272#define IOT_GATE_IMX8_GPIO_S0B2 IMX_GPIO_NR(6, 2) /* Slot ID slot 0 bit 2 */ 273#define IOT_GATE_IMX8_GPIO_S1B0 IMX_GPIO_NR(6, 3) /* Slot ID slot 1 bit 0 */ 274#define IOT_GATE_IMX8_GPIO_S1B1 IMX_GPIO_NR(6, 4) /* Slot ID slot 1 bit 1 */ 275#define IOT_GATE_IMX8_GPIO_S1B2 IMX_GPIO_NR(6, 5) /* Slot ID slot 1 bit 2 */ 276#define IOT_GATE_IMX8_GPIO_S2B0 IMX_GPIO_NR(6, 6) /* Slot ID slot 2 bit 0 */ 277#define IOT_GATE_IMX8_GPIO_S2B1 IMX_GPIO_NR(6, 7) /* Slot ID slot 2 bit 1 */ 278#define IOT_GATE_IMX8_GPIO_S2B2 IMX_GPIO_NR(6, 8) /* Slot ID slot 2 bit 2 */ 279 280/* 281 * iot_gate_imx8_update_ext_ied() 282 * Update device tree of the extended board IED-BASE. 283 * The device tree is updated according to the detected sub modules. 284 * 285 * Return 0 for success, 1 for failure. 286 */ 287static int iot_gate_imx8_update_ext_ied(void) 288{ 289 int revision; 290 291 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED) 292 return 0; 293 294 /* ID GPIO initializations */ 295 if (gpio_request(IOT_GATE_IMX8_GPIO_S0B0, "id_s0b0") || 296 gpio_request(IOT_GATE_IMX8_GPIO_S0B1, "id_s0b1") || 297 gpio_request(IOT_GATE_IMX8_GPIO_S0B2, "id_s0b2") || 298 gpio_request(IOT_GATE_IMX8_GPIO_S1B0, "id_s1b0") || 299 gpio_request(IOT_GATE_IMX8_GPIO_S1B1, "id_s1b1") || 300 gpio_request(IOT_GATE_IMX8_GPIO_S1B2, "id_s1b2") || 301 gpio_request(IOT_GATE_IMX8_GPIO_S2B0, "id_s2b0") || 302 gpio_request(IOT_GATE_IMX8_GPIO_S2B1, "id_s2b1") || 303 gpio_request(IOT_GATE_IMX8_GPIO_S2B2, "id_s2b2")) { 304 printf("%s: ID GPIO request failure\n", __func__); 305 return 1; 306 } 307 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B0); 308 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B1); 309 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B2); 310 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B0); 311 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B1); 312 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B2); 313 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B0); 314 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B1); 315 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B2); 316 317 /* Get slot 0 card ID */ 318 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S0B0) | 319 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B1) << 1 | 320 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B2) << 2; 321 iot_gate_imx8_ext_ied_id[0] = revision; 322 323 /* Get slot 1 card ID */ 324 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S1B0) | 325 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B1) << 1 | 326 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B2) << 2; 327 iot_gate_imx8_ext_ied_id[1] = revision; 328 329 /* Get slot 2 card ID */ 330 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S2B0) | 331 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B1) << 1 | 332 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B2) << 2; 333 iot_gate_imx8_ext_ied_id[2] = revision; 334 335 return 0; 336} 337 338int extension_board_scan(struct list_head *extension_list) 339{ 340 struct extension *extension = NULL; 341 int i; 342 int ret = 0; 343 344 iot_gate_imx8_detect_ext(); /* Extended board detection */ 345 346 switch(iot_gate_imx8_ext_id) { 347 case IOT_GATE_EXT_EMPTY: 348 break; 349 case IOT_GATE_EXT_CAN: 350 extension = calloc(1, sizeof(struct extension)); 351 snprintf(extension->name, sizeof(extension->name), 352 "IOT_GATE_EXT_CAN"); 353 break; 354 case IOT_GATE_EXT_IED: 355 extension = calloc(1, sizeof(struct extension)); 356 snprintf(extension->name, sizeof(extension->name), 357 "IOT_GATE_EXT_IED"); 358 snprintf(extension->overlay, sizeof(extension->overlay), 359 "imx8mm-cl-iot-gate-ied.dtbo"); 360 break; 361 case IOT_GATE_EXT_POE: 362 extension = calloc(1, sizeof(struct extension)); 363 snprintf(extension->name, sizeof(extension->name), 364 "IOT_GATE_EXT_POE"); 365 break; 366 case IOT_GATE_EXT_POEV2: 367 extension = calloc(1, sizeof(struct extension)); 368 snprintf(extension->name, sizeof(extension->name), 369 "IOT_GATE_EXT_POEV2"); 370 break; 371 default: 372 printf("IOT_GATE-iMX8 extension board: unknown\n"); 373 break; 374 } 375 376 if (extension) { 377 snprintf(extension->owner, sizeof(extension->owner), 378 "Compulab"); 379 list_add_tail(&extension->list, extension_list); 380 ret = 1; 381 } else 382 return ret; 383 384 iot_gate_imx8_update_pinmux(); 385 386 iot_gate_imx8_update_ext_ied(); 387 for (i=0; i<ARRAY_SIZE(iot_gate_imx8_ext_ied_id); i++) { 388 extension = NULL; 389 switch (iot_gate_imx8_ext_ied_id[i]) { 390 case IOT_GATE_IMX8_CARD_ID_EMPTY: 391 break; 392 case IOT_GATE_IMX8_CARD_ID_RS_485: 393 extension = calloc(1, sizeof(struct extension)); 394 snprintf(extension->name, sizeof(extension->name), 395 "IOT_GATE_IMX8_CARD_ID_RS_485"); 396 break; 397 case IOT_GATE_IMX8_CARD_ID_RS_232: 398 extension = calloc(1, sizeof(struct extension)); 399 snprintf(extension->name, sizeof(extension->name), 400 "IOT_GATE_IMX8_CARD_ID_RS_232"); 401 break; 402 case IOT_GATE_IMX8_CARD_ID_CAN: 403 extension = calloc(1, sizeof(struct extension)); 404 snprintf(extension->name, sizeof(extension->name), 405 "IOT_GATE_IMX8_CARD_ID_CAN"); 406 snprintf(extension->overlay, sizeof(extension->overlay), 407 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i); 408 break; 409 case IOT_GATE_IMX8_CARD_ID_TPM: 410 extension = calloc(1, sizeof(struct extension)); 411 snprintf(extension->name, sizeof(extension->name), 412 "IOT_GATE_IMX8_CARD_ID_TPM"); 413 snprintf(extension->overlay, sizeof(extension->overlay), 414 "imx8mm-cl-iot-gate-ied-tpm%d.dtbo", i); 415 break; 416 case IOT_GATE_IMX8_CARD_ID_CL420: 417 extension = calloc(1, sizeof(struct extension)); 418 snprintf(extension->name, sizeof(extension->name), 419 "IOT_GATE_IMX8_CARD_ID_CL420"); 420 snprintf(extension->overlay, sizeof(extension->overlay), 421 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i); 422 break; 423 case IOT_GATE_IMX8_CARD_ID_DI4O4: 424 extension = calloc(1, sizeof(struct extension)); 425 snprintf(extension->name, sizeof(extension->name), 426 "IOT_GATE_IMX8_CARD_ID_DI4O4"); 427 break; 428 default: 429 printf("%s: invalid slot %d card ID: %d\n", 430 __func__, i, iot_gate_imx8_ext_ied_id[i]); 431 break; 432 } 433 if (extension) { 434 snprintf(extension->owner, sizeof(extension->owner), 435 "Compulab"); 436 snprintf(extension->other, sizeof(extension->other), 437 "On slot %d", i); 438 list_add_tail(&extension->list, extension_list); 439 ret = ret + 1; 440 } 441 } 442 443 return ret; 444} 445 446static int setup_mac_address(void) 447{ 448 unsigned char enetaddr[6]; 449 struct udevice *dev; 450 int ret, off; 451 452 ret = eth_env_get_enetaddr("ethaddr", enetaddr); 453 if (ret) 454 return 0; 455 456 off = fdt_path_offset(gd->fdt_blob, "eeprom1"); 457 if (off < 0) { 458 printf("No eeprom0 path offset found in DT\n"); 459 return off; 460 } 461 462 ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, off, &dev); 463 if (ret) { 464 printf("%s: Could not find EEPROM\n", __func__); 465 return ret; 466 } 467 468 ret = i2c_set_chip_offset_len(dev, 1); 469 if (ret) 470 return ret; 471 472 ret = i2c_eeprom_read(dev, 4, enetaddr, sizeof(enetaddr)); 473 if (ret) { 474 printf("%s: Could not read EEPROM\n", __func__); 475 return ret; 476 } 477 478 ret = is_valid_ethaddr(enetaddr); 479 if (!ret) 480 return -EINVAL; 481 482 ret = eth_env_set_enetaddr("ethaddr", enetaddr); 483 if (ret) 484 return ret; 485 486 return 0; 487} 488 489static int read_serial_number(void) 490{ 491 unsigned char serialnumber[6]; 492 unsigned char reversed[6]; 493 char serial_string[12]; 494 struct udevice *dev; 495 int ret, off, i; 496 497 off = fdt_path_offset(gd->fdt_blob, "eeprom0"); 498 if (off < 0) { 499 printf("No eeprom0 path offset found in DT\n"); 500 return off; 501 } 502 503 ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, off, &dev); 504 if (ret) { 505 printf("%s: Could not find EEPROM\n", __func__); 506 return ret; 507 } 508 509 ret = i2c_set_chip_offset_len(dev, 1); 510 if (ret) 511 return ret; 512 513 ret = i2c_eeprom_read(dev, 0x14, serialnumber, sizeof(serialnumber)); 514 if (ret) { 515 printf("%s: Could not read EEPROM\n", __func__); 516 return ret; 517 } 518 519 for (i = sizeof(serialnumber) - 1; i >= 0; i--) 520 reversed[i] = serialnumber[sizeof(serialnumber) - 1 - i]; 521 522 for (i = 0; i < sizeof(reversed); i++) { 523 serial_string[i * 2] = (reversed[i] >> 4) & 0xf; 524 serial_string[i * 2 + 1] = reversed[i] & 0xf; 525 } 526 527 for (i = 0; i < sizeof(serial_string); i++) 528 serial_string[i] += '0'; 529 530 env_set("serial#", serial_string); 531 532 return 0; 533} 534 535int board_late_init(void) 536{ 537 int ret; 538 539 if (IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)) { 540 env_set("board_name", "IOT-GATE-IMX8"); 541 env_set("board_rev", "SBC-IOTMX8"); 542 } 543 544 ret = setup_mac_address(); 545 if (ret < 0) 546 printf("Cannot set MAC address from EEPROM\n"); 547 548 ret = read_serial_number(); 549 if (ret < 0) 550 printf("Cannot read serial number from EEPROM\n"); 551 552 return 0; 553} 554