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