xref: /openbmc/u-boot/board/st/stm32mp1/stm32mp1.c (revision 592cd5de)
1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4  */
5 #include <config.h>
6 #include <common.h>
7 #include <led.h>
8 #include <clk.h>
9 #include <dm.h>
10 #include <generic-phy.h>
11 #include <phy.h>
12 #include <reset.h>
13 #include <usb.h>
14 #include <asm/arch/stm32.h>
15 #include <asm/io.h>
16 #include <power/regulator.h>
17 #include <usb/dwc2_udc.h>
18 
19 /*
20  * Get a global data pointer
21  */
22 DECLARE_GLOBAL_DATA_PTR;
23 
24 #define STM32MP_GUSBCFG 0x40002407
25 
26 #define STM32MP_GGPIO 0x38
27 #define STM32MP_GGPIO_VBUS_SENSING BIT(21)
28 
29 static struct dwc2_plat_otg_data stm32mp_otg_data = {
30 	.usb_gusbcfg = STM32MP_GUSBCFG,
31 };
32 
33 static struct reset_ctl usbotg_reset;
34 
board_usb_init(int index,enum usb_init_type init)35 int board_usb_init(int index, enum usb_init_type init)
36 {
37 	struct fdtdec_phandle_args args;
38 	struct udevice *dev;
39 	const void *blob = gd->fdt_blob;
40 	struct clk clk;
41 	struct phy phy;
42 	int node;
43 	int phy_provider;
44 	int ret;
45 
46 	/* find the usb otg node */
47 	node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
48 	if (node < 0) {
49 		debug("Not found usb_otg device\n");
50 		return -ENODEV;
51 	}
52 
53 	if (!fdtdec_get_is_enabled(blob, node)) {
54 		debug("stm32 usbotg is disabled in the device tree\n");
55 		return -ENODEV;
56 	}
57 
58 	/* Enable clock */
59 	ret = fdtdec_parse_phandle_with_args(blob, node, "clocks",
60 					     "#clock-cells", 0, 0, &args);
61 	if (ret) {
62 		debug("usbotg has no clocks defined in the device tree\n");
63 		return ret;
64 	}
65 
66 	ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev);
67 	if (ret)
68 		return ret;
69 
70 	if (args.args_count != 1) {
71 		debug("Can't find clock ID in the device tree\n");
72 		return -ENODATA;
73 	}
74 
75 	clk.dev = dev;
76 	clk.id = args.args[0];
77 
78 	ret = clk_enable(&clk);
79 	if (ret) {
80 		debug("Failed to enable usbotg clock\n");
81 		return ret;
82 	}
83 
84 	/* Reset */
85 	ret = fdtdec_parse_phandle_with_args(blob, node, "resets",
86 					     "#reset-cells", 0, 0, &args);
87 	if (ret) {
88 		debug("usbotg has no resets defined in the device tree\n");
89 		goto clk_err;
90 	}
91 
92 	ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev);
93 	if (ret || args.args_count != 1)
94 		goto clk_err;
95 
96 	usbotg_reset.dev = dev;
97 	usbotg_reset.id = args.args[0];
98 
99 	reset_assert(&usbotg_reset);
100 	udelay(2);
101 	reset_deassert(&usbotg_reset);
102 
103 	/* Get USB PHY */
104 	ret = fdtdec_parse_phandle_with_args(blob, node, "phys",
105 					     "#phy-cells", 0, 0, &args);
106 	if (!ret) {
107 		phy_provider = fdt_parent_offset(blob, args.node);
108 		ret = uclass_get_device_by_of_offset(UCLASS_PHY,
109 						     phy_provider, &dev);
110 		if (ret)
111 			goto clk_err;
112 
113 		phy.dev = dev;
114 		phy.id = fdtdec_get_uint(blob, args.node, "reg", -1);
115 
116 		ret = generic_phy_power_on(&phy);
117 		if (ret) {
118 			debug("unable to power on the phy\n");
119 			goto clk_err;
120 		}
121 
122 		ret = generic_phy_init(&phy);
123 		if (ret) {
124 			debug("failed to init usb phy\n");
125 			goto phy_power_err;
126 		}
127 	}
128 
129 	/* Parse and store data needed for gadget */
130 	stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
131 	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) {
132 		debug("usbotg: can't get base address\n");
133 		ret = -ENODATA;
134 		goto phy_init_err;
135 	}
136 
137 	stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node,
138 						     "g-rx-fifo-size", 0);
139 	stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node,
140 							"g-np-tx-fifo-size", 0);
141 	stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node,
142 						     "g-tx-fifo-size", 0);
143 	/* Enable voltage level detector */
144 	if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply",
145 					     NULL, 0, 0, &args))) {
146 		if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR,
147 						    args.node, &dev)) {
148 			ret = regulator_set_enable(dev, true);
149 			if (ret) {
150 				debug("Failed to enable usb33d\n");
151 				goto phy_init_err;
152 			}
153 		}
154 	}
155 		/* Enable vbus sensing */
156 	setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO,
157 		     STM32MP_GGPIO_VBUS_SENSING);
158 
159 	return dwc2_udc_probe(&stm32mp_otg_data);
160 
161 phy_init_err:
162 	generic_phy_exit(&phy);
163 
164 phy_power_err:
165 	generic_phy_power_off(&phy);
166 
167 clk_err:
168 	clk_disable(&clk);
169 
170 	return ret;
171 }
172 
board_usb_cleanup(int index,enum usb_init_type init)173 int board_usb_cleanup(int index, enum usb_init_type init)
174 {
175 	/* Reset usbotg */
176 	reset_assert(&usbotg_reset);
177 	udelay(2);
178 	reset_deassert(&usbotg_reset);
179 
180 	return 0;
181 }
182 
board_late_init(void)183 int board_late_init(void)
184 {
185 	return 0;
186 }
187 
188 /* board dependent setup after realloc */
board_init(void)189 int board_init(void)
190 {
191 	/* address of boot parameters */
192 	gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100;
193 
194 	if (IS_ENABLED(CONFIG_LED))
195 		led_default_state();
196 
197 	return 0;
198 }
199