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 */
fdt_fixup_fman_firmware(void * blob)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