1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2016 Freescale Semiconductor, Inc. 4 */ 5 #include <asm/io.h> 6 #include <fsl_qe.h> /* For struct qe_firmware */ 7 8 #ifdef CONFIG_SYS_DPAA_FMAN 9 /** 10 * fdt_fixup_fman_firmware -- insert the Fman firmware into the device tree 11 * 12 * The binding for an Fman firmware node is documented in 13 * Documentation/powerpc/dts-bindings/fsl/dpaa/fman.txt. This node contains 14 * the actual Fman firmware binary data. The operating system is expected to 15 * be able to parse the binary data to determine any attributes it needs. 16 */ 17 void fdt_fixup_fman_firmware(void *blob) 18 { 19 int rc, fmnode, fwnode = -1; 20 uint32_t phandle; 21 struct qe_firmware *fmanfw; 22 const struct qe_header *hdr; 23 unsigned int length; 24 uint32_t crc; 25 const char *p; 26 27 /* The first Fman we find will contain the actual firmware. */ 28 fmnode = fdt_node_offset_by_compatible(blob, -1, "fsl,fman"); 29 if (fmnode < 0) 30 /* Exit silently if there are no Fman devices */ 31 return; 32 33 /* If we already have a firmware node, then also exit silently. */ 34 if (fdt_node_offset_by_compatible(blob, -1, "fsl,fman-firmware") > 0) 35 return; 36 37 /* If the environment variable is not set, then exit silently */ 38 p = env_get("fman_ucode"); 39 if (!p) 40 return; 41 42 fmanfw = (struct qe_firmware *)simple_strtoul(p, NULL, 16); 43 if (!fmanfw) 44 return; 45 46 hdr = &fmanfw->header; 47 length = fdt32_to_cpu(hdr->length); 48 49 /* Verify the firmware. */ 50 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 51 (hdr->magic[2] != 'F')) { 52 printf("Data at %p is not an Fman firmware\n", fmanfw); 53 return; 54 } 55 56 if (length > CONFIG_SYS_QE_FMAN_FW_LENGTH) { 57 printf("Fman firmware at %p is too large (size=%u)\n", 58 fmanfw, length); 59 return; 60 } 61 62 length -= sizeof(u32); /* Subtract the size of the CRC */ 63 crc = fdt32_to_cpu(*(u32 *)((void *)fmanfw + length)); 64 if (crc != crc32_no_comp(0, (void *)fmanfw, length)) { 65 printf("Fman firmware at %p has invalid CRC\n", fmanfw); 66 return; 67 } 68 69 length += sizeof(u32); 70 71 /* Increase the size of the fdt to make room for the node. */ 72 rc = fdt_increase_size(blob, length); 73 if (rc < 0) { 74 printf("Unable to make room for Fman firmware: %s\n", 75 fdt_strerror(rc)); 76 return; 77 } 78 79 /* Create the firmware node. */ 80 fwnode = fdt_add_subnode(blob, fmnode, "fman-firmware"); 81 if (fwnode < 0) { 82 char s[64]; 83 fdt_get_path(blob, fmnode, s, sizeof(s)); 84 printf("Could not add firmware node to %s: %s\n", s, 85 fdt_strerror(fwnode)); 86 return; 87 } 88 rc = fdt_setprop_string(blob, fwnode, "compatible", 89 "fsl,fman-firmware"); 90 if (rc < 0) { 91 char s[64]; 92 fdt_get_path(blob, fwnode, s, sizeof(s)); 93 printf("Could not add compatible property to node %s: %s\n", s, 94 fdt_strerror(rc)); 95 return; 96 } 97 phandle = fdt_create_phandle(blob, fwnode); 98 if (!phandle) { 99 char s[64]; 100 fdt_get_path(blob, fwnode, s, sizeof(s)); 101 printf("Could not add phandle property to node %s: %s\n", s, 102 fdt_strerror(rc)); 103 return; 104 } 105 rc = fdt_setprop(blob, fwnode, "fsl,firmware", fmanfw, length); 106 if (rc < 0) { 107 char s[64]; 108 fdt_get_path(blob, fwnode, s, sizeof(s)); 109 printf("Could not add firmware property to node %s: %s\n", s, 110 fdt_strerror(rc)); 111 return; 112 } 113 114 /* Find all other Fman nodes and point them to the firmware node. */ 115 while ((fmnode = fdt_node_offset_by_compatible(blob, fmnode, 116 "fsl,fman")) > 0) { 117 rc = fdt_setprop_cell(blob, fmnode, "fsl,firmware-phandle", 118 phandle); 119 if (rc < 0) { 120 char s[64]; 121 fdt_get_path(blob, fmnode, s, sizeof(s)); 122 printf("Could not add pointer property to node %s: %s\n", 123 s, fdt_strerror(rc)); 124 return; 125 } 126 } 127 } 128 #endif 129