diff options
author | Calvin Johnson <calvin.johnson@nxp.com> | 2018-03-08 15:30:25 +0530 |
---|---|---|
committer | Joe Hershberger <joe.hershberger@ni.com> | 2018-03-22 15:05:28 -0500 |
commit | a4a40437496f3df28dffb3d7b63b9dae79ec0777 (patch) | |
tree | 869efbd91b6056c4704d3dc11d9e6350c9cc1034 /drivers/net/pfe_eth/pfe_firmware.c | |
parent | 6b1373f2452a26b0c48ba8797d28e8c005016caf (diff) | |
download | u-boot-a4a40437496f3df28dffb3d7b63b9dae79ec0777.tar.gz |
drivers: net: pfe_eth: LS1012A PFE driver introduction
This patch adds PFE driver to U-Boot
Following are the main driver files:-
pfe_hw.c: provides low level helper functions to initialize PFE
internal processor engines and other hardware blocks
pfe_driver.c: provides initialization functions
and packet send and receive functions
pfe_eth.c: provides high level gemac initialization functions
pfe_firmware.c: provides functions to load firmware into PFE
internal processor engines.
pfe_mdio.c: provides functions to initialize phy and mdio.
Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Diffstat (limited to 'drivers/net/pfe_eth/pfe_firmware.c')
-rw-r--r-- | drivers/net/pfe_eth/pfe_firmware.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c new file mode 100644 index 0000000000..9dc063dc75 --- /dev/null +++ b/drivers/net/pfe_eth/pfe_firmware.c @@ -0,0 +1,230 @@ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * @file + * Contains all the functions to handle parsing and loading of PE firmware + * files. + */ + +#include <net/pfe_eth/pfe_eth.h> +#include <net/pfe_eth/pfe_firmware.h> + +#define PFE_FIRMEWARE_FIT_CNF_NAME "config@1" + +static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR; + +/* + * PFE elf firmware loader. + * Loads an elf firmware image into a list of PE's (specified using a bitmask) + * + * @param pe_mask Mask of PE id's to load firmware to + * @param pfe_firmware Pointer to the firmware image + * + * @return 0 on success, a negative value on error + */ +static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware) +{ + Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware; + Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum); + Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware + + be32_to_cpu(elf_hdr->e_shoff)); + int id, section; + int ret; + + debug("%s: no of sections: %d\n", __func__, sections); + + /* Some sanity checks */ + if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) { + printf("%s: incorrect elf magic number\n", __func__); + return -1; + } + + if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) { + printf("%s: incorrect elf class(%x)\n", __func__, + elf_hdr->e_ident[EI_CLASS]); + return -1; + } + + if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) { + printf("%s: incorrect elf data(%x)\n", __func__, + elf_hdr->e_ident[EI_DATA]); + return -1; + } + + if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) { + printf("%s: incorrect elf file type(%x)\n", __func__, + be16_to_cpu(elf_hdr->e_type)); + return -1; + } + + for (section = 0; section < sections; section++, shdr++) { + if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC | + SHF_EXECINSTR))) + continue; + for (id = 0; id < MAX_PE; id++) + if (pe_mask & BIT(id)) { + ret = pe_load_elf_section(id, + pfe_firmware, shdr); + if (ret < 0) + goto err; + } + } + return 0; + +err: + return ret; +} + +/* + * Get PFE firmware from FIT image + * + * @param data pointer to PFE firmware + * @param size pointer to size of the firmware + * @param fw_name pfe firmware name, either class or tmu + * + * @return 0 on success, a negative value on error + */ +static int pfe_get_fw(const void **data, + size_t *size, char *fw_name) +{ + int conf_node_off, fw_node_off; + char *conf_node_name = NULL; + char *desc; + int ret = 0; + + conf_node_name = PFE_FIRMEWARE_FIT_CNF_NAME; + + conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name); + if (conf_node_off < 0) { + printf("PFE Firmware: %s: no such config\n", conf_node_name); + return -ENOENT; + } + + fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off, + fw_name); + if (fw_node_off < 0) { + printf("PFE Firmware: No '%s' in config\n", + fw_name); + return -ENOLINK; + } + + if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) { + printf("PFE Firmware: Bad firmware image (bad CRC)\n"); + return -EINVAL; + } + + if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) { + printf("PFE Firmware: Can't get %s subimage data/size", + fw_name); + return -ENOENT; + } + + ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc); + if (ret) + printf("PFE Firmware: Can't get description\n"); + else + printf("%s\n", desc); + + return ret; +} + +/* + * Check PFE FIT image + * + * @return 0 on success, a negative value on error + */ +static int pfe_fit_check(void) +{ + int ret = 0; + + ret = fdt_check_header(pfe_fit_addr); + if (ret) { + printf("PFE Firmware: Bad firmware image (not a FIT image)\n"); + return ret; + } + + if (!fit_check_format(pfe_fit_addr)) { + printf("PFE Firmware: Bad firmware image (bad FIT header)\n"); + ret = -1; + return ret; + } + + return ret; +} + +/* + * PFE firmware initialization. + * Loads different firmware files from FIT image. + * Initializes PE IMEM/DMEM and UTIL-PE DDR + * Initializes control path symbol addresses (by looking them up in the elf + * firmware files + * Takes PE's out of reset + * + * @return 0 on success, a negative value on error + */ +int pfe_firmware_init(void) +{ + char *pfe_firmware_name; + const void *raw_image_addr; + size_t raw_image_size = 0; + u8 *pfe_firmware; + int ret = 0; + int fw_count; + + ret = pfe_fit_check(); + if (ret) + goto err; + + for (fw_count = 0; fw_count < 2; fw_count++) { + if (fw_count == 0) + pfe_firmware_name = "class"; + else if (fw_count == 1) + pfe_firmware_name = "tmu"; + + pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name); + pfe_firmware = malloc(raw_image_size); + if (!pfe_firmware) + return -ENOMEM; + memcpy((void *)pfe_firmware, (void *)raw_image_addr, + raw_image_size); + + if (fw_count == 0) + ret = pfe_load_elf(CLASS_MASK, pfe_firmware); + else if (fw_count == 1) + ret = pfe_load_elf(TMU_MASK, pfe_firmware); + + if (ret < 0) { + printf("%s: %s firmware load failed\n", __func__, + pfe_firmware_name); + goto err; + } + debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name); + free(pfe_firmware); + } + + tmu_enable(0xb); + class_enable(); + gpi_enable(HGPI_BASE_ADDR); + +err: + return ret; +} + +/* + * PFE firmware cleanup + * Puts PE's in reset + */ +void pfe_firmware_exit(void) +{ + debug("%s\n", __func__); + + class_disable(); + tmu_disable(0xf); + hif_tx_disable(); + hif_rx_disable(); +} |