Read Linux PPFE firmware from flash partition and pass it to Linux through
FDT entry. So that we can avoid placing PPFE firmware in Linux rootfs.

Signed-off-by: Chaitanya Sakinam <chaitanya.saki...@nxp.com>
Signed-off-by: Anji J <anji.jagarlm...@nxp.com>
---
 arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 148 ++++++++++++++++++++++++++++++++
 drivers/net/pfe_eth/pfe_firmware.c      |  58 ++++++++++++-
 2 files changed, 205 insertions(+), 1 deletion(-)

diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c 
b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
index a1d5dc6..f874b1f 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
@@ -427,6 +427,151 @@ __weak void fdt_fixup_ecam(void *blob)
 }
 #endif
 
+#ifdef CONFIG_FSL_PFE
+void pfe_set_firmware_in_fdt(void *blob, int pfenode, void *pfw, char *pename,
+                            unsigned int len)
+{
+       int rc, fwnode;
+       unsigned int phandle;
+       char subnode_str[32], prop_str[32], phandle_str[32], s[64];
+
+       sprintf(subnode_str, "pfe-%s-firmware", pename);
+       sprintf(prop_str, "fsl,pfe-%s-firmware", pename);
+       sprintf(phandle_str, "fsl,%s-firmware", pename);
+
+       /*Add PE FW to fdt.*/
+       /* Increase the size of the fdt to make room for the node. */
+       rc = fdt_increase_size(blob, len);
+       if (rc < 0) {
+               printf("Unable to make room for %s firmware: %s\n", pename,
+                      fdt_strerror(rc));
+               return;
+       }
+
+       /* Create the firmware node. */
+       fwnode = fdt_add_subnode(blob, pfenode, subnode_str);
+       if (fwnode < 0) {
+               fdt_get_path(blob, pfenode, s, sizeof(s));
+               printf("Could not add firmware node to %s: %s\n", s,
+                      fdt_strerror(fwnode));
+               return;
+       }
+
+       rc = fdt_setprop_string(blob, fwnode, "compatible", prop_str);
+       if (rc < 0) {
+               fdt_get_path(blob, fwnode, s, sizeof(s));
+               printf("Could not add compatible property to node %s: %s\n", s,
+                      fdt_strerror(rc));
+               return;
+       }
+
+       rc = fdt_setprop_u32(blob, fwnode, "length", len);
+       if (rc < 0) {
+               fdt_get_path(blob, fwnode, s, sizeof(s));
+               printf("Could not add compatible property to node %s: %s\n", s,
+                      fdt_strerror(rc));
+               return;
+       }
+
+       /*create phandle and set the property*/
+       phandle = fdt_create_phandle(blob, fwnode);
+       if (!phandle) {
+               fdt_get_path(blob, fwnode, s, sizeof(s));
+               printf("Could not add phandle property to node %s: %s\n", s,
+                      fdt_strerror(rc));
+               return;
+       }
+
+       rc = fdt_setprop(blob, fwnode, phandle_str, pfw, len);
+       if (rc < 0) {
+               fdt_get_path(blob, fwnode, s, sizeof(s));
+               printf("Could not add firmware property to node %s: %s\n", s,
+                      fdt_strerror(rc));
+               return;
+       }
+}
+
+void fdt_fixup_pfe_firmware(void *blob)
+{
+       int pfenode;
+       unsigned int len_class = 0, len_tmu = 0, len_util = 0;
+       const char *p;
+       void *pclassfw, *ptmufw, *putilfw;
+
+       /* The first PFE we find, will contain the actual firmware. */
+       pfenode = fdt_node_offset_by_compatible(blob, -1, "fsl,pfe");
+       if (pfenode < 0)
+               /* Exit silently if there are no PFE devices */
+               return;
+
+       /* If we already have a firmware node, then also exit silently. */
+       if (fdt_node_offset_by_compatible(blob, -1,
+                                         "fsl,pfe-class-firmware") > 0)
+               return;
+
+       /* If the environment variable is not set, then exit silently */
+       p = env_get("class_elf_firmware");
+       if (!p)
+               return;
+
+       pclassfw = (void *)simple_strtoul(p, NULL, 16);
+       if (!pclassfw)
+               return;
+
+       p = env_get("class_elf_size");
+       if (!p)
+               return;
+       len_class = simple_strtoul(p, NULL, 16);
+
+       /* If the environment variable is not set, then exit silently */
+       p = env_get("tmu_elf_firmware");
+       if (!p)
+               return;
+
+       ptmufw = (void *)simple_strtoul(p, NULL, 16);
+       if (!ptmufw)
+               return;
+
+       p = env_get("tmu_elf_size");
+       if (!p)
+               return;
+       len_tmu = simple_strtoul(p, NULL, 16);
+
+       if (len_class == 0 || len_tmu == 0) {
+               printf("PFE FW corrupted. CLASS FW size %d, TMU FW size %d\n",
+                      len_class, len_tmu);
+               return;
+       }
+
+       /*Add CLASS FW to fdt.*/
+       pfe_set_firmware_in_fdt(blob, pfenode, pclassfw, "class", len_class);
+
+       /*Add TMU FW to fdt.*/
+       pfe_set_firmware_in_fdt(blob, pfenode, ptmufw, "tmu", len_tmu);
+
+       /* Util PE firmware is handled separately as it is not a usual case*/
+       p = env_get("util_elf_firmware");
+       if (!p)
+               return;
+
+       putilfw = (void *)simple_strtoul(p, NULL, 16);
+       if (!putilfw)
+               return;
+
+       p = env_get("util_elf_size");
+       if (!p)
+               return;
+       len_util = simple_strtoul(p, NULL, 16);
+
+       if (len_util) {
+               printf("PFE Util PE firmware is not added to FDT.\n");
+               return;
+       }
+
+       pfe_set_firmware_in_fdt(blob, pfenode, putilfw, "util", len_util);
+}
+#endif
+
 void ft_cpu_setup(void *blob, bd_t *bd)
 {
        struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
@@ -479,6 +624,9 @@ void ft_cpu_setup(void *blob, bd_t *bd)
 #ifdef CONFIG_SYS_DPAA_FMAN
        fdt_fixup_fman_firmware(blob);
 #endif
+#ifdef CONFIG_FSL_PFE
+       fdt_fixup_pfe_firmware(blob);
+#endif
 #ifndef CONFIG_ARCH_LS1012A
        fsl_fdt_disable_usb(blob);
 #endif
diff --git a/drivers/net/pfe_eth/pfe_firmware.c 
b/drivers/net/pfe_eth/pfe_firmware.c
index adb2d06..947e2cd 100644
--- a/drivers/net/pfe_eth/pfe_firmware.c
+++ b/drivers/net/pfe_eth/pfe_firmware.c
@@ -181,7 +181,8 @@ int pfe_firmware_init(void)
        uintptr_t pfe_img_addr = 0;
 #endif
        int ret = 0;
-       int fw_count;
+       int fw_count, max_fw_count;
+       const char *p;
 
        ret = pfe_fit_check();
        if (ret)
@@ -208,6 +209,61 @@ int pfe_firmware_init(void)
        }
 #endif
 
