1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2022 StarFive Technology Co., Ltd.
4 * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
5 */
6
7#include <asm/arch/eeprom.h>
8#include <asm/arch/gpio.h>
9#include <asm/arch/regs.h>
10#include <asm/arch/spl.h>
11#include <asm/io.h>
12#include <dt-bindings/clock/starfive,jh7110-crg.h>
13#include <fdt_support.h>
14#include <linux/libfdt.h>
15#include <log.h>
16#include <spl.h>
17
18DECLARE_GLOBAL_DATA_PTR;
19#define JH7110_CLK_CPU_ROOT_OFFSET		0x0U
20#define JH7110_CLK_CPU_ROOT_SHIFT		24
21#define JH7110_CLK_CPU_ROOT_MASK		GENMASK(29, 24)
22
23struct starfive_vf2_pro {
24	const char *path;
25	const char *name;
26	const char *value;
27};
28
29static const struct starfive_vf2_pro milk_v_mars[] = {
30	{"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL},
31	{"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL},
32
33	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
34		"motorcomm,tx-clk-adj-enabled", NULL},
35	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
36		"motorcomm,tx-clk-100-inverted", NULL},
37	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
38		"motorcomm,tx-clk-1000-inverted", NULL},
39	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
40		"motorcomm,rx-clk-drv-microamp", "3970"},
41	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
42		"motorcomm,rx-data-drv-microamp", "2910"},
43	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
44		"rx-internal-delay-ps", "1900"},
45	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
46		"tx-internal-delay-ps", "1500"},
47};
48
49static const struct starfive_vf2_pro starfive_vera[] = {
50	{"/soc/ethernet@16030000/mdio/ethernet-phy@0", "rx-internal-delay-ps",
51		"1900"},
52	{"/soc/ethernet@16030000/mdio/ethernet-phy@0", "tx-internal-delay-ps",
53		"1350"}
54};
55
56static const struct starfive_vf2_pro starfive_verb[] = {
57	{"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL},
58	{"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL},
59
60	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
61		"motorcomm,tx-clk-adj-enabled", NULL},
62	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
63		"motorcomm,tx-clk-100-inverted", NULL},
64	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
65		"motorcomm,tx-clk-1000-inverted", NULL},
66	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
67		"motorcomm,rx-clk-drv-microamp", "3970"},
68	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
69		"motorcomm,rx-data-drv-microamp", "2910"},
70	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
71		"rx-internal-delay-ps", "1900"},
72	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
73		"tx-internal-delay-ps", "1500"},
74
75	{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
76		"motorcomm,tx-clk-adj-enabled", NULL},
77	{ "/soc/ethernet@16040000/mdio/ethernet-phy@1",
78		"motorcomm,tx-clk-100-inverted", NULL},
79	{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
80		"motorcomm,rx-clk-drv-microamp", "3970"},
81	{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
82		"motorcomm,rx-data-drv-microamp", "2910"},
83	{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
84		"rx-internal-delay-ps", "0"},
85	{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
86		"tx-internal-delay-ps", "0"},
87};
88
89void spl_fdt_fixup_mars(void *fdt)
90{
91	static const char compat[] = "milkv,mars\0starfive,jh7110";
92	u32 phandle;
93	u8 i;
94	int offset;
95	int ret;
96
97	fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat));
98	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
99			   "Milk-V Mars");
100
101	/* gmac0 */
102	offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000");
103	phandle = fdt_get_phandle(fdt, offset);
104	offset = fdt_path_offset(fdt, "/soc/ethernet@16030000");
105
106	fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
107	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX);
108	fdt_setprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
109	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
110			   JH7110_AONCLK_GMAC0_RMII_RTX);
111
112	/* gmac1 */
113	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"),
114			   "status", "disabled");
115
116	for (i = 0; i < ARRAY_SIZE(milk_v_mars); i++) {
117		offset = fdt_path_offset(fdt, milk_v_mars[i].path);
118
119		if (milk_v_mars[i].value)
120			ret = fdt_setprop_u32(fdt, offset, milk_v_mars[i].name,
121					      dectoul(milk_v_mars[i].value, NULL));
122		else
123			ret = fdt_setprop_empty(fdt, offset, milk_v_mars[i].name);
124
125		if (ret) {
126			pr_err("%s set prop %s fail.\n", __func__, milk_v_mars[i].name);
127				break;
128		}
129	}
130}
131
132void spl_fdt_fixup_mars_cm(void *fdt)
133{
134	const char *compat;
135	const char *model;
136
137	spl_fdt_fixup_mars(fdt);
138
139	if (!get_mmc_size_from_eeprom()) {
140		int offset;
141
142		model = "Milk-V Mars CM Lite";
143		compat = "milkv,mars-cm-lite\0starfive,jh7110";
144
145		offset = fdt_path_offset(fdt, "/soc/pinctrl/mmc0-pins/mmc0-pins-rest");
146		/* GPIOMUX(22, GPOUT_SYS_SDIO0_RST, GPOEN_ENABLE, GPI_NONE) */
147		fdt_setprop_u32(fdt, offset, "pinmux", 0xff130016);
148	} else {
149		model = "Milk-V Mars CM";
150		compat = "milkv,mars-cm\0starfive,jh7110";
151	}
152	fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat));
153	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", model);
154}
155
156void spl_fdt_fixup_version_a(void *fdt)
157{
158	static const char compat[] = "starfive,visionfive-2-v1.2a\0starfive,jh7110";
159	u32 phandle;
160	u8 i;
161	int offset;
162	int ret;
163
164	fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat));
165	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
166			   "StarFive VisionFive 2 v1.2A");
167
168	offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000");
169	phandle = fdt_get_phandle(fdt, offset);
170	offset = fdt_path_offset(fdt, "/soc/ethernet@16040000");
171
172	fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
173	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX);
174	fdt_appendprop_u32(fdt, offset, "assigned-clocks", phandle);
175	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_RX);
176
177	fdt_setprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
178	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
179			   JH7110_SYSCLK_GMAC1_RMII_RTX);
180	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
181	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
182			   JH7110_SYSCLK_GMAC1_RMII_RTX);
183
184	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"),
185			   "phy-mode", "rmii");
186
187	for (i = 0; i < ARRAY_SIZE(starfive_vera); i++) {
188		offset = fdt_path_offset(fdt, starfive_vera[i].path);
189
190		if (starfive_vera[i].value)
191			ret = fdt_setprop_u32(fdt, offset,  starfive_vera[i].name,
192					      dectoul(starfive_vera[i].value, NULL));
193		else
194			ret = fdt_setprop_empty(fdt, offset, starfive_vera[i].name);
195
196		if (ret) {
197			pr_err("%s set prop %s fail.\n", __func__, starfive_vera[i].name);
198				break;
199		}
200	}
201}
202
203void spl_fdt_fixup_version_b(void *fdt)
204{
205	static const char compat[] = "starfive,visionfive-2-v1.3b\0starfive,jh7110";
206	u32 phandle;
207	u8 i;
208	int offset;
209	int ret;
210
211	fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat));
212	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
213			   "StarFive VisionFive 2 v1.3B");
214
215	/* gmac0 */
216	offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000");
217	phandle = fdt_get_phandle(fdt, offset);
218	offset = fdt_path_offset(fdt, "/soc/ethernet@16030000");
219
220	fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
221	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX);
222	fdt_setprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
223	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
224			   JH7110_AONCLK_GMAC0_RMII_RTX);
225
226	/* gmac1 */
227	offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000");
228	phandle = fdt_get_phandle(fdt, offset);
229	offset = fdt_path_offset(fdt, "/soc/ethernet@16040000");
230
231	fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
232	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX);
233	fdt_setprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
234	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
235			   JH7110_SYSCLK_GMAC1_RMII_RTX);
236
237	for (i = 0; i < ARRAY_SIZE(starfive_verb); i++) {
238		offset = fdt_path_offset(fdt, starfive_verb[i].path);
239
240		if (starfive_verb[i].value)
241			ret = fdt_setprop_u32(fdt, offset,  starfive_verb[i].name,
242					      dectoul(starfive_verb[i].value, NULL));
243		else
244			ret = fdt_setprop_empty(fdt, offset, starfive_verb[i].name);
245
246		if (ret) {
247			pr_err("%s set prop %s fail.\n", __func__, starfive_verb[i].name);
248				break;
249		}
250	}
251}
252
253void spl_perform_fixups(struct spl_image_info *spl_image)
254{
255	u8 version;
256	const char *product_id;
257
258	product_id = get_product_id_from_eeprom();
259	if (!product_id) {
260		pr_err("Can't read EEPROM\n");
261		return;
262	}
263	if (!strncmp(product_id, "MARC", 4)) {
264		spl_fdt_fixup_mars_cm(spl_image->fdt_addr);
265	} else if (!strncmp(product_id, "MARS", 4)) {
266		spl_fdt_fixup_mars(spl_image->fdt_addr);
267	} else if (!strncmp(product_id, "VF7110", 6)) {
268		version = get_pcb_revision_from_eeprom();
269		switch (version) {
270		case 'a':
271		case 'A':
272			spl_fdt_fixup_version_a(spl_image->fdt_addr);
273			break;
274
275		case 'b':
276		case 'B':
277		default:
278			spl_fdt_fixup_version_b(spl_image->fdt_addr);
279		break;
280		};
281	} else {
282		pr_err("Unknown product %s\n", product_id);
283	};
284
285	/* Update the memory size which read from eeprom or DT */
286	fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size);
287}
288
289static void jh7110_jtag_init(void)
290{
291	/* nTRST: GPIO36 */
292	SYS_IOMUX_DOEN(36, HIGH);
293	SYS_IOMUX_DIN(36, 4);
294	/* TDI: GPIO61 */
295	SYS_IOMUX_DOEN(61, HIGH);
296	SYS_IOMUX_DIN(61, 19);
297	/* TMS: GPIO63 */
298	SYS_IOMUX_DOEN(63, HIGH);
299	SYS_IOMUX_DIN(63, 20);
300	/* TCK: GPIO60 */
301	SYS_IOMUX_DOEN(60, HIGH);
302	SYS_IOMUX_DIN(60, 29);
303	/* TDO: GPIO44 */
304	SYS_IOMUX_DOEN(44, 8);
305	SYS_IOMUX_DOUT(44, 22);
306}
307
308int spl_board_init_f(void)
309{
310	int ret;
311
312	jh7110_jtag_init();
313
314	ret = spl_dram_init();
315	if (ret) {
316		debug("JH7110 DRAM init failed: %d\n", ret);
317		return ret;
318	}
319
320	return 0;
321}
322
323u32 spl_boot_device(void)
324{
325	u32 mode;
326
327	mode = in_le32(JH7110_BOOT_MODE_SELECT_REG)
328				& JH7110_BOOT_MODE_SELECT_MASK;
329	switch (mode) {
330	case 0:
331		return BOOT_DEVICE_SPI;
332
333	case 1:
334		return BOOT_DEVICE_MMC2;
335
336	case 2:
337		return BOOT_DEVICE_MMC1;
338
339	case 3:
340		return BOOT_DEVICE_UART;
341
342	default:
343		debug("Unsupported boot device 0x%x.\n", mode);
344		return BOOT_DEVICE_NONE;
345	}
346}
347
348void board_init_f(ulong dummy)
349{
350	int ret;
351
352	ret = spl_early_init();
353	if (ret)
354		panic("spl_early_init() failed: %d\n", ret);
355
356	riscv_cpu_setup();
357	preloader_console_init();
358
359	/* Set the parent clock of cpu_root clock to pll0,
360	 * it must be initialized here
361	 */
362	clrsetbits_le32(JH7110_SYS_CRG + JH7110_CLK_CPU_ROOT_OFFSET,
363			JH7110_CLK_CPU_ROOT_MASK,
364			BIT(JH7110_CLK_CPU_ROOT_SHIFT));
365
366	ret = spl_board_init_f();
367	if (ret) {
368		debug("spl_board_init_f init failed: %d\n", ret);
369		return;
370	}
371}
372
373#if CONFIG_IS_ENABLED(SPL_LOAD_FIT)
374int board_fit_config_name_match(const char *name)
375{
376	/* boot using first FIT config */
377	return 0;
378}
379#endif
380