blob: 9828753412b8acbb83530ef92268833d67d15139 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Qianyu Gong8868a642016-02-18 13:02:00 +08002/*
3 * Copyright 2016 Freescale Semiconductor, Inc.
Qianyu Gong8868a642016-02-18 13:02:00 +08004 */
5#include <asm/io.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -06006#include <env.h>
Simon Glass2dc9c342020-05-10 11:40:01 -06007#include <fdt_support.h>
Qianyu Gong8868a642016-02-18 13:02:00 +08008#include <fsl_qe.h> /* For struct qe_firmware */
Simon Glass48b6c6b2019-11-14 12:57:16 -07009#include <u-boot/crc.h>
Qianyu Gong8868a642016-02-18 13:02:00 +080010
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 */
20void 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 */
Simon Glass64b723f2017-08-03 12:22:12 -060041 p = env_get("fman_ucode");
Qianyu Gong8868a642016-02-18 13:02:00 +080042 if (!p)
43 return;
44
Simon Glass3ff49ec2021-07-24 09:03:29 -060045 fmanfw = (struct qe_firmware *)hextoul(p, NULL);
Qianyu Gong8868a642016-02-18 13:02:00 +080046 if (!fmanfw)
47 return;
48
49 hdr = &fmanfw->header;
Qianyu Gong0f331d82016-02-18 13:02:01 +080050 length = fdt32_to_cpu(hdr->length);
Qianyu Gong8868a642016-02-18 13:02:00 +080051
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 */
Qianyu Gong0f331d82016-02-18 13:02:01 +080066 crc = fdt32_to_cpu(*(u32 *)((void *)fmanfw + length));
Qianyu Gong8868a642016-02-18 13:02:00 +080067 if (crc != crc32_no_comp(0, (void *)fmanfw, length)) {
68 printf("Fman firmware at %p has invalid CRC\n", fmanfw);
69 return;
70 }
71
Qianyu Gong0f331d82016-02-18 13:02:01 +080072 length += sizeof(u32);
73
Qianyu Gong8868a642016-02-18 13:02:00 +080074 /* Increase the size of the fdt to make room for the node. */
Qianyu Gong0f331d82016-02-18 13:02:01 +080075 rc = fdt_increase_size(blob, length);
Qianyu Gong8868a642016-02-18 13:02:00 +080076 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 }
Qianyu Gong0f331d82016-02-18 13:02:01 +0800108 rc = fdt_setprop(blob, fwnode, "fsl,firmware", fmanfw, length);
Qianyu Gong8868a642016-02-18 13:02:00 +0800109 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. */
Marek BehĂșn5d6b4482022-01-20 01:04:42 +0100118 fdt_for_each_node_by_compatible(fmnode, blob, fmnode, "fsl,fman") {
Qianyu Gong8868a642016-02-18 13:02:00 +0800119 rc = fdt_setprop_cell(blob, fmnode, "fsl,firmware-phandle",
120 phandle);
121 if (rc < 0) {
122 char s[64];
123 fdt_get_path(blob, fmnode, s, sizeof(s));
124 printf("Could not add pointer property to node %s: %s\n",
125 s, fdt_strerror(rc));
126 return;
127 }
128 }
129}
130#endif