1
2
3
4
5
6#include <common.h>
7#include <cpu_func.h>
8#include <init.h>
9#include <asm/global_data.h>
10
11#include <asm/arch/clock.h>
12#include <asm/arch/imx8-pins.h>
13#include <asm/arch/iomux.h>
14#include <asm/arch/snvs_security_sc.h>
15#include <firmware/imx/sci/sci.h>
16#include <asm/arch/sys_proto.h>
17#include <asm/gpio.h>
18#include <asm/io.h>
19#include <command.h>
20#include <env.h>
21#include <errno.h>
22#include <linux/bitops.h>
23#include <linux/delay.h>
24#include <linux/libfdt.h>
25
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
35#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
50#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
55enum 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
70static 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
75struct tdx_user_fuses {
76 u16 pid4;
77 u16 vers;
78 u8 ramid;
79};
80
81static void setup_iomux_uart(void)
82{
83 imx8_iomux_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
84}
85
86static 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
116
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
127void 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;
133 struct tdx_user_fuses tdxramfuses;
134 sc_err_t scierr = sc_misc_otp_fuse_read(-1, 6, &val);
135
136 if (scierr == SC_ERR_NONE) {
137
138 is_quadplus = ((val >> 4) & 0x3) != 0x0;
139 }
140
141 get_tdx_user_fuse(&tdxramfuses);
142
143 *phys_sdram_1_start = PHYS_SDRAM_1;
144 *phys_sdram_1_size = PHYS_SDRAM_1_SIZE;
145 *phys_sdram_2_start = PHYS_SDRAM_2;
146
147 switch (tdxramfuses.ramid) {
148 case 1:
149 *phys_sdram_2_size = SZ_2G;
150 break;
151 case 2:
152 *phys_sdram_2_size = 0x0UL;
153 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
163 *phys_sdram_2_size = 0x0UL;
164 else
165 *phys_sdram_2_size = PHYS_SDRAM_2_SIZE;
166 break;
167 }
168}
169
170int board_early_init_f(void)
171{
172 sc_pm_clock_rate_t rate = SC_80MHZ;
173 int ret;
174
175
176 ret = sc_pm_setup_uart(SC_R_UART_1, rate);
177 if (ret)
178 return ret;
179
180 setup_iomux_uart();
181
182 return 0;
183}
184
185#if CONFIG_IS_ENABLED(DM_GPIO)
186
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
193static void board_gpio_init(void)
194{
195 imx8_iomux_setup_multiple_pads(board_gpios, ARRAY_SIZE(board_gpios));
196
197 gpio_request(BKL1_GPIO, "BKL1_GPIO");
198}
199#else
200static inline void board_gpio_init(void) {}
201#endif
202
203
204
205
206void board_preboot_os(void)
207{
208 gpio_direction_output(BKL1_GPIO, 0);
209}
210
211int checkboard(void)
212{
213 puts("Model: Toradex Apalis iMX8\n");
214
215 build_info();
216 print_bootinfo();
217
218 return 0;
219}
220
221static 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
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
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
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
290int board_init(void)
291{
292 board_gpio_init();
293
294 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
301 return 0;
302}
303
304
305
306
307void reset_cpu(void)
308{
309
310}
311
312#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
313int ft_board_setup(void *blob, struct bd_info *bd)
314{
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
328 env_set("board_name", "Apalis iMX8QM");
329 env_set("board_rev", "v1.0");
330#endif
331
332 build_info();
333
334 select_dt_from_module_version();
335
336 return 0;
337}
338