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