blob: 9918d8089a1fa993776ebcb14b849657fe922d98 [file] [log] [blame]
Qianyu Gong075affb2016-02-18 13:02:00 +08001/*
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 */
18void 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 = getenv("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;
Qianyu Gong6fc95352016-02-18 13:02:01 +080048 length = fdt32_to_cpu(hdr->length);
Qianyu Gong075affb2016-02-18 13:02:00 +080049
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 */
Qianyu Gong6fc95352016-02-18 13:02:01 +080064 crc = fdt32_to_cpu(*(u32 *)((void *)fmanfw + length));
Qianyu Gong075affb2016-02-18 13:02:00 +080065 if (crc != crc32_no_comp(0, (void *)fmanfw, length)) {
66 printf("Fman firmware at %p has invalid CRC\n", fmanfw);
67 return;
68 }
69
Qianyu Gong6fc95352016-02-18 13:02:01 +080070 length += sizeof(u32);
71
Qianyu Gong075affb2016-02-18 13:02:00 +080072 /* Increase the size of the fdt to make room for the node. */
Qianyu Gong6fc95352016-02-18 13:02:01 +080073 rc = fdt_increase_size(blob, length);
Qianyu Gong075affb2016-02-18 13:02:00 +080074 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 }
Qianyu Gong6fc95352016-02-18 13:02:01 +0800106 rc = fdt_setprop(blob, fwnode, "fsl,firmware", fmanfw, length);
Qianyu Gong075affb2016-02-18 13:02:00 +0800107 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