+       p = env_get("load_util");
+       if (!p) {
+               max_fw_count = 2;
+       } else {
+               max_fw_count = simple_strtoul(p, NULL, 10);
+               if (max_fw_count)
+                       max_fw_count = 3;
+               else
+                       max_fw_count = 2;
+       }
+
+       for (fw_count = 0; fw_count < max_fw_count; fw_count++) {
+               switch (fw_count) {
+               case 0:
+                       pfe_firmware_name = "class_slowpath";
+                       break;
+               case 1:
+                       pfe_firmware_name = "tmu_slowpath";
+                       break;
+               case 2:
+                       pfe_firmware_name = "util_slowpath";
+                       break;
+               }
+
+               if (pfe_get_fw(&raw_image_addr, &raw_image_size,
+                              pfe_firmware_name)) {
+                       printf("%s firmware couldn't be found in FIT image\n",
+                              pfe_firmware_name);
+                       break;
+               }
+               pfe_firmware = malloc(raw_image_size);
+               if (!pfe_firmware)
+                       return -ENOMEM;
+               memcpy((void *)pfe_firmware, (void *)raw_image_addr,
+                      raw_image_size);
+
+               switch (fw_count) {
+               case 0:
+                       env_set_addr("class_elf_firmware", pfe_firmware);
+                       env_set_addr("class_elf_size", (void *)raw_image_size);
+                       break;
+               case 1:
+                       env_set_addr("tmu_elf_firmware", pfe_firmware);
+                       env_set_addr("tmu_elf_size", (void *)raw_image_size);
+                       break;
+               case 2:
+                       env_set_addr("util_elf_firmware", pfe_firmware);
+                       env_set_addr("util_elf_size", (void *)raw_image_size);
+                       break;
+               }
+       }
+
+       raw_image_addr = NULL;
+       pfe_firmware = NULL;
+       raw_image_size = 0;
        for (fw_count = 0; fw_count < 2; fw_count++) {
                if (fw_count == 0)
                        pfe_firmware_name = "class";
-- 
2.7.4

Reply via email to