Commit cdab22ac02ba4a2f9d2df4518695a5322b97c569
Committed by
guoyin.chen
1 parent
22338e28ca
Exists in
smarc-imx_v2015.04_4.1.15_1.0.0_ga
and in
1 other branch
MLK-12483-3 mx6: Add a module fuse checking
Implement a functionality to read the soc fuses and check if any module is fused. For fused module, we have to disable it in u-boot dynamically, and change the its node in FDT to "disabled" status before starting the kernel. In this patch, we implement the ft_system_setup for FDT fixup. This function will be called during boot process or by "fdt systemsetup" command. To enable the module fuse checking, two configurations must be defined: CONFIG_MODULE_FUSE CONFIG_OF_SYSTEM_SETUP Signed-off-by: Ye Li <ye.li@nxp.com> (cherry picked from commit 2bce02298d755af0ef7b2aaecc56bcebc1fda61b)
Showing 4 changed files with 385 additions and 0 deletions Side-by-side Diff
arch/arm/cpu/armv7/mx6/Makefile
arch/arm/cpu/armv7/mx6/module_fuse.c
1 | +/* | |
2 | + * (C) Copyright 2016 Freescale Semiconductor, Inc. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <fdt_support.h> | |
9 | +#include <asm/io.h> | |
10 | +#include <asm/errno.h> | |
11 | +#include <asm/arch/sys_proto.h> | |
12 | +#include <asm/arch/imx-regs.h> | |
13 | +#include <asm/arch/module_fuse.h> | |
14 | + | |
15 | +struct fuse_entry_desc { | |
16 | + enum fuse_module_type module; | |
17 | + const char* node_path; | |
18 | + u32 fuse_word_offset; | |
19 | + u32 fuse_bit_offset; | |
20 | + u32 status; | |
21 | +}; | |
22 | + | |
23 | +static struct fuse_entry_desc mx6_fuse_descs[] = { | |
24 | +#ifdef CONFIG_MX6UL | |
25 | + {MX6_MODULE_TSC, "/soc/aips-bus@02000000/tsc@02040000", 0x430, 22}, | |
26 | + {MX6_MODULE_ADC2, "/soc/aips-bus@02100000/adc@0219c000", 0x430, 23}, | |
27 | + {MX6_MODULE_SIM1, "/soc/aips-bus@02100000/sim@0218c000", 0x430, 24}, | |
28 | + {MX6_MODULE_SIM2, "/soc/aips-bus@02100000/sim@021b4000", 0x430, 25}, | |
29 | + {MX6_MODULE_FLEXCAN1, "/soc/aips-bus@02000000/can@02090000", 0x430, 26}, | |
30 | + {MX6_MODULE_FLEXCAN2, "/soc/aips-bus@02000000/can@02094000", 0x430, 27}, | |
31 | + {MX6_MODULE_SPDIF, "/soc/aips-bus@02000000/spba-bus@02000000/spdif@02004000", 0x440, 2}, | |
32 | + {MX6_MODULE_EIM, "/soc/aips-bus@02100000/weim@021b8000", 0x440, 3}, | |
33 | + {MX6_MODULE_SD1, "/soc/aips-bus@02100000/usdhc@02190000", 0x440, 4}, | |
34 | + {MX6_MODULE_SD2, "/soc/aips-bus@02100000/usdhc@02194000", 0x440, 5}, | |
35 | + {MX6_MODULE_QSPI1, "/soc/aips-bus@02100000/qspi@021e0000", 0x440, 6}, | |
36 | + {MX6_MODULE_GPMI, "/soc/gpmi-nand@01806000", 0x440, 7}, | |
37 | + {MX6_MODULE_APBHDMA, "/soc/dma-apbh@01804000", 0x440, 7}, | |
38 | + {MX6_MODULE_LCDIF, "/soc/aips-bus@02100000/lcdif@021c8000", 0x440, 8}, | |
39 | + {MX6_MODULE_PXP, "/soc/aips-bus@02100000/pxp@021cc000", 0x440, 9}, | |
40 | + {MX6_MODULE_CSI, "/soc/aips-bus@02100000/csi@021c4000", 0x440, 10}, | |
41 | + {MX6_MODULE_ADC1, "/soc/aips-bus@02100000/adc@02198000", 0x440, 11}, | |
42 | + {MX6_MODULE_ENET1, "/soc/aips-bus@02100000/ethernet@02188000", 0x440, 12}, | |
43 | + {MX6_MODULE_ENET2, "/soc/aips-bus@02000000/ethernet@020b4000", 0x440, 13}, | |
44 | + {MX6_MODULE_CAAM, "/soc/aips-bus@02100000/caam@2140000", 0x440, 14}, | |
45 | + {MX6_MODULE_USB_OTG2, "/soc/aips-bus@02100000/usb@02184200", 0x440, 15}, | |
46 | + {MX6_MODULE_SAI2, "/soc/aips-bus@02000000/spba-bus@02000000/sai@0202c000", 0x440, 24}, | |
47 | + {MX6_MODULE_SAI3, "/soc/aips-bus@02000000/spba-bus@02000000/sai@02030000", 0x440, 24}, | |
48 | + {MX6_MODULE_BEE, "/soc/aips-bus@02000000/bee@02044000", 0x440, 25}, | |
49 | + {MX6_MODULE_UART5, "/soc/aips-bus@02100000/serial@021f4000", 0x440, 26}, | |
50 | + {MX6_MODULE_UART6, "/soc/aips-bus@02100000/serial@021fc000", 0x440, 26}, | |
51 | + {MX6_MODULE_UART7, "/soc/aips-bus@02000000/spba-bus@02000000/serial@02018000", 0x440, 26}, | |
52 | + {MX6_MODULE_UART8, "/soc/aips-bus@02000000/spba-bus@02000000/serial@02024000", 0x440, 26}, | |
53 | + {MX6_MODULE_PWM5, "/soc/aips-bus@02000000/pwm@020f0000", 0x440, 27}, | |
54 | + {MX6_MODULE_PWM6, "/soc/aips-bus@02000000/pwm@020f4000", 0x440, 27}, | |
55 | + {MX6_MODULE_PWM7, "/soc/aips-bus@02000000/pwm@020f8000", 0x440, 27}, | |
56 | + {MX6_MODULE_PWM8, "/soc/aips-bus@02000000/pwm@020fc000", 0x440, 27}, | |
57 | + {MX6_MODULE_ECSPI3, "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000", 0x440, 28}, | |
58 | + {MX6_MODULE_ECSPI4, "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02014000", 0x440, 28}, | |
59 | + {MX6_MODULE_I2C3, "/soc/aips-bus@02100000/i2c@021a8000", 0x440, 29}, | |
60 | + {MX6_MODULE_I2C4, "/soc/aips-bus@02100000/i2c@021f8000", 0x440, 29}, | |
61 | + {MX6_MODULE_GPT2, "/soc/aips-bus@02000000/gpt@020e8000", 0x440, 30}, | |
62 | + {MX6_MODULE_EPIT2, "/soc/aips-bus@02000000/epit@020d4000", 0x440, 31}, | |
63 | +#endif | |
64 | +}; | |
65 | + | |
66 | +u32 check_module_fused(enum fuse_module_type module) | |
67 | +{ | |
68 | + u32 i, reg; | |
69 | + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) { | |
70 | + if (mx6_fuse_descs[i].module == module) { | |
71 | + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset); | |
72 | + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset)) | |
73 | + return 1; /* disabled */ | |
74 | + else | |
75 | + return 0; /* enabled */ | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + return 0; /* Not has a fuse, always enabled */ | |
80 | +} | |
81 | + | |
82 | +#ifdef DEBUG | |
83 | +void print_fuse_status() | |
84 | +{ | |
85 | + u32 i, reg; | |
86 | + | |
87 | + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) { | |
88 | + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset); | |
89 | + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset)) { | |
90 | + printf("%s, disabled\n", mx6_fuse_descs[i].node_path); | |
91 | + } | |
92 | + } | |
93 | +} | |
94 | + | |
95 | +void simulate_fuse() | |
96 | +{ | |
97 | + u32 i, reg; | |
98 | + | |
99 | + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) { | |
100 | + if (MX6_MODULE_SD2 == mx6_fuse_descs[i].module) | |
101 | + continue; | |
102 | + | |
103 | + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset); | |
104 | + reg |= (1 << mx6_fuse_descs[i].fuse_bit_offset); | |
105 | + writel(reg, OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset); | |
106 | + } | |
107 | +} | |
108 | +#endif | |
109 | + | |
110 | +#ifdef CONFIG_OF_SYSTEM_SETUP | |
111 | +int ft_system_setup(void *blob, bd_t *bd) | |
112 | +{ | |
113 | + u32 i, reg; | |
114 | + const char *status = "disabled"; | |
115 | + int rc; | |
116 | + | |
117 | + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) { | |
118 | + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset); | |
119 | + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset)) { | |
120 | + | |
121 | + int nodeoff = fdt_path_offset(blob, mx6_fuse_descs[i].node_path); | |
122 | + if (nodeoff < 0) | |
123 | + continue; /* Not found, skip it */ | |
124 | +add_status: | |
125 | + rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1); | |
126 | + if (rc) { | |
127 | + if (rc == -FDT_ERR_NOSPACE) { | |
128 | + rc = fdt_increase_size(blob, 512); | |
129 | + if (!rc) | |
130 | + goto add_status; | |
131 | + } | |
132 | + printf("Unable to update property %s:%s, err=%s\n", | |
133 | + mx6_fuse_descs[i].node_path, "status", fdt_strerror(rc)); | |
134 | + } else { | |
135 | + printf("Modify %s:%s disabled\n", | |
136 | + mx6_fuse_descs[i].node_path, "status"); | |
137 | + } | |
138 | + } | |
139 | + } | |
140 | + | |
141 | + printf("ft_system_setup for mx6\n"); | |
142 | + | |
143 | + return 0; | |
144 | +} | |
145 | +#endif | |
146 | + | |
147 | +u32 mx6_esdhc_fused(u32 base_addr) | |
148 | +{ | |
149 | + switch (base_addr) { | |
150 | + case USDHC1_BASE_ADDR: | |
151 | + return check_module_fused(MX6_MODULE_SD1); | |
152 | + case USDHC2_BASE_ADDR: | |
153 | + return check_module_fused(MX6_MODULE_SD2); | |
154 | +#ifdef USDHC3_BASE_ADDR | |
155 | + case USDHC3_BASE_ADDR: | |
156 | + return check_module_fused(MX6_MODULE_SD3); | |
157 | +#endif | |
158 | +#ifdef USDHC4_BASE_ADDR | |
159 | + case USDHC4_BASE_ADDR: | |
160 | + return check_module_fused(MX6_MODULE_SD4); | |
161 | +#endif | |
162 | + default: | |
163 | + return 0; | |
164 | + } | |
165 | +} | |
166 | + | |
167 | +u32 mx6_ecspi_fused(u32 base_addr) | |
168 | +{ | |
169 | + switch (base_addr) { | |
170 | + case ECSPI1_BASE_ADDR: | |
171 | + return check_module_fused(MX6_MODULE_ECSPI1); | |
172 | + case ECSPI2_BASE_ADDR: | |
173 | + return check_module_fused(MX6_MODULE_ECSPI2); | |
174 | + case ECSPI3_BASE_ADDR: | |
175 | + return check_module_fused(MX6_MODULE_ECSPI3); | |
176 | + case ECSPI4_BASE_ADDR: | |
177 | + return check_module_fused(MX6_MODULE_ECSPI4); | |
178 | +#ifdef ECSPI5_BASE_ADDR | |
179 | + case ECSPI5_BASE_ADDR: | |
180 | + return check_module_fused(MX6_MODULE_ECSPI5); | |
181 | +#endif | |
182 | + default: | |
183 | + return 0; | |
184 | + } | |
185 | +} | |
186 | + | |
187 | +u32 mx6_uart_fused(u32 base_addr) | |
188 | +{ | |
189 | + switch (base_addr) { | |
190 | + case UART1_BASE: | |
191 | + return check_module_fused(MX6_MODULE_UART1); | |
192 | + case UART2_BASE: | |
193 | + return check_module_fused(MX6_MODULE_UART2); | |
194 | + case UART3_BASE: | |
195 | + return check_module_fused(MX6_MODULE_UART3); | |
196 | + case UART4_BASE: | |
197 | + return check_module_fused(MX6_MODULE_UART4); | |
198 | + case UART5_BASE: | |
199 | + return check_module_fused(MX6_MODULE_UART5); | |
200 | +#ifdef UART6_BASE_ADDR | |
201 | + case UART6_BASE_ADDR: | |
202 | + return check_module_fused(MX6_MODULE_UART6); | |
203 | +#endif | |
204 | +#ifdef UART7_IPS_BASE_ADDR | |
205 | + case UART7_IPS_BASE_ADDR: | |
206 | + return check_module_fused(MX6_MODULE_UART7); | |
207 | +#endif | |
208 | +#ifdef UART8_IPS_BASE_ADDR | |
209 | + case UART8_IPS_BASE_ADDR: | |
210 | + return check_module_fused(MX6_MODULE_UART8); | |
211 | +#endif | |
212 | + } | |
213 | + | |
214 | + return 0; | |
215 | +} | |
216 | + | |
217 | +u32 mx6_usb_fused(u32 base_addr) | |
218 | +{ | |
219 | + int i = (base_addr - USB_BASE_ADDR) / 0x200; | |
220 | + return check_module_fused(MX6_MODULE_USB_OTG1 + i); | |
221 | +} | |
222 | + | |
223 | +u32 mx6_qspi_fused(u32 base_addr) | |
224 | +{ | |
225 | + switch (base_addr) { | |
226 | +#ifdef QSPI1_BASE_ADDR | |
227 | + case QSPI1_BASE_ADDR: | |
228 | + return check_module_fused(MX6_MODULE_QSPI1); | |
229 | +#endif | |
230 | + | |
231 | +#ifdef QSPI2_BASE_ADDR | |
232 | + case QSPI2_BASE_ADDR: | |
233 | + return check_module_fused(MX6_MODULE_QSPI2); | |
234 | +#endif | |
235 | + default: | |
236 | + return 0; | |
237 | + } | |
238 | +} | |
239 | + | |
240 | +u32 mx6_i2c_fused(u32 base_addr) | |
241 | +{ | |
242 | + switch (base_addr) { | |
243 | + case I2C1_BASE_ADDR: | |
244 | + return check_module_fused(MX6_MODULE_I2C1); | |
245 | + case I2C2_BASE_ADDR: | |
246 | + return check_module_fused(MX6_MODULE_I2C2); | |
247 | + case I2C3_BASE_ADDR: | |
248 | + return check_module_fused(MX6_MODULE_I2C3); | |
249 | +#ifdef I2C4_BASE_ADDR | |
250 | + case I2C4_BASE_ADDR: | |
251 | + return check_module_fused(MX6_MODULE_I2C4); | |
252 | +#endif | |
253 | + } | |
254 | + | |
255 | + return 0; | |
256 | +} | |
257 | + | |
258 | +u32 mx6_enet_fused(u32 base_addr) | |
259 | +{ | |
260 | + switch (base_addr) { | |
261 | + case ENET_BASE_ADDR: | |
262 | + return check_module_fused(MX6_MODULE_ENET1); | |
263 | +#ifdef ENET2_BASE_ADDR | |
264 | + case ENET2_BASE_ADDR: | |
265 | + return check_module_fused(MX6_MODULE_ENET2); | |
266 | +#endif | |
267 | + default: | |
268 | + return 0; | |
269 | + } | |
270 | +} |
arch/arm/include/asm/arch-mx6/module_fuse.h
1 | +/* | |
2 | + * Copyright (C) 2011 Freescale Semiconductor, Inc. | |
3 | + */ | |
4 | + | |
5 | +/* | |
6 | + * SPDX-License-Identifier: GPL-2.0+ | |
7 | + */ | |
8 | + | |
9 | +#ifndef __MODULE_FUSE_H__ | |
10 | +#define __MODULE_FUSE_H__ | |
11 | + | |
12 | +enum fuse_module_type{ | |
13 | + MX6_MODULE_TSC, | |
14 | + MX6_MODULE_ADC1, | |
15 | + MX6_MODULE_ADC2, | |
16 | + MX6_MODULE_SIM1, | |
17 | + MX6_MODULE_SIM2, | |
18 | + MX6_MODULE_FLEXCAN1, | |
19 | + MX6_MODULE_FLEXCAN2, | |
20 | + MX6_MODULE_SPDIF, | |
21 | + MX6_MODULE_EIM, | |
22 | + MX6_MODULE_SD1, | |
23 | + MX6_MODULE_SD2, | |
24 | + MX6_MODULE_SD3, | |
25 | + MX6_MODULE_SD4, | |
26 | + MX6_MODULE_QSPI1, | |
27 | + MX6_MODULE_QSPI2, | |
28 | + MX6_MODULE_GPMI, | |
29 | + MX6_MODULE_APBHDMA, | |
30 | + MX6_MODULE_LCDIF, | |
31 | + MX6_MODULE_PXP, | |
32 | + MX6_MODULE_CSI, | |
33 | + MX6_MODULE_ENET1, | |
34 | + MX6_MODULE_ENET2, | |
35 | + MX6_MODULE_CAAM, | |
36 | + MX6_MODULE_USB_OTG1, | |
37 | + MX6_MODULE_USB_OTG2, | |
38 | + MX6_MODULE_SAI2, | |
39 | + MX6_MODULE_SAI3, | |
40 | + MX6_MODULE_BEE, | |
41 | + MX6_MODULE_UART1, | |
42 | + MX6_MODULE_UART2, | |
43 | + MX6_MODULE_UART3, | |
44 | + MX6_MODULE_UART4, | |
45 | + MX6_MODULE_UART5, | |
46 | + MX6_MODULE_UART6, | |
47 | + MX6_MODULE_UART7, | |
48 | + MX6_MODULE_UART8, | |
49 | + MX6_MODULE_PWM5, | |
50 | + MX6_MODULE_PWM6, | |
51 | + MX6_MODULE_PWM7, | |
52 | + MX6_MODULE_PWM8, | |
53 | + MX6_MODULE_ECSPI1, | |
54 | + MX6_MODULE_ECSPI2, | |
55 | + MX6_MODULE_ECSPI3, | |
56 | + MX6_MODULE_ECSPI4, | |
57 | + MX6_MODULE_ECSPI5, | |
58 | + MX6_MODULE_I2C1, | |
59 | + MX6_MODULE_I2C2, | |
60 | + MX6_MODULE_I2C3, | |
61 | + MX6_MODULE_I2C4, | |
62 | + MX6_MODULE_GPT1, | |
63 | + MX6_MODULE_GPT2, | |
64 | + MX6_MODULE_EPIT1, | |
65 | + MX6_MODULE_EPIT2, | |
66 | +}; | |
67 | + | |
68 | +#if !defined(CONFIG_MODULE_FUSE) | |
69 | +static inline u32 check_module_fused(enum fuse_module_type module) { | |
70 | + return 0; | |
71 | +}; | |
72 | + | |
73 | +static inline u32 mx6_esdhc_fused(u32 base_addr) { | |
74 | + return 0; | |
75 | +}; | |
76 | + | |
77 | +static inline u32 mx6_ecspi_fused(u32 base_addr){ | |
78 | + return 0; | |
79 | +}; | |
80 | +static inline u32 mx6_uart_fused(u32 base_addr){ | |
81 | + return 0; | |
82 | +}; | |
83 | +static inline u32 mx6_usb_fused(u32 base_addr){ | |
84 | + return 0; | |
85 | +}; | |
86 | +static inline u32 mx6_qspi_fused(u32 base_addr){ | |
87 | + return 0; | |
88 | +}; | |
89 | +static inline u32 mx6_i2c_fused(u32 base_addr){ | |
90 | + return 0; | |
91 | +}; | |
92 | +static inline u32 mx6_enet_fused(u32 base_addr){ | |
93 | + return 0; | |
94 | +}; | |
95 | + | |
96 | +#else | |
97 | +u32 check_module_fused(enum fuse_module_type module); | |
98 | +u32 mx6_esdhc_fused(u32 base_addr); | |
99 | +u32 mx6_ecspi_fused(u32 base_addr); | |
100 | +u32 mx6_uart_fused(u32 base_addr); | |
101 | +u32 mx6_usb_fused(u32 base_addr); | |
102 | +u32 mx6_qspi_fused(u32 base_addr); | |
103 | +u32 mx6_i2c_fused(u32 base_addr); | |
104 | +u32 mx6_enet_fused(u32 base_addr); | |
105 | +#endif | |
106 | + | |
107 | +#ifdef DEBUG | |
108 | +void print_fuse_status(); | |
109 | +void simulate_fuse(); | |
110 | +#endif | |
111 | + | |
112 | +#endif /* __MODULE_FUSE_H__ */ |
arch/arm/include/asm/arch-mx6/sys_proto.h