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