xref: /openbmc/u-boot/drivers/net/fm/fdt.c (revision baefb63a)
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