1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2020-2021 SiFive, Inc
4  *
5  * Authors:
6  *   Pragnesh Patel <pragnesh.patel@sifive.com>
7  */
8 
9 #include <init.h>
10 #include <spl.h>
11 #include <misc.h>
12 #include <log.h>
13 #include <linux/delay.h>
14 #include <linux/io.h>
15 #include <asm/gpio.h>
16 #include <asm/arch/gpio.h>
17 #include <asm/arch/spl.h>
18 
19 #define UBRDG_RESET	SIFIVE_GENERIC_GPIO_NR(0, 7)
20 #define ULPI_RESET	SIFIVE_GENERIC_GPIO_NR(0, 9)
21 #define UHUB_RESET	SIFIVE_GENERIC_GPIO_NR(0, 11)
22 #define GEM_PHY_RESET	SIFIVE_GENERIC_GPIO_NR(0, 12)
23 
24 #define MODE_SELECT_REG		0x1000
25 #define MODE_SELECT_SD		0xb
26 #define MODE_SELECT_MASK	GENMASK(3, 0)
27 
spl_reset_device_by_gpio(const char * label,int pin,int low_width)28 static inline int spl_reset_device_by_gpio(const char *label, int pin, int low_width)
29 {
30 	int ret;
31 
32 	ret = gpio_request(pin, label);
33 	if (ret) {
34 		debug("%s gpio request failed: %d\n", label, ret);
35 		return ret;
36 	}
37 
38 	ret = gpio_direction_output(pin, 1);
39 	if (ret) {
40 		debug("%s gpio direction set failed: %d\n", label, ret);
41 		return ret;
42 	}
43 
44 	udelay(1);
45 
46 	gpio_set_value(pin, 0);
47 	udelay(low_width);
48 	gpio_set_value(pin, 1);
49 
50 	return ret;
51 }
52 
spl_gemgxl_init(void)53 static inline int spl_gemgxl_init(void)
54 {
55 	int ret;
56 	/*
57 	 * GEMGXL init VSC8541 PHY reset sequence;
58 	 * leave pull-down active for 2ms
59 	 */
60 	udelay(2000);
61 	ret = spl_reset_device_by_gpio("gem_phy_reset", GEM_PHY_RESET, 1);
62 	mdelay(15);
63 
64 	return ret;
65 }
66 
spl_usb_pcie_bridge_init(void)67 static inline int spl_usb_pcie_bridge_init(void)
68 {
69 	return spl_reset_device_by_gpio("usb_pcie_bridge_reset", UBRDG_RESET, 3000);
70 }
71 
spl_usb_hub_init(void)72 static inline int spl_usb_hub_init(void)
73 {
74 	return spl_reset_device_by_gpio("usb_hub_reset", UHUB_RESET, 100);
75 }
76 
spl_ulpi_init(void)77 static inline int spl_ulpi_init(void)
78 {
79 	return spl_reset_device_by_gpio("ulpi_reset", ULPI_RESET, 1);
80 }
81 
spl_board_init_f(void)82 int spl_board_init_f(void)
83 {
84 	int ret;
85 
86 	ret = spl_soc_init();
87 	if (ret) {
88 		debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret);
89 		goto end;
90 	}
91 
92 	ret = spl_gemgxl_init();
93 	if (ret) {
94 		debug("Gigabit ethernet PHY (VSC8541) init failed: %d\n", ret);
95 		goto end;
96 	}
97 
98 	ret = spl_usb_pcie_bridge_init();
99 	if (ret) {
100 		debug("USB Bridge (ASM1042A) init failed: %d\n", ret);
101 		goto end;
102 	}
103 
104 	ret = spl_usb_hub_init();
105 	if (ret) {
106 		debug("USB Hub (ASM1074) init failed: %d\n", ret);
107 		goto end;
108 	}
109 
110 	ret = spl_ulpi_init();
111 	if (ret) {
112 		debug("USB 2.0 PHY (USB3320C) init failed: %d\n", ret);
113 		goto end;
114 	}
115 
116 end:
117 	return ret;
118 }
119 
spl_boot_device(void)120 u32 spl_boot_device(void)
121 {
122 	u32 mode_select = readl((void *)MODE_SELECT_REG);
123 	u32 boot_device = mode_select & MODE_SELECT_MASK;
124 
125 	switch (boot_device) {
126 	case MODE_SELECT_SD:
127 		return BOOT_DEVICE_MMC1;
128 	default:
129 		debug("Unsupported boot device 0x%x but trying MMC1\n",
130 		      boot_device);
131 		return BOOT_DEVICE_MMC1;
132 	}
133 }
134 
135 #ifdef CONFIG_SPL_LOAD_FIT
board_fit_config_name_match(const char * name)136 int board_fit_config_name_match(const char *name)
137 {
138 	/* boot using first FIT config */
139 	return 0;
140 }
141 #endif
142