summaryrefslogtreecommitdiff
path: root/drivers/net/pfe_eth/pfe_firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/pfe_eth/pfe_firmware.c')
-rw-r--r--drivers/net/pfe_eth/pfe_firmware.c230
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 0000000..4fc1522
--- /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 <pfe_eth/pfe_eth.h>
+#include <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 & (1 << 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;
+ uint8_t *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);
+ 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);
+#if !defined(CONFIG_UTIL_PE_DISABLED)
+ util_disable();
+#endif
+ hif_tx_disable();
+ hif_rx_disable();
+}