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