blob: 6b43b58700734e2d37da857baac42b41250f37b1 [file] [log] [blame]
Marcel Ziswiler3d603662019-05-31 19:00:20 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Toradex
4 */
5
6#include <common.h>
Simon Glass9a3b4ce2019-12-28 10:45:01 -07007#include <cpu_func.h>
Simon Glass52559322019-11-14 12:57:46 -07008#include <init.h>
Simon Glass401d1c42020-10-30 21:38:53 -06009#include <asm/global_data.h>
Marcel Ziswiler3d603662019-05-31 19:00:20 +030010
11#include <asm/arch/clock.h>
12#include <asm/arch/imx8-pins.h>
13#include <asm/arch/iomux.h>
14#include <asm/arch/sci/sci.h>
Andrejs Cainikovs382e89c2023-01-16 20:05:12 +010015#include <asm/arch/snvs_security_sc.h>
Marcel Ziswiler3d603662019-05-31 19:00:20 +030016#include <asm/arch/sys_proto.h>
17#include <asm/gpio.h>
18#include <asm/io.h>
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +010019#include <command.h>
Simon Glass9fb625c2019-08-01 09:46:51 -060020#include <env.h>
Marcel Ziswiler3d603662019-05-31 19:00:20 +030021#include <errno.h>
Philippe Schenker0da8dde2022-05-09 18:58:16 +020022#include <linux/bitops.h>
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +010023#include <linux/delay.h>
24#include <linux/libfdt.h>
Marcel Ziswiler3d603662019-05-31 19:00:20 +030025
26#include "../common/tdx-cfg-block.h"
27
28DECLARE_GLOBAL_DATA_PTR;
29
30#define UART_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
31 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
32 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
33 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
34
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +010035#define PCB_VERS_DETECT ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
36 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
37 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
38 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
39
40#define GPIO_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
41 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
42 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
43 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
44
45#define PCB_VERS_DEFAULT ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
46 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
47 (SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT) | \
48 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT))
49
Philippe Schenker0da8dde2022-05-09 18:58:16 +020050#define TDX_USER_FUSE_BLOCK1_A 276
51#define TDX_USER_FUSE_BLOCK1_B 277
52#define TDX_USER_FUSE_BLOCK2_A 278
53#define TDX_USER_FUSE_BLOCK2_B 279
54
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +010055enum pcb_rev_t {
56 PCB_VERSION_1_0,
57 PCB_VERSION_1_1
58};
59
60static iomux_cfg_t pcb_vers_detect[] = {
61 SC_P_MIPI_DSI0_GPIO0_00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DETECT),
62 SC_P_MIPI_DSI0_GPIO0_01 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DETECT),
63};
64
65static iomux_cfg_t pcb_vers_default[] = {
66 SC_P_MIPI_DSI0_GPIO0_00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DEFAULT),
67 SC_P_MIPI_DSI0_GPIO0_01 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DEFAULT),
68};
69
Marcel Ziswiler3d603662019-05-31 19:00:20 +030070static iomux_cfg_t uart1_pads[] = {
71 SC_P_UART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
72 SC_P_UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
73};
74
Philippe Schenker0da8dde2022-05-09 18:58:16 +020075struct tdx_user_fuses {
76 u16 pid4;
77 u16 vers;
78 u8 ramid;
79};
80
Marcel Ziswiler3d603662019-05-31 19:00:20 +030081static void setup_iomux_uart(void)
82{
83 imx8_iomux_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
84}
85
Philippe Schenker0da8dde2022-05-09 18:58:16 +020086static uint32_t do_get_tdx_user_fuse(int a, int b)
87{
88 sc_err_t sciErr;
89 u32 val_a = 0;
90 u32 val_b = 0;
91
92 sciErr = sc_misc_otp_fuse_read(-1, a, &val_a);
93 if (sciErr != SC_ERR_NONE) {
94 printf("Error reading out user fuse %d\n", a);
95 return 0;
96 }
97
98 sciErr = sc_misc_otp_fuse_read(-1, b, &val_b);
99 if (sciErr != SC_ERR_NONE) {
100 printf("Error reading out user fuse %d\n", b);
101 return 0;
102 }
103
104 return ((val_a & 0xffff) << 16) | (val_b & 0xffff);
105}
106
107static void get_tdx_user_fuse(struct tdx_user_fuses *tdxuserfuse)
108{
109 u32 fuse_block;
110
111 fuse_block = do_get_tdx_user_fuse(TDX_USER_FUSE_BLOCK2_A,
112 TDX_USER_FUSE_BLOCK2_B);
113
114 /*
115 * Fuse block 2 acts as a backup area, if this reads 0 we want to
116 * use fuse block 1
117 */
118 if (fuse_block == 0)
119 fuse_block = do_get_tdx_user_fuse(TDX_USER_FUSE_BLOCK1_A,
120 TDX_USER_FUSE_BLOCK1_B);
121
122 tdxuserfuse->pid4 = (fuse_block >> 18) & GENMASK(13, 0);
123 tdxuserfuse->vers = (fuse_block >> 4) & GENMASK(13, 0);
124 tdxuserfuse->ramid = fuse_block & GENMASK(3, 0);
125}
126
Igor Opaniuk90311be2020-10-22 11:21:41 +0300127void board_mem_get_layout(u64 *phys_sdram_1_start,
128 u64 *phys_sdram_1_size,
129 u64 *phys_sdram_2_start,
130 u64 *phys_sdram_2_size)
131{
132 u32 is_quadplus = 0, val = 0;
Philippe Schenker0da8dde2022-05-09 18:58:16 +0200133 struct tdx_user_fuses tdxramfuses;
Igor Opaniuk90311be2020-10-22 11:21:41 +0300134 sc_err_t scierr = sc_misc_otp_fuse_read(-1, 6, &val);
135
136 if (scierr == SC_ERR_NONE) {
137 /* QP has one A72 core disabled */
138 is_quadplus = ((val >> 4) & 0x3) != 0x0;
139 }
140
Philippe Schenker0da8dde2022-05-09 18:58:16 +0200141 get_tdx_user_fuse(&tdxramfuses);
142
Igor Opaniuk90311be2020-10-22 11:21:41 +0300143 *phys_sdram_1_start = PHYS_SDRAM_1;
144 *phys_sdram_1_size = PHYS_SDRAM_1_SIZE;
145 *phys_sdram_2_start = PHYS_SDRAM_2;
Philippe Schenker0da8dde2022-05-09 18:58:16 +0200146
147 switch (tdxramfuses.ramid) {
148 case 1:
149 *phys_sdram_2_size = SZ_2G;
150 break;
151 case 2:
Igor Opaniuk90311be2020-10-22 11:21:41 +0300152 *phys_sdram_2_size = 0x0UL;
Philippe Schenker0da8dde2022-05-09 18:58:16 +0200153 break;
154 case 3:
155 *phys_sdram_2_size = SZ_2G;
156 break;
157 case 4:
158 *phys_sdram_2_size = SZ_4G + SZ_2G;
159 break;
160 default:
161 if (is_quadplus)
162 /* Our QP based SKUs only have 2 GB RAM (PHYS_SDRAM_1_SIZE) */
163 *phys_sdram_2_size = 0x0UL;
164 else
165 *phys_sdram_2_size = PHYS_SDRAM_2_SIZE;
166 break;
167 }
Igor Opaniuk90311be2020-10-22 11:21:41 +0300168}
169
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300170int board_early_init_f(void)
171{
Anatolij Gustschin64b5f462019-06-12 13:35:25 +0200172 sc_pm_clock_rate_t rate = SC_80MHZ;
Philippe Schenker63b61932023-01-16 20:05:10 +0100173 int ret;
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300174
Anatolij Gustschin64b5f462019-06-12 13:35:25 +0200175 /* Set UART1 clock root to 80 MHz and enable it */
Philippe Schenker63b61932023-01-16 20:05:10 +0100176 ret = sc_pm_setup_uart(SC_R_UART_1, rate);
177 if (ret)
178 return ret;
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300179
180 setup_iomux_uart();
181
182 return 0;
183}
184
Simon Glassbcee8d62019-12-06 21:41:35 -0700185#if CONFIG_IS_ENABLED(DM_GPIO)
Marcel Ziswiler717783e2023-01-16 20:04:57 +0100186
187#define BKL1_GPIO IMX_GPIO_NR(1, 10)
188
189static iomux_cfg_t board_gpios[] = {
190 SC_P_LVDS1_GPIO00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(GPIO_PAD_CTRL),
191};
192
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300193static void board_gpio_init(void)
194{
Marcel Ziswiler717783e2023-01-16 20:04:57 +0100195 imx8_iomux_setup_multiple_pads(board_gpios, ARRAY_SIZE(board_gpios));
196
197 gpio_request(BKL1_GPIO, "BKL1_GPIO");
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300198}
199#else
200static inline void board_gpio_init(void) {}
201#endif
202
Marcel Ziswiler717783e2023-01-16 20:04:57 +0100203/*
204 * Backlight off before OS handover
205 */
206void board_preboot_os(void)
207{
208 gpio_direction_output(BKL1_GPIO, 0);
209}
210
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300211int checkboard(void)
212{
213 puts("Model: Toradex Apalis iMX8\n");
214
215 build_info();
216 print_bootinfo();
217
218 return 0;
219}
220
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +0100221static enum pcb_rev_t get_pcb_revision(void)
222{
223 unsigned int pcb_vers = 0;
224
225 imx8_iomux_setup_multiple_pads(pcb_vers_detect,
226 ARRAY_SIZE(pcb_vers_detect));
227
228 gpio_request(IMX_GPIO_NR(1, 18),
229 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_00");
230 gpio_request(IMX_GPIO_NR(1, 19),
231 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_01");
232 gpio_direction_input(IMX_GPIO_NR(1, 18));
233 gpio_direction_input(IMX_GPIO_NR(1, 19));
234
235 udelay(1000);
236
237 pcb_vers = gpio_get_value(IMX_GPIO_NR(1, 18));
238 pcb_vers |= gpio_get_value(IMX_GPIO_NR(1, 19)) << 1;
239
240 /* Set muxing back to default values for saving energy */
241 imx8_iomux_setup_multiple_pads(pcb_vers_default,
242 ARRAY_SIZE(pcb_vers_default));
243
244 switch (pcb_vers) {
245 case 0b11:
246 return PCB_VERSION_1_0;
247 case 0b10:
248 return PCB_VERSION_1_1;
249 default:
250 printf("Unknown PCB version=0x%x, default to V1.1\n", pcb_vers);
251 return PCB_VERSION_1_1;
252 }
253}
254
255static void select_dt_from_module_version(void)
256{
257 env_set("soc", "imx8qm");
258 env_set("variant", "-v1.1");
259
260 switch (tdx_hw_tag.prodid) {
261 /* Select Apalis iMX8QM device trees */
262 case APALIS_IMX8QM_IT:
263 case APALIS_IMX8QM_WIFI_BT_IT:
264 case APALIS_IMX8QM_8GB_WIFI_BT_IT:
265 if (get_pcb_revision() == PCB_VERSION_1_0)
266 env_set("variant", "");
267 break;
268 /* Select Apalis iMX8QP device trees */
269 case APALIS_IMX8QP_WIFI_BT:
270 case APALIS_IMX8QP:
271 env_set("soc", "imx8qp");
272 break;
273 default:
274 printf("Unknown Apalis iMX8 module\n");
275 return;
276 }
277}
278
279static int do_select_dt_from_module_version(struct cmd_tbl *cmdtp, int flag,
280 int argc, char * const argv[])
281{
282 select_dt_from_module_version();
283 return 0;
284}
285
286U_BOOT_CMD(select_dt_from_module_version, CONFIG_SYS_MAXARGS, 1, do_select_dt_from_module_version,
287 "\n", " - select devicetree from module version"
288);
289
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300290int board_init(void)
291{
292 board_gpio_init();
293
Andrejs Cainikovs382e89c2023-01-16 20:05:12 +0100294 if (IS_ENABLED(CONFIG_IMX_SNVS_SEC_SC_AUTO)) {
295 int ret = snvs_security_sc_init();
296
297 if (ret)
298 return ret;
299 }
300
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300301 return 0;
302}
303
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300304/*
305 * Board specific reset that is system reset.
306 */
Harald Seiler35b65dd2020-12-15 16:47:52 +0100307void reset_cpu(void)
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300308{
309 /* TODO */
310}
311
312#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900313int ft_board_setup(void *blob, struct bd_info *bd)
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300314{
315 return ft_common_board_setup(blob, bd);
316}
317#endif
318
319int board_mmc_get_env_dev(int devno)
320{
321 return devno;
322}
323
324int board_late_init(void)
325{
326#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
327/* TODO move to common */
328 env_set("board_name", "Apalis iMX8QM");
329 env_set("board_rev", "v1.0");
330#endif
331
Marcel Ziswiler37630e02023-01-16 20:04:58 +0100332 build_info();
333
Marcel Ziswilerfe7b2b32023-01-16 20:04:56 +0100334 select_dt_from_module_version();
335
Marcel Ziswiler3d603662019-05-31 19:00:20 +0300336 return 0;
337}