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