blob: 6f28367cf0345a7653a9d1fbb819c63fc1e7be1d [file] [log] [blame]
Marcel Ziswiler475ceff2019-05-31 19:00:20 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Toradex
4 */
5
6#include <common.h>
Simon Glassafb02152019-12-28 10:45:01 -07007#include <cpu_func.h>
Simon Glassa7b51302019-11-14 12:57:46 -07008#include <init.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Marcel Ziswiler475ceff2019-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>
15#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{
87 sc_err_t sciErr;
88 u32 val_a = 0;
89 u32 val_b = 0;
90
91 sciErr = sc_misc_otp_fuse_read(-1, a, &val_a);
92 if (sciErr != SC_ERR_NONE) {
93 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);
98 if (sciErr != SC_ERR_NONE) {
99 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;
Igor Opaniuk96b90ba2020-10-22 11:21:41 +0300133 sc_err_t scierr = sc_misc_otp_fuse_read(-1, 6, &val);
134
135 if (scierr == SC_ERR_NONE) {
136 /* 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;
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300172 sc_err_t err = 0;
173
Anatolij Gustschinef156d22019-06-12 13:35:25 +0200174 /* Set UART1 clock root to 80 MHz and enable it */
175 err = sc_pm_setup_uart(SC_R_UART_1, rate);
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300176 if (err != SC_ERR_NONE)
177 return 0;
178
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 Ziswiler475ceff2019-05-31 19:00:20 +0300185static void board_gpio_init(void)
186{
187 /* TODO */
188}
189#else
190static inline void board_gpio_init(void) {}
191#endif
192
193#if IS_ENABLED(CONFIG_FEC_MXC)
194#include <miiphy.h>
195
196int board_phy_config(struct phy_device *phydev)
197{
198 if (phydev->drv->config)
199 phydev->drv->config(phydev);
200
201 return 0;
202}
203#endif
204
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300205int checkboard(void)
206{
207 puts("Model: Toradex Apalis iMX8\n");
208
209 build_info();
210 print_bootinfo();
211
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100212 return 0;
213}
214
215static enum pcb_rev_t get_pcb_revision(void)
216{
217 unsigned int pcb_vers = 0;
218
219 imx8_iomux_setup_multiple_pads(pcb_vers_detect,
220 ARRAY_SIZE(pcb_vers_detect));
221
222 gpio_request(IMX_GPIO_NR(1, 18),
223 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_00");
224 gpio_request(IMX_GPIO_NR(1, 19),
225 "PCB version detection on PAD SC_P_MIPI_DSI0_GPIO0_01");
226 gpio_direction_input(IMX_GPIO_NR(1, 18));
227 gpio_direction_input(IMX_GPIO_NR(1, 19));
228
229 udelay(1000);
230
231 pcb_vers = gpio_get_value(IMX_GPIO_NR(1, 18));
232 pcb_vers |= gpio_get_value(IMX_GPIO_NR(1, 19)) << 1;
233
234 /* Set muxing back to default values for saving energy */
235 imx8_iomux_setup_multiple_pads(pcb_vers_default,
236 ARRAY_SIZE(pcb_vers_default));
237
238 switch (pcb_vers) {
239 case 0b11:
240 return PCB_VERSION_1_0;
241 case 0b10:
242 return PCB_VERSION_1_1;
243 default:
244 printf("Unknown PCB version=0x%x, default to V1.1\n", pcb_vers);
245 return PCB_VERSION_1_1;
246 }
247}
248
249static void select_dt_from_module_version(void)
250{
251 env_set("soc", "imx8qm");
252 env_set("variant", "-v1.1");
253
254 switch (tdx_hw_tag.prodid) {
255 /* Select Apalis iMX8QM device trees */
256 case APALIS_IMX8QM_IT:
257 case APALIS_IMX8QM_WIFI_BT_IT:
258 case APALIS_IMX8QM_8GB_WIFI_BT_IT:
259 if (get_pcb_revision() == PCB_VERSION_1_0)
260 env_set("variant", "");
261 break;
262 /* Select Apalis iMX8QP device trees */
263 case APALIS_IMX8QP_WIFI_BT:
264 case APALIS_IMX8QP:
265 env_set("soc", "imx8qp");
266 break;
267 default:
268 printf("Unknown Apalis iMX8 module\n");
269 return;
270 }
271}
272
273static int do_select_dt_from_module_version(struct cmd_tbl *cmdtp, int flag,
274 int argc, char * const argv[])
275{
276 select_dt_from_module_version();
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300277 return 0;
278}
279
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100280U_BOOT_CMD(select_dt_from_module_version, CONFIG_SYS_MAXARGS, 1, do_select_dt_from_module_version,
281 "\n", " - select devicetree from module version"
282);
283
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300284int board_init(void)
285{
286 board_gpio_init();
287
288 return 0;
289}
290
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300291/*
292 * Board specific reset that is system reset.
293 */
Harald Seiler6f14d5f2020-12-15 16:47:52 +0100294void reset_cpu(void)
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300295{
296 /* TODO */
297}
298
299#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900300int ft_board_setup(void *blob, struct bd_info *bd)
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300301{
302 return ft_common_board_setup(blob, bd);
303}
304#endif
305
306int board_mmc_get_env_dev(int devno)
307{
308 return devno;
309}
310
311int board_late_init(void)
312{
313#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
314/* TODO move to common */
315 env_set("board_name", "Apalis iMX8QM");
316 env_set("board_rev", "v1.0");
317#endif
318
Marcel Ziswiler79d300c2023-01-16 20:04:56 +0100319 select_dt_from_module_version();
320
Marcel Ziswiler475ceff2019-05-31 19:00:20 +0300321 return 0;
322}