blob: 72d67d90d418306d605c05735a97dbcf25f01d4f [file] [log] [blame]
Marcel Ziswiler475ceff2019-05-31 19:00:20 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Toradex
4 */
5
Simon Glassafb02152019-12-28 10:45:01 -07006#include <cpu_func.h>
Simon Glassa7b51302019-11-14 12:57:46 -07007#include <init.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06008#include <asm/global_data.h>
Marcel Ziswiler475ceff2019-05-31 19:00:20 +03009
10#include <asm/arch/clock.h>
11#include <asm/arch/imx8-pins.h>
12#include <asm/arch/iomux.h>
Andrejs Cainikovsfa7327f2023-01-16 20:05:12 +010013#include <asm/arch/snvs_security_sc.h>
Peng Fan2e0644a2023-04-28 12:08:09 +080014#include <firmware/imx/sci/sci.h>
Marcel Ziswiler475ceff2019-05-31 19:00:20 +030015#include <asm/arch/sys_proto.h>
16#include <asm/gpio.h>
17#include <asm/io.h>
Marcel Ziswiler79d300c2023-01-16 20:04:56 +010018#include <command.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060019#include <env.h>
Marcel Ziswiler475ceff2019-05-31 19:00:20 +030020#include <errno.h>
Philippe Schenker0e2980d2022-05-09 18:58:16 +020021#include <linux/bitops.h>
Marcel Ziswiler79d300c2023-01-16 20:04:56 +010022#include <linux/delay.h>
23#include <linux/libfdt.h>
Marcel Ziswiler475ceff2019-05-31 19:00:20 +030024
25#include "../common/tdx-cfg-block.h"
26
27DECLARE_GLOBAL_DATA_PTR;
28
29#define UART_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
30 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
31 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
32 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
33
Marcel Ziswiler79d300c2023-01-16 20:04:56 +010034#define PCB_VERS_DETECT ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
35 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
36 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
37 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
38
39#define GPIO_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
40 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
41 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
42 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
43
44#define PCB_VERS_DEFAULT ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
45 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
46 (SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT) | \
47 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT))
48
Philippe Schenker0e2980d2022-05-09 18:58:16 +020049#define TDX_USER_FUSE_BLOCK1_A 276
50#define TDX_USER_FUSE_BLOCK1_B 277
51#define TDX_USER_FUSE_BLOCK2_A 278
52#define TDX_USER_FUSE_BLOCK2_B 279
53
Marcel Ziswiler79d300c2023-01-16 20:04:56 +010054enum pcb_rev_t {
55 PCB_VERSION_1_0,
56 PCB_VERSION_1_1
57};
58
59static iomux_cfg_t pcb_vers_detect[] = {
60 SC_P_MIPI_DSI0_GPIO0_00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DETECT),
61 SC_P_MIPI_DSI0_GPIO0_01 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DETECT),
62};
63
64static iomux_cfg_t pcb_vers_default[] = {
65 SC_P_MIPI_DSI0_GPIO0_00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DEFAULT),
66 SC_P_MIPI_DSI0_GPIO0_01 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(PCB_VERS_DEFAULT),
67};
68
Marcel Ziswiler475ceff2019-05-31 19:00:20 +030069static iomux_cfg_t uart1_pads[] = {
70 SC_P_UART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
71 SC_P_UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
72};
73
Philippe Schenker0e2980d2022-05-09 18:58:16 +020074struct tdx_user_fuses {
75 u16 pid4;
76 u16 vers;
77 u8 ramid;
78};
79
Marcel Ziswiler475ceff2019-05-31 19:00:20 +030080static void setup_iomux_uart(void)
81{
82 imx8_iomux_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
83}
84
Philippe Schenker0e2980d2022-05-09 18:58:16 +020085static uint32_t do_get_tdx_user_fuse(int a, int b)
86{
Peng Fane24d0aa2023-06-15 18:08:59 +080087 int sciErr;
Philippe Schenker0e2980d2022-05-09 18:58:16 +020088 u32 val_a = 0;
89 u32 val_b = 0;
90
91 sciErr = sc_misc_otp_fuse_read(-1, a, &val_a);
Peng Fane24d0aa2023-06-15 18:08:59 +080092 if (sciErr) {
Philippe Schenker0e2980d2022-05-09 18:58:16 +020093 printf("Error reading out user fuse %d\n", a);
94 return 0;
95 }
96
97 sciErr = sc_misc_otp_fuse_read(-1, b, &val_b);
Peng Fane24d0aa2023-06-15 18:08:59 +080098 if (sciErr) {
Philippe Schenker0e2980d2022-05-09 18:58:16 +020099 printf("Error reading out user fuse %d\n", b);
100 return 0;
101 }
102
103 return ((val_a & 0xffff) << 16) | (val_b & 0xffff);
104}
105
106static void get_tdx_user_fuse(struct tdx_user_fuses *tdxuserfuse)
107{
108 u32 fuse_block;
109
110 fuse_block = do_get_tdx_user_fuse(TDX_USER_FUSE_BLOCK2_A,
111 TDX_USER_FUSE_BLOCK2_B);
112
113 /*
114 * Fuse block 2 acts as a backup area, if this reads 0 we want to
115 * use fuse block 1
116 */
117 if (fuse_block == 0)
118 fuse_block = do_get_tdx_user_fuse(TDX_USER_FUSE_BLOCK1_A,
119 TDX_USER_FUSE_BLOCK1_B);
120
121 tdxuserfuse->pid4 = (fuse_block >> 18) & GENMASK(13, 0);
122 tdxuserfuse->vers = (fuse_block >> 4) & GENMASK(13, 0);
123 tdxuserfuse->ramid = fuse_block & GENMASK(3, 0);
124}
125
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300126void board_mem_get_layout(u64 *phys_sdram_1_start,
127 u64 *phys_sdram_1_size,
128 u64 *phys_sdram_2_start,
129 u64 *phys_sdram_2_size)
130{
131 u32 is_quadplus = 0, val = 0;
Philippe Schenker0e2980d2022-05-09 18:58:16 +0200132 struct tdx_user_fuses tdxramfuses;
Peng Fane24d0aa2023-06-15 18:08:59 +0800133 int scierr = sc_misc_otp_fuse_read(-1, 6, &val);
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300134
Fabio Estevam0cada442024-03-12 21:59:41 -0300135 if (!scierr) {
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300136 /* QP has one A72 core disabled */
137 is_quadplus = ((val >> 4) & 0x3) != 0x0;
138 }
139
Philippe Schenker0e2980d2022-05-09 18:58:16 +0200140 get_tdx_user_fuse(&tdxramfuses);
141
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300142 *phys_sdram_1_start = PHYS_SDRAM_1;
143 *phys_sdram_1_size = PHYS_SDRAM_1_SIZE;
144 *phys_sdram_2_start = PHYS_SDRAM_2;
Philippe Schenker0e2980d2022-05-09 18:58:16 +0200145
146 switch (tdxramfuses.ramid) {
147 case 1:
148 *phys_sdram_2_size = SZ_2G;
149 break;
150 case 2:
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300151 *phys_sdram_2_size = 0x0UL;
Philippe Schenker0e2980d2022-05-09 18:58:16 +0200152 break;
153 case 3:
154 *phys_sdram_2_size = SZ_2G;
155 break;
156 case 4:
157 *phys_sdram_2_size = SZ_4G + SZ_2G;
158 break;
159 default:
160 if (is_quadplus)
161 /* Our QP based SKUs only have 2 GB RAM (PHYS_SDRAM_1_SIZE) */
162 *phys_sdram_2_size = 0x0UL;
163 else
164 *phys_sdram_2_size = PHYS_SDRAM_2_SIZE;
165 break;
166 }
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300167}
168
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300169int board_early_init_f(void)
170{
Anatolij Gustschinef156d22019-06-12 13:35:25 +0200171 sc_pm_clock_rate_t rate = SC_80MHZ;
Philippe Schenker8ae977ce2023-01-16 20:05:10 +0100172 int ret;
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300173
Anatolij Gustschinef156d22019-06-12 13:35:25 +0200174 /* Set UART1 clock root to 80 MHz and enable it */
Philippe Schenker8ae977ce2023-01-16 20:05:10 +0100175 ret = sc_pm_setup_uart(SC_R_UART_1, rate);
176 if (ret)
177 return ret;
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300178
179 setup_iomux_uart();
180
181 return 0;
182}
183
Simon Glassfa4689a2019-12-06 21:41:35 -0700184#if CONFIG_IS_ENABLED(DM_GPIO)
Marcel Ziswilerd5ee5f82023-01-16 20:04:57 +0100185
186#define BKL1_GPIO IMX_GPIO_NR(1, 10)
187
188static iomux_cfg_t board_gpios[] = {
189 SC_P_LVDS1_GPIO00 | MUX_MODE_ALT(3) | MUX_PAD_CTRL(GPIO_PAD_CTRL),
190};
191
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300192static void board_gpio_init(void)
193{
Marcel Ziswilerd5ee5f82023-01-16 20:04:57 +0100194 imx8_iomux_setup_multiple_pads(board_gpios, ARRAY_SIZE(board_gpios));
195
196 gpio_request(BKL1_GPIO, "BKL1_GPIO");
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300197}
198#else
199static inline void board_gpio_init(void) {}
200#endif
201
Marcel Ziswilerd5ee5f82023-01-16 20:04:57 +0100202/*
203 * Backlight off before OS handover
204 */
205void board_preboot_os(void)
206{
207 gpio_direction_output(BKL1_GPIO, 0);
208}
209
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100210static enum pcb_rev_t get_pcb_revision(void)
211{
212 unsigned int pcb_vers = 0;
213
214 imx8_iomux_setup_multiple_pads(pcb_vers_detect,
215 ARRAY_SIZE(pcb_vers_detect));
216
217 gpio_request(IMX_GPIO_NR(1, 18),
218 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_00");
219 gpio_request(IMX_GPIO_NR(1, 19),
220 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_01");
221 gpio_direction_input(IMX_GPIO_NR(1, 18));
222 gpio_direction_input(IMX_GPIO_NR(1, 19));
223
224 udelay(1000);
225
226 pcb_vers = gpio_get_value(IMX_GPIO_NR(1, 18));
227 pcb_vers |= gpio_get_value(IMX_GPIO_NR(1, 19)) << 1;
228
229 /* Set muxing back to default values for saving energy */
230 imx8_iomux_setup_multiple_pads(pcb_vers_default,
231 ARRAY_SIZE(pcb_vers_default));
232
233 switch (pcb_vers) {
234 case 0b11:
235 return PCB_VERSION_1_0;
236 case 0b10:
237 return PCB_VERSION_1_1;
238 default:
239 printf("Unknown PCB version=0x%x, default to V1.1\n", pcb_vers);
240 return PCB_VERSION_1_1;
241 }
242}
243
244static void select_dt_from_module_version(void)
245{
246 env_set("soc", "imx8qm");
247 env_set("variant", "-v1.1");
248
249 switch (tdx_hw_tag.prodid) {
250 /* Select Apalis iMX8QM device trees */
251 case APALIS_IMX8QM_IT:
252 case APALIS_IMX8QM_WIFI_BT_IT:
253 case APALIS_IMX8QM_8GB_WIFI_BT_IT:
254 if (get_pcb_revision() == PCB_VERSION_1_0)
255 env_set("variant", "");
256 break;
257 /* Select Apalis iMX8QP device trees */
258 case APALIS_IMX8QP_WIFI_BT:
259 case APALIS_IMX8QP:
260 env_set("soc", "imx8qp");
261 break;
262 default:
263 printf("Unknown Apalis iMX8 module\n");
264 return;
265 }
266}
267
268static int do_select_dt_from_module_version(struct cmd_tbl *cmdtp, int flag,
269 int argc, char * const argv[])
270{
271 select_dt_from_module_version();
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300272 return 0;
273}
274
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100275U_BOOT_CMD(select_dt_from_module_version, CONFIG_SYS_MAXARGS, 1, do_select_dt_from_module_version,
276 "\n", " - select devicetree from module version"
277);
278
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300279int board_init(void)
280{
281 board_gpio_init();
282
Andrejs Cainikovsfa7327f2023-01-16 20:05:12 +0100283 if (IS_ENABLED(CONFIG_IMX_SNVS_SEC_SC_AUTO)) {
284 int ret = snvs_security_sc_init();
285
286 if (ret)
287 return ret;
288 }
289
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300290 return 0;
291}
292
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300293#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900294int ft_board_setup(void *blob, struct bd_info *bd)
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300295{
296 return ft_common_board_setup(blob, bd);
297}
298#endif
299
300int board_mmc_get_env_dev(int devno)
301{
302 return devno;
303}
304
305int board_late_init(void)
306{
307#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
308/* TODO move to common */
309 env_set("board_name", "Apalis iMX8QM");
310 env_set("board_rev", "v1.0");
311#endif
312
Marcel Ziswiler28c817f2023-01-16 20:04:58 +0100313 build_info();
314
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100315 select_dt_from_module_version();
316
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300317 return 0;
318}