uboot/drivers/net/pfe_eth/pfe_firmware.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
   4 * Copyright 2017 NXP
   5 */
   6
   7/*
   8 * @file
   9 *  Contains all the functions to handle parsing and loading of PE firmware
  10 * files.
  11 */
  12
  13#include <net/pfe_eth/pfe_eth.h>
  14#include <net/pfe_eth/pfe_firmware.h>
  15#ifdef CONFIG_CHAIN_OF_TRUST
  16#include <fsl_validate.h>
  17#endif
  18
  19#define PFE_FIRMEWARE_FIT_CNF_NAME      "config@1"
  20
  21static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR;
  22
  23/*
  24 * PFE elf firmware loader.
  25 * Loads an elf firmware image into a list of PE's (specified using a bitmask)
  26 *
  27 * @param pe_mask       Mask of PE id's to load firmware to
  28 * @param pfe_firmware  Pointer to the firmware image
  29 *
  30 * @return              0 on success, a negative value on error
  31 */
  32static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
  33{
  34        Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
  35        Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
  36        Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
  37                                                be32_to_cpu(elf_hdr->e_shoff));
  38        int id, section;
  39        int ret;
  40
  41        debug("%s: no of sections: %d\n", __func__, sections);
  42
  43        /* Some sanity checks */
  44        if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
  45                printf("%s: incorrect elf magic number\n", __func__);
  46                return -1;
  47        }
  48
  49        if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
  50                printf("%s: incorrect elf class(%x)\n", __func__,
  51                       elf_hdr->e_ident[EI_CLASS]);
  52                return -1;
  53        }
  54
  55        if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
  56                printf("%s: incorrect elf data(%x)\n", __func__,
  57                       elf_hdr->e_ident[EI_DATA]);
  58                return -1;
  59        }
  60
  61        if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
  62                printf("%s: incorrect elf file type(%x)\n", __func__,
  63                       be16_to_cpu(elf_hdr->e_type));
  64                return -1;
  65        }
  66
  67        for (section = 0; section < sections; section++, shdr++) {
  68                if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
  69                        SHF_EXECINSTR)))
  70                        continue;
  71                for (id = 0; id < MAX_PE; id++)
  72                        if (pe_mask & BIT(id)) {
  73                                ret = pe_load_elf_section(id,
  74                                                          pfe_firmware, shdr);
  75                                if (ret < 0)
  76                                        goto err;
  77                        }
  78        }
  79        return 0;
  80
  81err:
  82        return ret;
  83}
  84
  85/*
  86 * Get PFE firmware from FIT image
  87 *
  88 * @param data pointer to PFE firmware
  89 * @param size pointer to size of the firmware
  90 * @param fw_name pfe firmware name, either class or tmu
  91 *
  92 * @return 0 on success, a negative value on error
  93 */
  94static int pfe_get_fw(const void **data,
  95                      size_t *size, char *fw_name)
  96{
  97        int conf_node_off, fw_node_off;
  98        char *conf_node_name = NULL;
  99        char *desc;
 100        int ret = 0;
 101
 102        conf_node_name = PFE_FIRMEWARE_FIT_CNF_NAME;
 103
 104        conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
 105        if (conf_node_off < 0) {
 106                printf("PFE Firmware: %s: no such config\n", conf_node_name);
 107                return -ENOENT;
 108        }
 109
 110        fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
 111                                             fw_name);
 112        if (fw_node_off < 0) {
 113                printf("PFE Firmware: No '%s' in config\n",
 114                       fw_name);
 115                return -ENOLINK;
 116        }
 117
 118        if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
 119                printf("PFE Firmware: Bad firmware image (bad CRC)\n");
 120                return -EINVAL;
 121        }
 122
 123        if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
 124                printf("PFE Firmware: Can't get %s subimage data/size",
 125                       fw_name);
 126                return -ENOENT;
 127        }
 128
 129        ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
 130        if (ret)
 131                printf("PFE Firmware: Can't get description\n");
 132        else
 133                printf("%s\n", desc);
 134
 135        return ret;
 136}
 137
 138/*
 139 * Check PFE FIT image
 140 *
 141 * @return 0 on success, a negative value on error
 142 */
 143static int pfe_fit_check(void)
 144{
 145        int ret = 0;
 146
 147        ret = fdt_check_header(pfe_fit_addr);
 148        if (ret) {
 149                printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
 150                return ret;
 151        }
 152
 153        if (!fit_check_format(pfe_fit_addr)) {
 154                printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
 155                ret = -1;
 156                return ret;
 157        }
 158
 159        return ret;
 160}
 161
 162/*
 163 * PFE firmware initialization.
 164 * Loads different firmware files from FIT image.
 165 * Initializes PE IMEM/DMEM and UTIL-PE DDR
 166 * Initializes control path symbol addresses (by looking them up in the elf
 167 * firmware files
 168 * Takes PE's out of reset
 169 *
 170 * @return 0 on success, a negative value on error
 171 */
 172int pfe_firmware_init(void)
 173{
 174#define PFE_KEY_HASH    NULL
 175        char *pfe_firmware_name;
 176        const void *raw_image_addr;
 177        size_t raw_image_size = 0;
 178        u8 *pfe_firmware;
 179#ifdef CONFIG_CHAIN_OF_TRUST
 180        uintptr_t pfe_esbc_hdr = 0;
 181        uintptr_t pfe_img_addr = 0;
 182#endif
 183        int ret = 0;
 184        int fw_count;
 185
 186        ret = pfe_fit_check();
 187        if (ret)
 188                goto err;
 189
 190#ifdef CONFIG_CHAIN_OF_TRUST
 191        pfe_esbc_hdr = CONFIG_SYS_LS_PFE_ESBC_ADDR;
 192        pfe_img_addr = (uintptr_t)pfe_fit_addr;
 193        if (fsl_check_boot_mode_secure() != 0) {
 194                /*
 195                 * In case of failure in validation, fsl_secboot_validate
 196                 * would not return back in case of Production environment
 197                 * with ITS=1. In Development environment (ITS=0 and
 198                 * SB_EN=1), the function may return back in case of
 199                 * non-fatal failures.
 200                 */
 201                ret = fsl_secboot_validate(pfe_esbc_hdr,
 202                                           PFE_KEY_HASH,
 203                                           &pfe_img_addr);
 204                if (ret != 0)
 205                        printf("PFE firmware(s) validation failed\n");
 206                else
 207                        printf("PFE firmware(s) validation Successful\n");
 208        }
 209#endif
 210
 211        for (fw_count = 0; fw_count < 2; fw_count++) {
 212                if (fw_count == 0)
 213                        pfe_firmware_name = "class";
 214                else if (fw_count == 1)
 215                        pfe_firmware_name = "tmu";
 216
 217                pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
 218                pfe_firmware = malloc(raw_image_size);
 219                if (!pfe_firmware)
 220                        return -ENOMEM;
 221                memcpy((void *)pfe_firmware, (void *)raw_image_addr,
 222                       raw_image_size);
 223
 224                if (fw_count == 0)
 225                        ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
 226                else if (fw_count == 1)
 227                        ret = pfe_load_elf(TMU_MASK, pfe_firmware);
 228
 229                if (ret < 0) {
 230                        printf("%s: %s firmware load failed\n", __func__,
 231                               pfe_firmware_name);
 232                        goto err;
 233                }
 234                debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
 235                free(pfe_firmware);
 236        }
 237
 238        tmu_enable(0xb);
 239        class_enable();
 240        gpi_enable(HGPI_BASE_ADDR);
 241
 242err:
 243        return ret;
 244}
 245
 246/*
 247 * PFE firmware cleanup
 248 * Puts PE's in reset
 249 */
 250void pfe_firmware_exit(void)
 251{
 252        debug("%s\n", __func__);
 253
 254        class_disable();
 255        tmu_disable(0xf);
 256        hif_tx_disable();
 257        hif_rx_disable();
 258}
 259