]>
Commit | Line | Data |
---|---|---|
c5752f73 AA |
1 | /* |
2 | * Copyright (C) 2015 Freescale Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <asm/io.h> | |
9 | #include <asm/arch/imx-regs.h> | |
10 | #include <asm/arch/clock.h> | |
11 | #include <asm/arch/sys_proto.h> | |
552a848e SB |
12 | #include <asm/mach-imx/boot_mode.h> |
13 | #include <asm/mach-imx/dma.h> | |
14 | #include <asm/mach-imx/hab.h> | |
15 | #include <asm/mach-imx/rdc-sema.h> | |
35c4ce5e | 16 | #include <asm/arch/imx-rdc.h> |
c5752f73 AA |
17 | #include <asm/arch/crm_regs.h> |
18 | #include <dm.h> | |
19 | #include <imx_thermal.h> | |
20 | ||
c5752f73 AA |
21 | #if defined(CONFIG_IMX_THERMAL) |
22 | static const struct imx_thermal_plat imx7_thermal_plat = { | |
23 | .regs = (void *)ANATOP_BASE_ADDR, | |
24 | .fuse_bank = 3, | |
25 | .fuse_word = 3, | |
26 | }; | |
27 | ||
28 | U_BOOT_DEVICE(imx7_thermal) = { | |
29 | .name = "imx_thermal", | |
30 | .platdata = &imx7_thermal_plat, | |
31 | }; | |
32 | #endif | |
33 | ||
e872f27a | 34 | #if CONFIG_IS_ENABLED(IMX_RDC) |
35c4ce5e PF |
35 | /* |
36 | * In current design, if any peripheral was assigned to both A7 and M4, | |
37 | * it will receive ipg_stop or ipg_wait when any of the 2 platforms enter | |
38 | * low power mode. So M4 sleep will cause some peripherals fail to work | |
39 | * at A7 core side. At default, all resources are in domain 0 - 3. | |
40 | * | |
41 | * There are 26 peripherals impacted by this IC issue: | |
42 | * SIM2(sim2/emvsim2) | |
43 | * SIM1(sim1/emvsim1) | |
44 | * UART1/UART2/UART3/UART4/UART5/UART6/UART7 | |
45 | * SAI1/SAI2/SAI3 | |
46 | * WDOG1/WDOG2/WDOG3/WDOG4 | |
47 | * GPT1/GPT2/GPT3/GPT4 | |
48 | * PWM1/PWM2/PWM3/PWM4 | |
49 | * ENET1/ENET2 | |
50 | * Software Workaround: | |
51 | * Here we setup some resources to domain 0 where M4 codes will move | |
52 | * the M4 out of this domain. Then M4 is not able to access them any longer. | |
53 | * This is a workaround for ic issue. So the peripherals are not shared | |
54 | * by them. This way requires the uboot implemented the RDC driver and | |
55 | * set the 26 IPs above to domain 0 only. M4 code will assign resource | |
56 | * to its own domain, if it want to use the resource. | |
57 | */ | |
58 | static rdc_peri_cfg_t const resources[] = { | |
59 | (RDC_PER_SIM1 | RDC_DOMAIN(0)), | |
60 | (RDC_PER_SIM2 | RDC_DOMAIN(0)), | |
61 | (RDC_PER_UART1 | RDC_DOMAIN(0)), | |
62 | (RDC_PER_UART2 | RDC_DOMAIN(0)), | |
63 | (RDC_PER_UART3 | RDC_DOMAIN(0)), | |
64 | (RDC_PER_UART4 | RDC_DOMAIN(0)), | |
65 | (RDC_PER_UART5 | RDC_DOMAIN(0)), | |
66 | (RDC_PER_UART6 | RDC_DOMAIN(0)), | |
67 | (RDC_PER_UART7 | RDC_DOMAIN(0)), | |
68 | (RDC_PER_SAI1 | RDC_DOMAIN(0)), | |
69 | (RDC_PER_SAI2 | RDC_DOMAIN(0)), | |
70 | (RDC_PER_SAI3 | RDC_DOMAIN(0)), | |
71 | (RDC_PER_WDOG1 | RDC_DOMAIN(0)), | |
72 | (RDC_PER_WDOG2 | RDC_DOMAIN(0)), | |
73 | (RDC_PER_WDOG3 | RDC_DOMAIN(0)), | |
74 | (RDC_PER_WDOG4 | RDC_DOMAIN(0)), | |
75 | (RDC_PER_GPT1 | RDC_DOMAIN(0)), | |
76 | (RDC_PER_GPT2 | RDC_DOMAIN(0)), | |
77 | (RDC_PER_GPT3 | RDC_DOMAIN(0)), | |
78 | (RDC_PER_GPT4 | RDC_DOMAIN(0)), | |
79 | (RDC_PER_PWM1 | RDC_DOMAIN(0)), | |
80 | (RDC_PER_PWM2 | RDC_DOMAIN(0)), | |
81 | (RDC_PER_PWM3 | RDC_DOMAIN(0)), | |
82 | (RDC_PER_PWM4 | RDC_DOMAIN(0)), | |
83 | (RDC_PER_ENET1 | RDC_DOMAIN(0)), | |
84 | (RDC_PER_ENET2 | RDC_DOMAIN(0)), | |
85 | }; | |
86 | ||
87 | static void isolate_resource(void) | |
88 | { | |
89 | imx_rdc_setup_peripherals(resources, ARRAY_SIZE(resources)); | |
90 | } | |
91 | #endif | |
92 | ||
bb955146 AA |
93 | #if defined(CONFIG_SECURE_BOOT) |
94 | struct imx_sec_config_fuse_t const imx_sec_config_fuse = { | |
95 | .bank = 1, | |
96 | .word = 3, | |
97 | }; | |
98 | #endif | |
99 | ||
e25a0656 FE |
100 | static bool is_mx7d(void) |
101 | { | |
102 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | |
103 | struct fuse_bank *bank = &ocotp->bank[1]; | |
104 | struct fuse_bank1_regs *fuse = | |
105 | (struct fuse_bank1_regs *)bank->fuse_regs; | |
106 | int val; | |
107 | ||
108 | val = readl(&fuse->tester4); | |
109 | if (val & 1) | |
110 | return false; | |
111 | else | |
112 | return true; | |
113 | } | |
114 | ||
c5752f73 AA |
115 | u32 get_cpu_rev(void) |
116 | { | |
117 | struct mxc_ccm_anatop_reg *ccm_anatop = (struct mxc_ccm_anatop_reg *) | |
118 | ANATOP_BASE_ADDR; | |
119 | u32 reg = readl(&ccm_anatop->digprog); | |
120 | u32 type = (reg >> 16) & 0xff; | |
121 | ||
e25a0656 FE |
122 | if (!is_mx7d()) |
123 | type = MXC_CPU_MX7S; | |
124 | ||
c5752f73 AA |
125 | reg &= 0xff; |
126 | return (type << 12) | reg; | |
127 | } | |
128 | ||
129 | #ifdef CONFIG_REVISION_TAG | |
130 | u32 __weak get_board_rev(void) | |
131 | { | |
132 | return get_cpu_rev(); | |
133 | } | |
134 | #endif | |
135 | ||
7de47036 PF |
136 | /* enable all periherial can be accessed in nosec mode */ |
137 | static void init_csu(void) | |
138 | { | |
139 | int i = 0; | |
140 | for (i = 0; i < CSU_NUM_REGS; i++) | |
141 | writel(CSU_INIT_SEC_LEVEL0, CSU_IPS_BASE_ADDR + i * 4); | |
142 | } | |
143 | ||
d9699de8 PF |
144 | static void imx_enet_mdio_fixup(void) |
145 | { | |
146 | struct iomuxc_gpr_base_regs *gpr_regs = | |
147 | (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR; | |
148 | ||
149 | /* | |
150 | * The management data input/output (MDIO) requires open-drain, | |
151 | * i.MX7D TO1.0 ENET MDIO pin has no open drain, but TO1.1 supports | |
152 | * this feature. So to TO1.1, need to enable open drain by setting | |
153 | * bits GPR0[8:7]. | |
154 | */ | |
155 | ||
156 | if (soc_rev() >= CHIP_REV_1_1) { | |
157 | setbits_le32(&gpr_regs->gpr[0], | |
158 | IOMUXC_GPR_GPR0_ENET_MDIO_OPEN_DRAIN_MASK); | |
159 | } | |
160 | } | |
161 | ||
c5752f73 AA |
162 | int arch_cpu_init(void) |
163 | { | |
164 | init_aips(); | |
165 | ||
7de47036 | 166 | init_csu(); |
c5752f73 | 167 | /* Disable PDE bit of WMCR register */ |
e2162d70 | 168 | imx_wdog_disable_powerdown(); |
c5752f73 | 169 | |
d9699de8 PF |
170 | imx_enet_mdio_fixup(); |
171 | ||
c5752f73 AA |
172 | #ifdef CONFIG_APBH_DMA |
173 | /* Start APBH DMA */ | |
174 | mxs_dma_init(); | |
175 | #endif | |
176 | ||
e872f27a PF |
177 | #if CONFIG_IS_ENABLED(IMX_RDC) |
178 | isolate_resource(); | |
179 | #endif | |
35c4ce5e | 180 | |
c5752f73 AA |
181 | return 0; |
182 | } | |
183 | ||
ec7fde3e SA |
184 | #ifdef CONFIG_ARCH_MISC_INIT |
185 | int arch_misc_init(void) | |
186 | { | |
187 | #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG | |
188 | if (is_mx7d()) | |
382bee57 | 189 | env_set("soc", "imx7d"); |
ec7fde3e | 190 | else |
382bee57 | 191 | env_set("soc", "imx7s"); |
ec7fde3e SA |
192 | #endif |
193 | ||
194 | return 0; | |
195 | } | |
196 | #endif | |
197 | ||
c5752f73 AA |
198 | #ifdef CONFIG_SERIAL_TAG |
199 | void get_board_serial(struct tag_serialnr *serialnr) | |
200 | { | |
201 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | |
202 | struct fuse_bank *bank = &ocotp->bank[0]; | |
203 | struct fuse_bank0_regs *fuse = | |
204 | (struct fuse_bank0_regs *)bank->fuse_regs; | |
205 | ||
206 | serialnr->low = fuse->tester0; | |
207 | serialnr->high = fuse->tester1; | |
208 | } | |
209 | #endif | |
210 | ||
c5752f73 AA |
211 | void set_wdog_reset(struct wdog_regs *wdog) |
212 | { | |
213 | u32 reg = readw(&wdog->wcr); | |
214 | /* | |
215 | * Output WDOG_B signal to reset external pmic or POR_B decided by | |
216 | * the board desgin. Without external reset, the peripherals/DDR/ | |
217 | * PMIC are not reset, that may cause system working abnormal. | |
218 | */ | |
219 | reg = readw(&wdog->wcr); | |
220 | reg |= 1 << 3; | |
221 | /* | |
222 | * WDZST bit is write-once only bit. Align this bit in kernel, | |
223 | * otherwise kernel code will have no chance to set this bit. | |
224 | */ | |
225 | reg |= 1 << 0; | |
226 | writew(reg, &wdog->wcr); | |
227 | } | |
228 | ||
229 | /* | |
230 | * cfg_val will be used for | |
231 | * Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0] | |
232 | * After reset, if GPR10[28] is 1, ROM will copy GPR9[25:0] | |
233 | * to SBMR1, which will determine the boot device. | |
234 | */ | |
235 | const struct boot_mode soc_boot_modes[] = { | |
236 | {"ecspi1:0", MAKE_CFGVAL(0x00, 0x60, 0x00, 0x00)}, | |
237 | {"ecspi1:1", MAKE_CFGVAL(0x40, 0x62, 0x00, 0x00)}, | |
238 | {"ecspi1:2", MAKE_CFGVAL(0x80, 0x64, 0x00, 0x00)}, | |
239 | {"ecspi1:3", MAKE_CFGVAL(0xc0, 0x66, 0x00, 0x00)}, | |
240 | ||
241 | {"weim", MAKE_CFGVAL(0x00, 0x50, 0x00, 0x00)}, | |
242 | {"qspi1", MAKE_CFGVAL(0x10, 0x40, 0x00, 0x00)}, | |
243 | /* 4 bit bus width */ | |
244 | {"usdhc1", MAKE_CFGVAL(0x10, 0x10, 0x00, 0x00)}, | |
245 | {"usdhc2", MAKE_CFGVAL(0x10, 0x14, 0x00, 0x00)}, | |
246 | {"usdhc3", MAKE_CFGVAL(0x10, 0x18, 0x00, 0x00)}, | |
247 | {"mmc1", MAKE_CFGVAL(0x10, 0x20, 0x00, 0x00)}, | |
248 | {"mmc2", MAKE_CFGVAL(0x10, 0x24, 0x00, 0x00)}, | |
249 | {"mmc3", MAKE_CFGVAL(0x10, 0x28, 0x00, 0x00)}, | |
250 | {NULL, 0}, | |
251 | }; | |
252 | ||
c5752f73 AA |
253 | void s_init(void) |
254 | { | |
255 | #if !defined CONFIG_SPL_BUILD | |
256 | /* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */ | |
257 | asm volatile( | |
258 | "mrc p15, 0, r0, c1, c0, 1\n" | |
259 | "orr r0, r0, #1 << 6\n" | |
260 | "mcr p15, 0, r0, c1, c0, 1\n"); | |
261 | #endif | |
262 | /* clock configuration. */ | |
263 | clock_init(); | |
264 | ||
265 | return; | |
266 | } | |
9f8fa184 PF |
267 | |
268 | void reset_misc(void) | |
269 | { | |
270 | #ifdef CONFIG_VIDEO_MXS | |
271 | lcdif_power_down(); | |
272 | #endif | |
273 | } | |
274 |