blob: 1db2a4a26750f641721a9d614552cffa2d15df5b [file] [log] [blame]
Suneel Garapatiaddfabc2019-10-19 18:37:55 -07001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 Marvell International Ltd.
4 *
5 * https://spdx.org/licenses
6 */
7
8#include <errno.h>
9#include <env.h>
10#include <log.h>
11#include <net.h>
12#include <asm/io.h>
13#include <linux/compiler.h>
14#include <linux/libfdt.h>
15#include <fdtdec.h>
16#include <fdt_support.h>
17#include <asm/arch/board.h>
18#include <asm/global_data.h>
19
20DECLARE_GLOBAL_DATA_PTR;
21
22static int fdt_get_mdio_bus(const void *fdt, int phy_offset)
23{
24 int node, bus = -1;
25 const u64 *reg;
26 u64 addr;
27
28 if (phy_offset < 0)
29 return -1;
30 /* obtain mdio node and get the reg prop */
31 node = fdt_parent_offset(fdt, phy_offset);
32 if (node < 0)
33 return -1;
34
35 reg = fdt_getprop(fdt, node, "reg", NULL);
36 addr = fdt64_to_cpu(*reg);
37 bus = (addr & (1 << 7)) ? 1 : 0;
38 return bus;
39}
40
41static int fdt_get_phy_addr(const void *fdt, int phy_offset)
42{
43 const u32 *reg;
44 int addr = -1;
45
46 if (phy_offset < 0)
47 return -1;
48 reg = fdt_getprop(fdt, phy_offset, "reg", NULL);
49 addr = fdt32_to_cpu(*reg);
50 return addr;
51}
52
53void fdt_parse_phy_info(void)
54{
55 const void *fdt = gd->fdt_blob;
56 int offset = 0, node, bgx_id = 0, lmacid = 0;
57 const u32 *val;
58 char bgxname[24];
59 int len, rgx_id = 0, eth_id = 0;
60 int phandle, phy_offset;
61 int subnode, i;
62 int bdknode;
63
64 bdknode = fdt_path_offset(fdt, "/cavium,bdk");
65 if (bdknode < 0) {
66 printf("%s: bdk node is missing from device tree: %s\n",
67 __func__, fdt_strerror(bdknode));
68 }
69
70 offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge");
71 if (offset < 1)
72 return;
73
74 for (bgx_id = 0; bgx_id < MAX_BGX_PER_NODE; bgx_id++) {
75 int phy_addr[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1};
76 bool autoneg_dis[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0};
77 int mdio_bus[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1};
78 bool lmac_reg[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0};
79 bool lmac_enable[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0};
80
81 snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx_id);
82 node = fdt_subnode_offset(fdt, offset, bgxname);
83 if (node < 0) {
84 /* check if it is rgx node */
85 snprintf(bgxname, sizeof(bgxname), "rgx%d", rgx_id);
86 node = fdt_subnode_offset(fdt, offset, bgxname);
87 if (node < 0) {
88 debug("bgx%d/rgx0 node not found\n", bgx_id);
89 return;
90 }
91 }
92 debug("bgx%d node found\n", bgx_id);
93
94 /*
95 * loop through each of the bgx/rgx nodes
96 * to find PHY nodes
97 */
98 fdt_for_each_subnode(subnode, fdt, node) {
99 /* Check for reg property */
100 val = fdt_getprop(fdt, subnode, "reg", &len);
101 if (val) {
102 debug("lmacid = %d\n", lmacid);
103 lmac_reg[lmacid] = 1;
104 }
105 /* check for phy-handle property */
106 val = fdt_getprop(fdt, subnode, "phy-handle", &len);
107 if (val) {
108 phandle = fdt32_to_cpu(*val);
109 if (!phandle) {
110 debug("phandle not valid %d\n", lmacid);
111 } else {
112 phy_offset = fdt_node_offset_by_phandle
113 (fdt, phandle);
114 phy_addr[lmacid] = fdt_get_phy_addr
115 (fdt, phy_offset);
116 mdio_bus[lmacid] = fdt_get_mdio_bus
117 (fdt, phy_offset);
118 }
119 } else {
120 debug("phy-handle prop not found %d\n",
121 lmacid);
122 }
123 /* check for autonegotiation property */
124 val = fdt_getprop(fdt, subnode,
125 "cavium,disable-autonegotiation",
126 &len);
127 if (val)
128 autoneg_dis[lmacid] = 1;
129
130 eth_id++;
131 lmacid++;
132 }
133
134 for (i = 0; i < MAX_LMAC_PER_BGX; i++) {
135 const char *str;
136
137 snprintf(bgxname, sizeof(bgxname),
138 "BGX-ENABLE.N0.BGX%d.P%d", bgx_id, i);
139 if (bdknode >= 0) {
140 str = fdt_getprop(fdt, bdknode,
141 bgxname, &len);
142 if (str)
143 lmac_enable[i] =
144 simple_strtol(str, NULL,
145 10);
146 }
147 }
148
149 lmacid = 0;
150 bgx_set_board_info(bgx_id, mdio_bus, phy_addr,
151 autoneg_dis, lmac_reg, lmac_enable);
152 }
153}
154
155static int fdt_get_bdk_node(void)
156{
157 int node, ret;
158 const void *fdt = gd->fdt_blob;
159
160 if (!fdt) {
161 printf("ERROR: %s: no valid device tree found\n", __func__);
162 return 0;
163 }
164
165 ret = fdt_check_header(fdt);
166 if (ret < 0) {
167 printf("fdt: %s\n", fdt_strerror(ret));
168 return 0;
169 }
170
171 node = fdt_path_offset(fdt, "/cavium,bdk");
172 if (node < 0) {
173 printf("%s: /cavium,bdk is missing from device tree: %s\n",
174 __func__, fdt_strerror(node));
175 return 0;
176 }
177 return node;
178}
179
180const char *fdt_get_board_serial(void)
181{
182 const void *fdt = gd->fdt_blob;
183 int node, len = 64;
184 const char *str = NULL;
185
186 node = fdt_get_bdk_node();
187 if (!node)
188 return NULL;
189
190 str = fdt_getprop(fdt, node, "BOARD-SERIAL", &len);
191 if (!str)
192 printf("Error: cannot retrieve board serial from fdt\n");
193 return str;
194}
195
196const char *fdt_get_board_revision(void)
197{
198 const void *fdt = gd->fdt_blob;
199 int node, len = 64;
200 const char *str = NULL;
201
202 node = fdt_get_bdk_node();
203 if (!node)
204 return NULL;
205
206 str = fdt_getprop(fdt, node, "BOARD-REVISION", &len);
207 if (!str)
208 printf("Error: cannot retrieve board revision from fdt\n");
209 return str;
210}
211
212const char *fdt_get_board_model(void)
213{
214 const void *fdt = gd->fdt_blob;
215 int node, len = 16;
216 const char *str = NULL;
217
218 node = fdt_get_bdk_node();
219 if (!node)
220 return NULL;
221
222 str = fdt_getprop(fdt, node, "BOARD-MODEL", &len);
223 if (!str)
224 printf("Error: cannot retrieve board model from fdt\n");
225 return str;
226}
227
228void fdt_board_get_ethaddr(int bgx, int lmac, unsigned char *eth)
229{
230 const void *fdt = gd->fdt_blob;
231 const char *mac = NULL;
232 int offset = 0, node, len;
233 int subnode, i = 0;
234 char bgxname[24];
235
236 offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge");
237 if (offset < 0) {
238 printf("%s couldn't find mrml bridge node in fdt\n",
239 __func__);
240 return;
241 }
242 if (bgx == 2 && otx_is_soc(CN81XX)) {
243 snprintf(bgxname, sizeof(bgxname), "rgx%d", 0);
244 lmac = 0;
245 } else {
246 snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx);
247 }
248
249 node = fdt_subnode_offset(fdt, offset, bgxname);
250
251 fdt_for_each_subnode(subnode, fdt, node) {
252 if (i++ != lmac)
253 continue;
254 /* check for local-mac-address */
255 mac = fdt_getprop(fdt, subnode, "local-mac-address", &len);
256 if (mac) {
257 debug("%s mac %pM\n", __func__, mac);
258 memcpy(eth, mac, ARP_HLEN);
259 } else {
260 memset(eth, 0, ARP_HLEN);
261 }
262 debug("%s eth %pM\n", __func__, eth);
263 return;
264 }
265}
266
267int arch_fixup_memory_node(void *blob)
268{
269 return 0;
270}
271
272int ft_board_setup(void *blob, struct bd_info *bd)
273{
274 /* remove "cavium, bdk" node from DT */
275 int ret = 0, offset;
276
277 ret = fdt_check_header(blob);
278 if (ret < 0) {
279 printf("ERROR: %s\n", fdt_strerror(ret));
280 return ret;
281 }
282
283 if (blob) {
Tim Harvey0ab73802021-06-17 16:31:07 -0700284 /* delete cavium,bdk node if it exists */
Suneel Garapatiaddfabc2019-10-19 18:37:55 -0700285 offset = fdt_path_offset(blob, "/cavium,bdk");
Tim Harvey0ab73802021-06-17 16:31:07 -0700286 if (offset >= 0) {
287 ret = fdt_del_node(blob, offset);
288 if (ret < 0) {
289 printf("WARNING : could not remove bdk node\n");
290 return ret;
291 }
292 debug("%s deleted bdk node\n", __func__);
Suneel Garapatiaddfabc2019-10-19 18:37:55 -0700293 }
Suneel Garapatiaddfabc2019-10-19 18:37:55 -0700294 }
295
296 return 0;
297}
298
299/**
300 * Return the FDT base address that was passed by ATF
301 *
302 * @return FDT base address received from ATF in x1 register
303 */
304void *board_fdt_blob_setup(void)
305{
306 return (void *)fdt_base_addr;
307}