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 <command.h>
9#include <console.h>
10#include <cpu_func.h>
11#include <dm.h>
12#include <asm/global_data.h>
13#include <dm/uclass-internal.h>
14#include <env.h>
15#include <event.h>
16#include <init.h>
17#include <malloc.h>
18#include <net.h>
19#include <pci_ids.h>
20#include <errno.h>
21#include <asm/io.h>
22#include <linux/compiler.h>
23#include <linux/delay.h>
24#include <linux/libfdt.h>
25#include <fdt_support.h>
26#include <asm/arch/smc.h>
27#include <asm/arch/soc.h>
28#include <asm/arch/board.h>
29#include <dm/util.h>
30
31DECLARE_GLOBAL_DATA_PTR;
32
33void cleanup_env_ethaddr(void)
34{
35	char ename[32];
36
37	for (int i = 0; i < 20; i++) {
38		sprintf(ename, i ? "eth%daddr" : "ethaddr", i);
39		if (env_get(ename))
40			env_set(ename, NULL);
41	}
42}
43
44void octeontx2_board_get_mac_addr(u8 index, u8 *mac_addr)
45{
46	u64 tmp_mac, board_mac_addr = fdt_get_board_mac_addr();
47	static int board_mac_num;
48
49	board_mac_num = fdt_get_board_mac_cnt();
50	if ((!is_zero_ethaddr((u8 *)&board_mac_addr)) && board_mac_num) {
51		tmp_mac = board_mac_addr;
52		tmp_mac += index;
53		tmp_mac = swab64(tmp_mac) >> 16;
54		memcpy(mac_addr, (u8 *)&tmp_mac, ARP_HLEN);
55		board_mac_num--;
56	} else {
57		memset(mac_addr, 0, ARP_HLEN);
58	}
59	debug("%s mac %pM\n", __func__, mac_addr);
60}
61
62void board_quiesce_devices(void)
63{
64	struct uclass *uc_dev;
65	int ret;
66
67	/* Removes all RVU PF devices */
68	ret = uclass_get(UCLASS_ETH, &uc_dev);
69	if (uc_dev)
70		ret = uclass_destroy(uc_dev);
71	if (ret)
72		printf("couldn't remove rvu pf devices\n");
73
74	if (IS_ENABLED(CONFIG_OCTEONTX2_CGX_INTF)) {
75		/* Bring down all cgx lmac links */
76		cgx_intf_shutdown();
77	}
78
79	/* Removes all CGX and RVU AF devices */
80	ret = uclass_get(UCLASS_MISC, &uc_dev);
81	if (uc_dev)
82		ret = uclass_destroy(uc_dev);
83	if (ret)
84		printf("couldn't remove misc (cgx/rvu_af) devices\n");
85
86	/* SMC call - removes all LF<->PF mappings */
87	smc_disable_rvu_lfs(0);
88}
89
90int board_early_init_r(void)
91{
92	pci_init();
93	return 0;
94}
95
96int board_init(void)
97{
98	return 0;
99}
100
101int timer_init(void)
102{
103	return 0;
104}
105
106int dram_init(void)
107{
108	gd->ram_size = smc_dram_size(0);
109	gd->ram_size -= CFG_SYS_SDRAM_BASE;
110
111	mem_map_fill();
112
113	return 0;
114}
115
116void board_late_probe_devices(void)
117{
118	struct udevice *dev;
119	int err, cgx_cnt = 3, i;
120
121	/* Probe MAC(CGX) and NIC AF devices before Network stack init */
122	for (i = 0; i < cgx_cnt; i++) {
123		err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
124					 PCI_DEVICE_ID_CAVIUM_CGX, i, &dev);
125		if (err)
126			debug("%s CGX%d device not found\n", __func__, i);
127	}
128	err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
129				 PCI_DEVICE_ID_CAVIUM_RVU_AF, 0, &dev);
130	if (err)
131		debug("NIC AF device not found\n");
132}
133
134/**
135 * Board late initialization routine.
136 */
137int board_late_init(void)
138{
139	char boardname[32];
140	char boardserial[150], boardrev[150];
141	long val;
142	bool save_env = false;
143	const char *str;
144
145	debug("%s()\n", __func__);
146
147	/*
148	 * Now that pci_init initializes env device.
149	 * Try to cleanup ethaddr env variables, this is needed
150	 * as with each boot, configuration of QLM can change.
151	 */
152	cleanup_env_ethaddr();
153
154	snprintf(boardname, sizeof(boardname), "%s> ", fdt_get_board_model());
155	env_set("prompt", boardname);
156	set_working_fdt_addr(env_get_hex("fdtcontroladdr", fdt_base_addr));
157
158	str = fdt_get_board_revision();
159	if (str) {
160		snprintf(boardrev, sizeof(boardrev), "%s", str);
161		if (env_get("boardrev") &&
162		    strcmp(boardrev, env_get("boardrev")))
163			save_env = true;
164		env_set("boardrev", boardrev);
165	}
166
167	str = fdt_get_board_serial();
168	if (str) {
169		snprintf(boardserial, sizeof(boardserial), "%s", str);
170		if (env_get("serial#") &&
171		    strcmp(boardserial, env_get("serial#")))
172			save_env = true;
173		env_set("serial#", boardserial);
174	}
175
176	val = env_get_hex("disable_ooo", 0);
177	smc_configure_ooo(val);
178
179	if (IS_ENABLED(CONFIG_NET_OCTEONTX2))
180		board_late_probe_devices();
181
182	if (save_env)
183		env_save();
184
185	return 0;
186}
187
188/*
189 * Invoked before relocation, so limit to stack variables.
190 */
191int checkboard(void)
192{
193	printf("Board: %s\n", fdt_get_board_model());
194
195	return 0;
196}
197
198void board_acquire_flash_arb(bool acquire)
199{
200	union cpc_boot_ownerx ownerx;
201
202	if (!acquire) {
203		ownerx.u = readl(CPC_BOOT_OWNERX(3));
204		ownerx.s.boot_req = 0;
205		writel(ownerx.u, CPC_BOOT_OWNERX(3));
206	} else {
207		ownerx.u = 0;
208		ownerx.s.boot_req = 1;
209		writel(ownerx.u, CPC_BOOT_OWNERX(3));
210		udelay(1);
211		do {
212			ownerx.u = readl(CPC_BOOT_OWNERX(3));
213		} while (ownerx.s.boot_wait);
214	}
215}
216
217static int last_stage_init(void)
218{
219	(void)smc_flsf_fw_booted();
220	return 0;
221}
222EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, last_stage_init);
223
224static int do_go_uboot(struct cmd_tbl *cmdtp, int flag, int argc,
225		       char *const argv[])
226{
227	typedef void __noreturn (*uboot_entry_t)(ulong, void *);
228	uboot_entry_t entry;
229	ulong addr;
230	void *fdt;
231	int err;
232
233	if (argc < 2)
234		return CMD_RET_USAGE;
235
236	addr = hextoul(argv[1], NULL);
237	fdt = board_fdt_blob_setup(&err);
238	entry = (uboot_entry_t)addr;
239	flush_cache((ulong)addr, 1 << 20);	/* 1MiB should be enough */
240	dcache_disable();
241
242	printf("## Starting U-Boot at %p (FDT at %p)...\n", entry, fdt);
243
244	entry(0, fdt);
245
246	return 0;
247}
248
249U_BOOT_CMD(go_uboot, 2, 0, do_go_uboot,
250	   "Start U-Boot from RAM (pass FDT via x1 register)",
251	   "");
252