/* * Copyright 2021 NXP * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fuse_io.h" #include #include #include "plat_common.h" #include "platform_def.h" extern uintptr_t backend_dev_handle; static uint32_t fuse_fip; static uintptr_t fuse_fip_dev_handle; static io_block_spec_t fuse_fip_block_spec = { .offset = PLAT_FUSE_FIP_OFFSET, .length = PLAT_FUSE_FIP_MAX_SIZE }; static const io_uuid_spec_t fuse_prov_uuid_spec = { .uuid = UUID_FUSE_PROV, }; static const io_uuid_spec_t fuse_up_uuid_spec = { .uuid = UUID_FUSE_UP, }; static int open_fuse_fip(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; /* By default, ARM platforms load images from the FIP */ static const struct plat_io_policy fuse_policies[] = { [FUSE_FIP_IMAGE_ID - FUSE_FIP_IMAGE_ID] = { &backend_dev_handle, (uintptr_t)&fuse_fip_block_spec, NULL }, [FUSE_PROV_IMAGE_ID - FUSE_FIP_IMAGE_ID] = { &fuse_fip_dev_handle, (uintptr_t)&fuse_prov_uuid_spec, open_fuse_fip }, [FUSE_UP_IMAGE_ID - FUSE_FIP_IMAGE_ID] = { &fuse_fip_dev_handle, (uintptr_t)&fuse_up_uuid_spec, open_fuse_fip } }; static int open_fuse_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fuse_fip_dev_handle, (uintptr_t)FUSE_FIP_IMAGE_ID); if (result == 0) { result = io_open(fuse_fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } /* The image can be one of the DDR PHY images, which can be sleected via DDR * policies */ int plat_get_fuse_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec, int (*check)(const uintptr_t spec)) { int result; const struct plat_io_policy *policy; assert(image_id < (FUSE_FIP_IMAGE_ID + ARRAY_SIZE(fuse_policies))); policy = &fuse_policies[image_id - FUSE_FIP_IMAGE_ID]; if (image_id == FUSE_FIP_IMAGE_ID) { result = check(policy->image_spec); } else { result = policy->check(policy->image_spec); } if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } return result; } int fuse_fip_setup(const io_dev_connector_t *fip_dev_con, unsigned int boot_dev) { int io_result; size_t fuse_fip_offset = PLAT_FUSE_FIP_OFFSET; /* Open connections to fuse fip and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)&fuse_fip, &fuse_fip_dev_handle); assert(io_result == 0); switch (boot_dev) { #if QSPI_BOOT case BOOT_DEVICE_QSPI: fuse_fip_offset += NXP_QSPI_FLASH_ADDR; break; #endif #if NOR_BOOT case BOOT_DEVICE_IFC_NOR: fuse_fip_offset += NXP_NOR_FLASH_ADDR; break; #endif #if FLEXSPI_NOR_BOOT case BOOT_DEVICE_FLEXSPI_NOR: fuse_fip_offset += NXP_FLEXSPI_FLASH_ADDR; break; #endif default: break; } fuse_fip_block_spec.offset = fuse_fip_offset; return io_result; } int fip_fuse_provisioning(uintptr_t image_buf, uint32_t size) { uint32_t bit_num; uint32_t *gpio_base_addr = NULL; struct fuse_hdr_t *fuse_hdr = NULL; uint8_t barker[] = {0x68U, 0x39U, 0x27U, 0x81U}; int ret = -1; if (sfp_check_oem_wp() == 0) { ret = load_img(FUSE_PROV_IMAGE_ID, &image_buf, &size); if (ret != 0) { ERROR("Failed to load FUSE PRIV image\n"); assert(ret == 0); } fuse_hdr = (struct fuse_hdr_t *)image_buf; /* Check barker code */ if (memcmp(fuse_hdr->barker, barker, sizeof(barker)) != 0) { ERROR("FUSE Barker code mismatch.\n"); error_handler(ERROR_FUSE_BARKER); return 1; } /* Check if GPIO pin to be set for POVDD */ if (((fuse_hdr->flags >> FLAG_POVDD_SHIFT) & 0x1) != 0) { gpio_base_addr = select_gpio_n_bitnum(fuse_hdr->povdd_gpio, &bit_num); /* * Add delay so that Efuse gets the power * when GPIO is enabled. */ ret = set_gpio_bit(gpio_base_addr, bit_num); mdelay(EFUSE_POWERUP_DELAY_mSec); } else { ret = (board_enable_povdd() == true) ? 0 : PLAT_ERROR_ENABLE_POVDD; } if (ret != 0) { ERROR("Error enabling board POVDD: %d\n", ret); ERROR("Only SFP mirror register will be set.\n"); } provision_fuses(image_buf, ret == 0); /* Check if GPIO pin to be reset for POVDD */ if (((fuse_hdr->flags >> FLAG_POVDD_SHIFT) & 0x1) != 0) { if (gpio_base_addr == NULL) { gpio_base_addr = select_gpio_n_bitnum( fuse_hdr->povdd_gpio, &bit_num); } ret = clr_gpio_bit(gpio_base_addr, bit_num); } else { ret = board_disable_povdd() ? 0 : PLAT_ERROR_DISABLE_POVDD; } if (ret != 0) { ERROR("Error disabling board POVDD: %d\n", ret); } } return 0; }