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