1// 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 <fdtdec.h>
10#include <fdt_support.h>
11#include <log.h>
12
13#include <linux/compiler.h>
14#include <linux/libfdt.h>
15
16#include <asm/arch/board.h>
17#include <asm/arch/smc.h>
18#include <asm/global_data.h>
19#include <asm/io.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
23static int fdt_get_bdk_node(void)
24{
25	int node, ret;
26	const void *fdt = gd->fdt_blob;
27
28	if (!fdt) {
29		printf("ERROR: %s: no valid device tree found\n", __func__);
30		return 0;
31	}
32
33	ret = fdt_check_header(fdt);
34	if (ret < 0) {
35		printf("fdt: %s\n", fdt_strerror(ret));
36		return 0;
37	}
38
39	node = fdt_path_offset(fdt, "/cavium,bdk");
40	if (node < 0) {
41		printf("%s: /cavium,bdk is missing from device tree: %s\n",
42		       __func__, fdt_strerror(node));
43		return 0;
44	}
45	return node;
46}
47
48u64 fdt_get_board_mac_addr(void)
49{
50	int node, len = 16;
51	const char *str = NULL;
52	const void *fdt = gd->fdt_blob;
53	u64 mac_addr = 0;
54
55	node = fdt_get_bdk_node();
56	if (!node)
57		return mac_addr;
58	str = fdt_getprop(fdt, node, "BOARD-MAC-ADDRESS", &len);
59	if (str)
60		mac_addr = simple_strtol(str, NULL, 16);
61	return mac_addr;
62}
63
64int fdt_get_board_mac_cnt(void)
65{
66	int node, len = 16;
67	const char *str = NULL;
68	const void *fdt = gd->fdt_blob;
69	int mac_count = 0;
70
71	node = fdt_get_bdk_node();
72	if (!node)
73		return mac_count;
74	str = fdt_getprop(fdt, node, "BOARD-MAC-ADDRESS-NUM", &len);
75	if (str) {
76		mac_count = simple_strtol(str, NULL, 10);
77		if (!mac_count)
78			mac_count = simple_strtol(str, NULL, 16);
79		debug("fdt: MAC_NUM %d\n", mac_count);
80	} else {
81		printf("Error: cannot retrieve mac count prop from fdt\n");
82	}
83	str = fdt_getprop(gd->fdt_blob, node, "BOARD-MAC-ADDRESS-NUM-OVERRIDE",
84			  &len);
85	if (str) {
86		if (simple_strtol(str, NULL, 10) >= 0)
87			mac_count = simple_strtol(str, NULL, 10);
88		debug("fdt: MAC_NUM %d\n", mac_count);
89	} else {
90		printf("Error: cannot retrieve mac num override prop\n");
91	}
92	return mac_count;
93}
94
95const char *fdt_get_board_serial(void)
96{
97	const void *fdt = gd->fdt_blob;
98	int node, len = 64;
99	const char *str = NULL;
100
101	node = fdt_get_bdk_node();
102	if (!node)
103		return NULL;
104
105	str = fdt_getprop(fdt, node, "BOARD-SERIAL", &len);
106	if (!str)
107		printf("Error: cannot retrieve board serial from fdt\n");
108	return str;
109}
110
111const char *fdt_get_board_revision(void)
112{
113	const void *fdt = gd->fdt_blob;
114	int node, len = 64;
115	const char *str = NULL;
116
117	node = fdt_get_bdk_node();
118	if (!node)
119		return NULL;
120
121	str = fdt_getprop(fdt, node, "BOARD-REVISION", &len);
122	if (!str)
123		printf("Error: cannot retrieve board revision from fdt\n");
124	return str;
125}
126
127const char *fdt_get_board_model(void)
128{
129	int node, len = 16;
130	const char *str = NULL;
131	const void *fdt = gd->fdt_blob;
132
133	node = fdt_get_bdk_node();
134	if (!node)
135		return NULL;
136	str = fdt_getprop(fdt, node, "BOARD-MODEL", &len);
137	if (!str)
138		printf("Error: cannot retrieve board model from fdt\n");
139	return str;
140}
141
142int arch_fixup_memory_node(void *blob)
143{
144	return 0;
145}
146
147int ft_board_setup(void *blob, struct bd_info *bd)
148{
149	int nodeoff, node, ret, i;
150	const char *temp;
151
152	static const char * const
153		octeontx_brd_nodes[] = {"BOARD-MODEL",
154					"BOARD-SERIAL",
155					"BOARD-MAC-ADDRESS",
156					"BOARD-REVISION",
157					"BOARD-MAC-ADDRESS-NUM"
158					};
159	char nodes[ARRAY_SIZE(octeontx_brd_nodes)][32];
160
161	ret = fdt_check_header(blob);
162	if (ret < 0) {
163		printf("ERROR: %s\n", fdt_strerror(ret));
164		return ret;
165	}
166
167	if (blob) {
168		nodeoff = fdt_path_offset(blob, "/cavium,bdk");
169		if (nodeoff < 0) {
170			printf("ERROR: FDT BDK node not found\n");
171			return nodeoff;
172		}
173
174		/* Read properties in temporary variables */
175		for (i = 0; i < ARRAY_SIZE(octeontx_brd_nodes); i++) {
176			temp = fdt_getprop(blob, nodeoff,
177					   octeontx_brd_nodes[i], NULL);
178			strncpy(nodes[i], temp, sizeof(nodes[i]));
179		}
180
181		/* Delete cavium,bdk node */
182		ret = fdt_del_node(blob, nodeoff);
183		if (ret < 0) {
184			printf("WARNING : could not remove cavium, bdk node\n");
185			return ret;
186		}
187		debug("%s deleted 'cavium,bdk' node\n", __func__);
188		/*
189		 * Add a new node at root level which would have
190		 * necessary info
191		 */
192		node = fdt_add_subnode(blob, 0, "octeontx_brd");
193		if (node < 0) {
194			printf("Cannot create node octeontx_brd: %s\n",
195			       fdt_strerror(node));
196			return -EIO;
197		}
198
199		/* Populate properties in node */
200		for (i = 0; i < ARRAY_SIZE(octeontx_brd_nodes); i++) {
201			if (fdt_setprop_string(blob, node,
202					       octeontx_brd_nodes[i],
203					       nodes[i])) {
204				printf("Can't set %s\n", nodes[i]);
205				return -EIO;
206			}
207		}
208	}
209
210	return 0;
211}
212
213/**
214 * Return the FDT base address that was passed by ATF
215 *
216 * Return:	FDT base address received from ATF in x1 register
217 */
218void *board_fdt_blob_setup(int *err)
219{
220	*err = 0;
221	return (void *)fdt_base_addr;
222}
223