xref: /rk3399_rockchip-uboot/drivers/net/fm/fdt.c (revision 00caae6d47645e68d6e5277aceb69592b49381a6)
1075affb1SQianyu Gong /*
2075affb1SQianyu Gong  * Copyright 2016 Freescale Semiconductor, Inc.
3075affb1SQianyu Gong  *
4075affb1SQianyu Gong  * SPDX-License-Identifier:	GPL-2.0+
5075affb1SQianyu Gong  */
6075affb1SQianyu Gong #include <asm/io.h>
7075affb1SQianyu Gong #include <fsl_qe.h>	/* For struct qe_firmware */
8075affb1SQianyu Gong 
9075affb1SQianyu Gong #ifdef CONFIG_SYS_DPAA_FMAN
10075affb1SQianyu Gong /**
11075affb1SQianyu Gong  * fdt_fixup_fman_firmware -- insert the Fman firmware into the device tree
12075affb1SQianyu Gong  *
13075affb1SQianyu Gong  * The binding for an Fman firmware node is documented in
14075affb1SQianyu Gong  * Documentation/powerpc/dts-bindings/fsl/dpaa/fman.txt.  This node contains
15075affb1SQianyu Gong  * the actual Fman firmware binary data.  The operating system is expected to
16075affb1SQianyu Gong  * be able to parse the binary data to determine any attributes it needs.
17075affb1SQianyu Gong  */
fdt_fixup_fman_firmware(void * blob)18075affb1SQianyu Gong void fdt_fixup_fman_firmware(void *blob)
19075affb1SQianyu Gong {
20075affb1SQianyu Gong 	int rc, fmnode, fwnode = -1;
21075affb1SQianyu Gong 	uint32_t phandle;
22075affb1SQianyu Gong 	struct qe_firmware *fmanfw;
23075affb1SQianyu Gong 	const struct qe_header *hdr;
24075affb1SQianyu Gong 	unsigned int length;
25075affb1SQianyu Gong 	uint32_t crc;
26075affb1SQianyu Gong 	const char *p;
27075affb1SQianyu Gong 
28075affb1SQianyu Gong 	/* The first Fman we find will contain the actual firmware. */
29075affb1SQianyu Gong 	fmnode = fdt_node_offset_by_compatible(blob, -1, "fsl,fman");
30075affb1SQianyu Gong 	if (fmnode < 0)
31075affb1SQianyu Gong 		/* Exit silently if there are no Fman devices */
32075affb1SQianyu Gong 		return;
33075affb1SQianyu Gong 
34075affb1SQianyu Gong 	/* If we already have a firmware node, then also exit silently. */
35075affb1SQianyu Gong 	if (fdt_node_offset_by_compatible(blob, -1, "fsl,fman-firmware") > 0)
36075affb1SQianyu Gong 		return;
37075affb1SQianyu Gong 
38075affb1SQianyu Gong 	/* If the environment variable is not set, then exit silently */
39*00caae6dSSimon Glass 	p = env_get("fman_ucode");
40075affb1SQianyu Gong 	if (!p)
41075affb1SQianyu Gong 		return;
42075affb1SQianyu Gong 
43075affb1SQianyu Gong 	fmanfw = (struct qe_firmware *)simple_strtoul(p, NULL, 16);
44075affb1SQianyu Gong 	if (!fmanfw)
45075affb1SQianyu Gong 		return;
46075affb1SQianyu Gong 
47075affb1SQianyu Gong 	hdr = &fmanfw->header;
486fc9535fSQianyu Gong 	length = fdt32_to_cpu(hdr->length);
49075affb1SQianyu Gong 
50075affb1SQianyu Gong 	/* Verify the firmware. */
51075affb1SQianyu Gong 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
52075affb1SQianyu Gong 	    (hdr->magic[2] != 'F')) {
53075affb1SQianyu Gong 		printf("Data at %p is not an Fman firmware\n", fmanfw);
54075affb1SQianyu Gong 		return;
55075affb1SQianyu Gong 	}
56075affb1SQianyu Gong 
57075affb1SQianyu Gong 	if (length > CONFIG_SYS_QE_FMAN_FW_LENGTH) {
58075affb1SQianyu Gong 		printf("Fman firmware at %p is too large (size=%u)\n",
59075affb1SQianyu Gong 		       fmanfw, length);
60075affb1SQianyu Gong 		return;
61075affb1SQianyu Gong 	}
62075affb1SQianyu Gong 
63075affb1SQianyu Gong 	length -= sizeof(u32);	/* Subtract the size of the CRC */
646fc9535fSQianyu Gong 	crc = fdt32_to_cpu(*(u32 *)((void *)fmanfw + length));
65075affb1SQianyu Gong 	if (crc != crc32_no_comp(0, (void *)fmanfw, length)) {
66075affb1SQianyu Gong 		printf("Fman firmware at %p has invalid CRC\n", fmanfw);
67075affb1SQianyu Gong 		return;
68075affb1SQianyu Gong 	}
69075affb1SQianyu Gong 
706fc9535fSQianyu Gong 	length += sizeof(u32);
716fc9535fSQianyu Gong 
72075affb1SQianyu Gong 	/* Increase the size of the fdt to make room for the node. */
736fc9535fSQianyu Gong 	rc = fdt_increase_size(blob, length);
74075affb1SQianyu Gong 	if (rc < 0) {
75075affb1SQianyu Gong 		printf("Unable to make room for Fman firmware: %s\n",
76075affb1SQianyu Gong 		       fdt_strerror(rc));
77075affb1SQianyu Gong 		return;
78075affb1SQianyu Gong 	}
79075affb1SQianyu Gong 
80075affb1SQianyu Gong 	/* Create the firmware node. */
81075affb1SQianyu Gong 	fwnode = fdt_add_subnode(blob, fmnode, "fman-firmware");
82075affb1SQianyu Gong 	if (fwnode < 0) {
83075affb1SQianyu Gong 		char s[64];
84075affb1SQianyu Gong 		fdt_get_path(blob, fmnode, s, sizeof(s));
85075affb1SQianyu Gong 		printf("Could not add firmware node to %s: %s\n", s,
86075affb1SQianyu Gong 		       fdt_strerror(fwnode));
87075affb1SQianyu Gong 		return;
88075affb1SQianyu Gong 	}
89075affb1SQianyu Gong 	rc = fdt_setprop_string(blob, fwnode, "compatible",
90075affb1SQianyu Gong 					"fsl,fman-firmware");
91075affb1SQianyu Gong 	if (rc < 0) {
92075affb1SQianyu Gong 		char s[64];
93075affb1SQianyu Gong 		fdt_get_path(blob, fwnode, s, sizeof(s));
94075affb1SQianyu Gong 		printf("Could not add compatible property to node %s: %s\n", s,
95075affb1SQianyu Gong 		       fdt_strerror(rc));
96075affb1SQianyu Gong 		return;
97075affb1SQianyu Gong 	}
98075affb1SQianyu Gong 	phandle = fdt_create_phandle(blob, fwnode);
99075affb1SQianyu Gong 	if (!phandle) {
100075affb1SQianyu Gong 		char s[64];
101075affb1SQianyu Gong 		fdt_get_path(blob, fwnode, s, sizeof(s));
102075affb1SQianyu Gong 		printf("Could not add phandle property to node %s: %s\n", s,
103075affb1SQianyu Gong 		       fdt_strerror(rc));
104075affb1SQianyu Gong 		return;
105075affb1SQianyu Gong 	}
1066fc9535fSQianyu Gong 	rc = fdt_setprop(blob, fwnode, "fsl,firmware", fmanfw, length);
107075affb1SQianyu Gong 	if (rc < 0) {
108075affb1SQianyu Gong 		char s[64];
109075affb1SQianyu Gong 		fdt_get_path(blob, fwnode, s, sizeof(s));
110075affb1SQianyu Gong 		printf("Could not add firmware property to node %s: %s\n", s,
111075affb1SQianyu Gong 		       fdt_strerror(rc));
112075affb1SQianyu Gong 		return;
113075affb1SQianyu Gong 	}
114075affb1SQianyu Gong 
115075affb1SQianyu Gong 	/* Find all other Fman nodes and point them to the firmware node. */
116075affb1SQianyu Gong 	while ((fmnode = fdt_node_offset_by_compatible(blob, fmnode,
117075affb1SQianyu Gong 		"fsl,fman")) > 0) {
118075affb1SQianyu Gong 		rc = fdt_setprop_cell(blob, fmnode, "fsl,firmware-phandle",
119075affb1SQianyu Gong 				      phandle);
120075affb1SQianyu Gong 		if (rc < 0) {
121075affb1SQianyu Gong 			char s[64];
122075affb1SQianyu Gong 			fdt_get_path(blob, fmnode, s, sizeof(s));
123075affb1SQianyu Gong 			printf("Could not add pointer property to node %s: %s\n",
124075affb1SQianyu Gong 			       s, fdt_strerror(rc));
125075affb1SQianyu Gong 			return;
126075affb1SQianyu Gong 		}
127075affb1SQianyu Gong 	}
128075affb1SQianyu Gong }
129075affb1SQianyu Gong #endif
130