stm32mp1: support forced boot mode
[platform/kernel/u-boot.git] / board / st / stm32mp1 / stm32mp1.c
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 <clk.h>
7 #include <common.h>
8 #include <dm.h>
9 #include <generic-phy.h>
10 #include <led.h>
11 #include <misc.h>
12 #include <phy.h>
13 #include <reset.h>
14 #include <usb.h>
15 #include <asm/arch/stm32.h>
16 #include <asm/io.h>
17 #include <asm/gpio.h>
18 #include <power/regulator.h>
19 #include <usb/dwc2_udc.h>
20
21 /*
22  * Get a global data pointer
23  */
24 DECLARE_GLOBAL_DATA_PTR;
25
26 #define STM32MP_GUSBCFG 0x40002407
27
28 #define STM32MP_GGPIO 0x38
29 #define STM32MP_GGPIO_VBUS_SENSING BIT(21)
30
31 int checkboard(void)
32 {
33         int ret;
34         char *mode;
35         u32 otp;
36         struct udevice *dev;
37         const char *fdt_compat;
38         int fdt_compat_len;
39
40         if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
41                 mode = "trusted";
42         else
43                 mode = "basic";
44
45         printf("Board: stm32mp1 in %s mode", mode);
46         fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
47                                  &fdt_compat_len);
48         if (fdt_compat && fdt_compat_len)
49                 printf(" (%s)", fdt_compat);
50         puts("\n");
51
52         ret = uclass_get_device_by_driver(UCLASS_MISC,
53                                           DM_GET_DRIVER(stm32mp_bsec),
54                                           &dev);
55
56         if (!ret)
57                 ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
58                                 &otp, sizeof(otp));
59         if (!ret && otp) {
60                 printf("Board: MB%04x Var%d Rev.%c-%02d\n",
61                        otp >> 16,
62                        (otp >> 12) & 0xF,
63                        ((otp >> 8) & 0xF) - 1 + 'A',
64                        otp & 0xF);
65         }
66
67         return 0;
68 }
69
70 static void board_key_check(void)
71 {
72 #if defined(CONFIG_FASTBOOT) || defined(CONFIG_CMD_STM32PROG)
73         ofnode node;
74         struct gpio_desc gpio;
75         enum forced_boot_mode boot_mode = BOOT_NORMAL;
76
77         node = ofnode_path("/config");
78         if (!ofnode_valid(node)) {
79                 debug("%s: no /config node?\n", __func__);
80                 return;
81         }
82 #ifdef CONFIG_FASTBOOT
83         if (gpio_request_by_name_nodev(node, "st,fastboot-gpios", 0,
84                                        &gpio, GPIOD_IS_IN)) {
85                 debug("%s: could not find a /config/st,fastboot-gpios\n",
86                       __func__);
87         } else {
88                 if (dm_gpio_get_value(&gpio)) {
89                         puts("Fastboot key pressed, ");
90                         boot_mode = BOOT_FASTBOOT;
91                 }
92
93                 dm_gpio_free(NULL, &gpio);
94         }
95 #endif
96 #ifdef CONFIG_CMD_STM32PROG
97         if (gpio_request_by_name_nodev(node, "st,stm32prog-gpios", 0,
98                                        &gpio, GPIOD_IS_IN)) {
99                 debug("%s: could not find a /config/st,stm32prog-gpios\n",
100                       __func__);
101         } else {
102                 if (dm_gpio_get_value(&gpio)) {
103                         puts("STM32Programmer key pressed, ");
104                         boot_mode = BOOT_STM32PROG;
105                 }
106                 dm_gpio_free(NULL, &gpio);
107         }
108 #endif
109
110         if (boot_mode != BOOT_NORMAL) {
111                 puts("entering download mode...\n");
112                 clrsetbits_le32(TAMP_BOOT_CONTEXT,
113                                 TAMP_BOOT_FORCED_MASK,
114                                 boot_mode);
115         }
116 #endif
117 }
118
119 static struct dwc2_plat_otg_data stm32mp_otg_data = {
120         .usb_gusbcfg = STM32MP_GUSBCFG,
121 };
122
123 static struct reset_ctl usbotg_reset;
124
125 int board_usb_init(int index, enum usb_init_type init)
126 {
127         struct fdtdec_phandle_args args;
128         struct udevice *dev;
129         const void *blob = gd->fdt_blob;
130         struct clk clk;
131         struct phy phy;
132         int node;
133         int phy_provider;
134         int ret;
135
136         /* find the usb otg node */
137         node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
138         if (node < 0) {
139                 debug("Not found usb_otg device\n");
140                 return -ENODEV;
141         }
142
143         if (!fdtdec_get_is_enabled(blob, node)) {
144                 debug("stm32 usbotg is disabled in the device tree\n");
145                 return -ENODEV;
146         }
147
148         /* Enable clock */
149         ret = fdtdec_parse_phandle_with_args(blob, node, "clocks",
150                                              "#clock-cells", 0, 0, &args);
151         if (ret) {
152                 debug("usbotg has no clocks defined in the device tree\n");
153                 return ret;
154         }
155
156         ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev);
157         if (ret)
158                 return ret;
159
160         if (args.args_count != 1) {
161                 debug("Can't find clock ID in the device tree\n");
162                 return -ENODATA;
163         }
164
165         clk.dev = dev;
166         clk.id = args.args[0];
167
168         ret = clk_enable(&clk);
169         if (ret) {
170                 debug("Failed to enable usbotg clock\n");
171                 return ret;
172         }
173
174         /* Reset */
175         ret = fdtdec_parse_phandle_with_args(blob, node, "resets",
176                                              "#reset-cells", 0, 0, &args);
177         if (ret) {
178                 debug("usbotg has no resets defined in the device tree\n");
179                 goto clk_err;
180         }
181
182         ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev);
183         if (ret || args.args_count != 1)
184                 goto clk_err;
185
186         usbotg_reset.dev = dev;
187         usbotg_reset.id = args.args[0];
188
189         reset_assert(&usbotg_reset);
190         udelay(2);
191         reset_deassert(&usbotg_reset);
192
193         /* Get USB PHY */
194         ret = fdtdec_parse_phandle_with_args(blob, node, "phys",
195                                              "#phy-cells", 0, 0, &args);
196         if (!ret) {
197                 phy_provider = fdt_parent_offset(blob, args.node);
198                 ret = uclass_get_device_by_of_offset(UCLASS_PHY,
199                                                      phy_provider, &dev);
200                 if (ret)
201                         goto clk_err;
202
203                 phy.dev = dev;
204                 phy.id = fdtdec_get_uint(blob, args.node, "reg", -1);
205
206                 ret = generic_phy_power_on(&phy);
207                 if (ret) {
208                         debug("unable to power on the phy\n");
209                         goto clk_err;
210                 }
211
212                 ret = generic_phy_init(&phy);
213                 if (ret) {
214                         debug("failed to init usb phy\n");
215                         goto phy_power_err;
216                 }
217         }
218
219         /* Parse and store data needed for gadget */
220         stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
221         if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) {
222                 debug("usbotg: can't get base address\n");
223                 ret = -ENODATA;
224                 goto phy_init_err;
225         }
226
227         stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node,
228                                                      "g-rx-fifo-size", 0);
229         stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node,
230                                                         "g-np-tx-fifo-size", 0);
231         stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node,
232                                                      "g-tx-fifo-size", 0);
233         /* Enable voltage level detector */
234         if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply",
235                                              NULL, 0, 0, &args))) {
236                 if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR,
237                                                     args.node, &dev)) {
238                         ret = regulator_set_enable(dev, true);
239                         if (ret) {
240                                 debug("Failed to enable usb33d\n");
241                                 goto phy_init_err;
242                         }
243                 }
244         }
245                 /* Enable vbus sensing */
246         setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO,
247                      STM32MP_GGPIO_VBUS_SENSING);
248
249         return dwc2_udc_probe(&stm32mp_otg_data);
250
251 phy_init_err:
252         generic_phy_exit(&phy);
253
254 phy_power_err:
255         generic_phy_power_off(&phy);
256
257 clk_err:
258         clk_disable(&clk);
259
260         return ret;
261 }
262
263 int board_usb_cleanup(int index, enum usb_init_type init)
264 {
265         /* Reset usbotg */
266         reset_assert(&usbotg_reset);
267         udelay(2);
268         reset_deassert(&usbotg_reset);
269
270         return 0;
271 }
272
273 /* board dependent setup after realloc */
274 int board_init(void)
275 {
276         /* address of boot parameters */
277         gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100;
278
279         board_key_check();
280
281         if (IS_ENABLED(CONFIG_LED))
282                 led_default_state();
283
284         return 0;
285 }
286
287 int board_late_init(void)
288 {
289 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
290         const void *fdt_compat;
291         int fdt_compat_len;
292
293         fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
294                                  &fdt_compat_len);
295         if (fdt_compat && fdt_compat_len) {
296                 if (strncmp(fdt_compat, "st,", 3) != 0)
297                         env_set("board_name", fdt_compat);
298                 else
299                         env_set("board_name", fdt_compat + 3);
300         }
301 #endif
302
303         return 0;
304 }