]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
ae6b03fe SL |
2 | /* |
3 | * Copyright 2011 Freescale Semiconductor | |
bddec1b0 | 4 | * Copyright 2020 NXP |
ae6b03fe SL |
5 | * Author: Shengzhou Liu <[email protected]> |
6 | * | |
ae6b03fe | 7 | * This file provides support for the QIXIS of some Freescale reference boards. |
ae6b03fe SL |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <command.h> | |
12 | #include <asm/io.h> | |
1f0ce325 | 13 | #include <linux/compiler.h> |
2ae4e8d9 | 14 | #include <linux/time.h> |
960aa89b | 15 | #include <i2c.h> |
ae6b03fe SL |
16 | #include "qixis.h" |
17 | ||
16dacb26 AS |
18 | #ifndef QIXIS_LBMAP_BRDCFG_REG |
19 | /* | |
20 | * For consistency with existing platforms | |
21 | */ | |
22 | #define QIXIS_LBMAP_BRDCFG_REG 0x00 | |
23 | #endif | |
24 | ||
0f6607f9 YT |
25 | #ifndef QIXIS_RCFG_CTL_RECONFIG_IDLE |
26 | #define QIXIS_RCFG_CTL_RECONFIG_IDLE 0x20 | |
27 | #endif | |
28 | #ifndef QIXIS_RCFG_CTL_RECONFIG_START | |
29 | #define QIXIS_RCFG_CTL_RECONFIG_START 0x21 | |
30 | #endif | |
31 | ||
960aa89b PK |
32 | #ifdef CONFIG_SYS_I2C_FPGA_ADDR |
33 | u8 qixis_read_i2c(unsigned int reg) | |
34 | { | |
0eba65d2 | 35 | #ifndef CONFIG_DM_I2C |
960aa89b | 36 | return i2c_reg_read(CONFIG_SYS_I2C_FPGA_ADDR, reg); |
0eba65d2 CH |
37 | #else |
38 | struct udevice *dev; | |
39 | ||
40 | if (i2c_get_chip_for_busnum(0, CONFIG_SYS_I2C_FPGA_ADDR, 1, &dev)) | |
41 | return 0xff; | |
42 | ||
43 | return dm_i2c_reg_read(dev, reg); | |
44 | #endif | |
960aa89b PK |
45 | } |
46 | ||
47 | void qixis_write_i2c(unsigned int reg, u8 value) | |
48 | { | |
49 | u8 val = value; | |
0eba65d2 | 50 | #ifndef CONFIG_DM_I2C |
960aa89b | 51 | i2c_reg_write(CONFIG_SYS_I2C_FPGA_ADDR, reg, val); |
0eba65d2 CH |
52 | #else |
53 | struct udevice *dev; | |
54 | ||
55 | if (!i2c_get_chip_for_busnum(0, CONFIG_SYS_I2C_FPGA_ADDR, 1, &dev)) | |
56 | dm_i2c_reg_write(dev, reg, val); | |
57 | #endif | |
58 | ||
960aa89b PK |
59 | } |
60 | #endif | |
61 | ||
3faaa24b | 62 | #ifdef QIXIS_BASE |
ae6b03fe SL |
63 | u8 qixis_read(unsigned int reg) |
64 | { | |
65 | void *p = (void *)QIXIS_BASE; | |
66 | ||
67 | return in_8(p + reg); | |
68 | } | |
69 | ||
70 | void qixis_write(unsigned int reg, u8 value) | |
71 | { | |
72 | void *p = (void *)QIXIS_BASE; | |
73 | ||
74 | out_8(p + reg, value); | |
75 | } | |
3faaa24b | 76 | #endif |
ae6b03fe | 77 | |
2ae4e8d9 PK |
78 | u16 qixis_read_minor(void) |
79 | { | |
80 | u16 minor; | |
81 | ||
82 | /* this data is in little endian */ | |
83 | QIXIS_WRITE(tagdata, 5); | |
84 | minor = QIXIS_READ(tagdata); | |
85 | QIXIS_WRITE(tagdata, 6); | |
86 | minor += QIXIS_READ(tagdata) << 8; | |
87 | ||
88 | return minor; | |
89 | } | |
90 | ||
91 | char *qixis_read_time(char *result) | |
92 | { | |
93 | time_t time = 0; | |
94 | int i; | |
95 | ||
96 | /* timestamp is in 32-bit big endian */ | |
97 | for (i = 8; i <= 11; i++) { | |
98 | QIXIS_WRITE(tagdata, i); | |
99 | time = (time << 8) + QIXIS_READ(tagdata); | |
100 | } | |
101 | ||
102 | return ctime_r(&time, result); | |
103 | } | |
104 | ||
105 | char *qixis_read_tag(char *buf) | |
106 | { | |
107 | int i; | |
108 | char tag, *ptr = buf; | |
109 | ||
110 | for (i = 16; i <= 63; i++) { | |
111 | QIXIS_WRITE(tagdata, i); | |
112 | tag = QIXIS_READ(tagdata); | |
113 | *(ptr++) = tag; | |
114 | if (!tag) | |
115 | break; | |
116 | } | |
117 | if (i > 63) | |
118 | *ptr = '\0'; | |
119 | ||
120 | return buf; | |
121 | } | |
122 | ||
c6cef92f SL |
123 | /* |
124 | * return the string of binary of u8 in the format of | |
125 | * 1010 10_0. The masked bit is filled as underscore. | |
126 | */ | |
127 | const char *byte_to_binary_mask(u8 val, u8 mask, char *buf) | |
128 | { | |
129 | char *ptr; | |
130 | int i; | |
131 | ||
132 | ptr = buf; | |
133 | for (i = 0x80; i > 0x08 ; i >>= 1, ptr++) | |
134 | *ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0'); | |
135 | *(ptr++) = ' '; | |
136 | for (i = 0x08; i > 0 ; i >>= 1, ptr++) | |
137 | *ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0'); | |
138 | ||
139 | *ptr = '\0'; | |
140 | ||
141 | return buf; | |
142 | } | |
143 | ||
c63e1370 YS |
144 | #ifdef QIXIS_RST_FORCE_MEM |
145 | void board_assert_mem_reset(void) | |
146 | { | |
147 | u8 rst; | |
148 | ||
149 | rst = QIXIS_READ(rst_frc[0]); | |
150 | if (!(rst & QIXIS_RST_FORCE_MEM)) | |
151 | QIXIS_WRITE(rst_frc[0], rst | QIXIS_RST_FORCE_MEM); | |
152 | } | |
153 | ||
154 | void board_deassert_mem_reset(void) | |
155 | { | |
156 | u8 rst; | |
157 | ||
158 | rst = QIXIS_READ(rst_frc[0]); | |
159 | if (rst & QIXIS_RST_FORCE_MEM) | |
160 | QIXIS_WRITE(rst_frc[0], rst & ~QIXIS_RST_FORCE_MEM); | |
161 | } | |
162 | #endif | |
163 | ||
1f0ce325 TR |
164 | #ifndef CONFIG_SPL_BUILD |
165 | static void qixis_reset(void) | |
ae6b03fe | 166 | { |
9f26fd79 | 167 | QIXIS_WRITE(rst_ctl, QIXIS_RST_CTL_RESET); |
ae6b03fe SL |
168 | } |
169 | ||
0f6607f9 | 170 | #ifdef QIXIS_LBMAP_ALTBANK |
1f0ce325 | 171 | static void qixis_bank_reset(void) |
ae6b03fe | 172 | { |
9f26fd79 PK |
173 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE); |
174 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START); | |
ae6b03fe | 175 | } |
0f6607f9 | 176 | #endif |
ae6b03fe | 177 | |
548cf52f | 178 | static void __maybe_unused set_lbmap(int lbmap) |
ae6b03fe SL |
179 | { |
180 | u8 reg; | |
181 | ||
16dacb26 | 182 | reg = QIXIS_READ(brdcfg[QIXIS_LBMAP_BRDCFG_REG]); |
548cf52f | 183 | reg = (reg & ~QIXIS_LBMAP_MASK) | lbmap; |
16dacb26 | 184 | QIXIS_WRITE(brdcfg[QIXIS_LBMAP_BRDCFG_REG], reg); |
ae6b03fe SL |
185 | } |
186 | ||
548cf52f | 187 | static void __maybe_unused set_rcw_src(int rcw_src) |
ae6b03fe | 188 | { |
0f6607f9 YT |
189 | #ifdef CONFIG_NXP_LSCH3_2 |
190 | QIXIS_WRITE(dutcfg[0], (rcw_src & 0xff)); | |
191 | #else | |
ae6b03fe SL |
192 | u8 reg; |
193 | ||
548cf52f SW |
194 | reg = QIXIS_READ(dutcfg[1]); |
195 | reg = (reg & ~1) | (rcw_src & 1); | |
196 | QIXIS_WRITE(dutcfg[1], reg); | |
197 | QIXIS_WRITE(dutcfg[0], (rcw_src >> 1) & 0xff); | |
0f6607f9 | 198 | #endif |
ae6b03fe SL |
199 | } |
200 | ||
ae6b03fe SL |
201 | static void qixis_dump_regs(void) |
202 | { | |
203 | int i; | |
204 | ||
205 | printf("id = %02x\n", QIXIS_READ(id)); | |
206 | printf("arch = %02x\n", QIXIS_READ(arch)); | |
207 | printf("scver = %02x\n", QIXIS_READ(scver)); | |
208 | printf("model = %02x\n", QIXIS_READ(model)); | |
209 | printf("rst_ctl = %02x\n", QIXIS_READ(rst_ctl)); | |
210 | printf("aux = %02x\n", QIXIS_READ(aux)); | |
211 | for (i = 0; i < 16; i++) | |
212 | printf("brdcfg%02d = %02x\n", i, QIXIS_READ(brdcfg[i])); | |
213 | for (i = 0; i < 16; i++) | |
214 | printf("dutcfg%02d = %02x\n", i, QIXIS_READ(dutcfg[i])); | |
215 | printf("sclk = %02x%02x%02x\n", QIXIS_READ(sclk[0]), | |
216 | QIXIS_READ(sclk[1]), QIXIS_READ(sclk[2])); | |
217 | printf("dclk = %02x%02x%02x\n", QIXIS_READ(dclk[0]), | |
218 | QIXIS_READ(dclk[1]), QIXIS_READ(dclk[2])); | |
219 | printf("aux = %02x\n", QIXIS_READ(aux)); | |
220 | printf("watch = %02x\n", QIXIS_READ(watch)); | |
221 | printf("ctl_sys = %02x\n", QIXIS_READ(ctl_sys)); | |
222 | printf("rcw_ctl = %02x\n", QIXIS_READ(rcw_ctl)); | |
223 | printf("present = %02x\n", QIXIS_READ(present)); | |
e4de13e3 | 224 | printf("present2 = %02x\n", QIXIS_READ(present2)); |
ae6b03fe SL |
225 | printf("clk_spd = %02x\n", QIXIS_READ(clk_spd)); |
226 | printf("stat_dut = %02x\n", QIXIS_READ(stat_dut)); | |
227 | printf("stat_sys = %02x\n", QIXIS_READ(stat_sys)); | |
228 | printf("stat_alrm = %02x\n", QIXIS_READ(stat_alrm)); | |
ae6b03fe | 229 | } |
c6cef92f | 230 | |
1f0ce325 | 231 | void __weak qixis_dump_switch(void) |
c6cef92f SL |
232 | { |
233 | puts("Reverse engineering switch is not implemented for this board\n"); | |
234 | } | |
235 | ||
09140113 SG |
236 | static int qixis_reset_cmd(struct cmd_tbl *cmdtp, int flag, int argc, |
237 | char *const argv[]) | |
ae6b03fe SL |
238 | { |
239 | int i; | |
240 | ||
241 | if (argc <= 1) { | |
548cf52f | 242 | set_lbmap(QIXIS_LBMAP_DFLTBANK); |
ae6b03fe SL |
243 | qixis_reset(); |
244 | } else if (strcmp(argv[1], "altbank") == 0) { | |
0f6607f9 | 245 | #ifdef QIXIS_LBMAP_ALTBANK |
548cf52f | 246 | set_lbmap(QIXIS_LBMAP_ALTBANK); |
ae6b03fe | 247 | qixis_bank_reset(); |
0f6607f9 YT |
248 | #else |
249 | printf("No Altbank!\n"); | |
250 | #endif | |
548cf52f SW |
251 | } else if (strcmp(argv[1], "nand") == 0) { |
252 | #ifdef QIXIS_LBMAP_NAND | |
253 | QIXIS_WRITE(rst_ctl, 0x30); | |
254 | QIXIS_WRITE(rcfg_ctl, 0); | |
255 | set_lbmap(QIXIS_LBMAP_NAND); | |
256 | set_rcw_src(QIXIS_RCW_SRC_NAND); | |
0f6607f9 YT |
257 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE); |
258 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START); | |
548cf52f SW |
259 | #else |
260 | printf("Not implemented\n"); | |
98d9aa40 GQ |
261 | #endif |
262 | } else if (strcmp(argv[1], "sd") == 0) { | |
263 | #ifdef QIXIS_LBMAP_SD | |
264 | QIXIS_WRITE(rst_ctl, 0x30); | |
265 | QIXIS_WRITE(rcfg_ctl, 0); | |
58c3e620 PJ |
266 | #ifdef NON_EXTENDED_DUTCFG |
267 | QIXIS_WRITE(dutcfg[0], QIXIS_RCW_SRC_SD); | |
268 | #else | |
98d9aa40 GQ |
269 | set_lbmap(QIXIS_LBMAP_SD); |
270 | set_rcw_src(QIXIS_RCW_SRC_SD); | |
58c3e620 | 271 | #endif |
0f6607f9 YT |
272 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE); |
273 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START); | |
98d9aa40 GQ |
274 | #else |
275 | printf("Not implemented\n"); | |
fe997689 AK |
276 | #endif |
277 | } else if (strcmp(argv[1], "ifc") == 0) { | |
278 | #ifdef QIXIS_LBMAP_IFC | |
279 | QIXIS_WRITE(rst_ctl, 0x30); | |
280 | QIXIS_WRITE(rcfg_ctl, 0); | |
281 | set_lbmap(QIXIS_LBMAP_IFC); | |
282 | set_rcw_src(QIXIS_RCW_SRC_IFC); | |
0f6607f9 YT |
283 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE); |
284 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START); | |
fe997689 AK |
285 | #else |
286 | printf("Not implemented\n"); | |
287 | #endif | |
288 | } else if (strcmp(argv[1], "emmc") == 0) { | |
289 | #ifdef QIXIS_LBMAP_EMMC | |
290 | QIXIS_WRITE(rst_ctl, 0x30); | |
291 | QIXIS_WRITE(rcfg_ctl, 0); | |
bddec1b0 | 292 | #ifndef NON_EXTENDED_DUTCFG |
fe997689 | 293 | set_lbmap(QIXIS_LBMAP_EMMC); |
bddec1b0 | 294 | #endif |
fe997689 | 295 | set_rcw_src(QIXIS_RCW_SRC_EMMC); |
0f6607f9 YT |
296 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE); |
297 | QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START); | |
fe997689 AK |
298 | #else |
299 | printf("Not implemented\n"); | |
98d9aa40 GQ |
300 | #endif |
301 | } else if (strcmp(argv[1], "sd_qspi") == 0) { | |
302 | #ifdef QIXIS_LBMAP_SD_QSPI | |
303 | QIXIS_WRITE(rst_ctl, 0x30); | |
304 | QIXIS_WRITE(rcfg_ctl, 0); | |
305 | set_lbmap(QIXIS_LBMAP_SD_QSPI); | |
306 | set_rcw_src(QIXIS_RCW_SRC_SD); | |
0f6607f9 YT |
307 | qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), |
308 | QIXIS_RCFG_CTL_RECONFIG_IDLE); | |
309 | qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), | |
310 | QIXIS_RCFG_CTL_RECONFIG_START); | |
98d9aa40 GQ |
311 | #else |
312 | printf("Not implemented\n"); | |
313 | #endif | |
314 | } else if (strcmp(argv[1], "qspi") == 0) { | |
315 | #ifdef QIXIS_LBMAP_QSPI | |
316 | QIXIS_WRITE(rst_ctl, 0x30); | |
317 | QIXIS_WRITE(rcfg_ctl, 0); | |
318 | set_lbmap(QIXIS_LBMAP_QSPI); | |
319 | set_rcw_src(QIXIS_RCW_SRC_QSPI); | |
0f6607f9 YT |
320 | qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), |
321 | QIXIS_RCFG_CTL_RECONFIG_IDLE); | |
322 | qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), | |
323 | QIXIS_RCFG_CTL_RECONFIG_START); | |
98d9aa40 GQ |
324 | #else |
325 | printf("Not implemented\n"); | |
548cf52f | 326 | #endif |
ae6b03fe SL |
327 | } else if (strcmp(argv[1], "watchdog") == 0) { |
328 | static char *period[9] = {"2s", "4s", "8s", "16s", "32s", | |
329 | "1min", "2min", "4min", "8min"}; | |
330 | u8 rcfg = QIXIS_READ(rcfg_ctl); | |
331 | ||
332 | if (argv[2] == NULL) { | |
333 | printf("qixis watchdog <watchdog_period>\n"); | |
334 | return 0; | |
335 | } | |
336 | for (i = 0; i < ARRAY_SIZE(period); i++) { | |
337 | if (strcmp(argv[2], period[i]) == 0) { | |
338 | /* disable watchdog */ | |
9f26fd79 PK |
339 | QIXIS_WRITE(rcfg_ctl, |
340 | rcfg & ~QIXIS_RCFG_CTL_WATCHDOG_ENBLE); | |
ae6b03fe SL |
341 | QIXIS_WRITE(watch, ((i<<2) - 1)); |
342 | QIXIS_WRITE(rcfg_ctl, rcfg); | |
343 | return 0; | |
344 | } | |
345 | } | |
c6cef92f | 346 | } else if (strcmp(argv[1], "dump") == 0) { |
ae6b03fe SL |
347 | qixis_dump_regs(); |
348 | return 0; | |
c6cef92f SL |
349 | } else if (strcmp(argv[1], "switch") == 0) { |
350 | qixis_dump_switch(); | |
351 | return 0; | |
352 | } else { | |
ae6b03fe SL |
353 | printf("Invalid option: %s\n", argv[1]); |
354 | return 1; | |
355 | } | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
360 | U_BOOT_CMD( | |
361 | qixis_reset, CONFIG_SYS_MAXARGS, 1, qixis_reset_cmd, | |
362 | "Reset the board using the FPGA sequencer", | |
363 | "- hard reset to default bank\n" | |
364 | "qixis_reset altbank - reset to alternate bank\n" | |
548cf52f | 365 | "qixis_reset nand - reset to nand\n" |
98d9aa40 GQ |
366 | "qixis_reset sd - reset to sd\n" |
367 | "qixis_reset sd_qspi - reset to sd with qspi support\n" | |
368 | "qixis_reset qspi - reset to qspi\n" | |
ae6b03fe SL |
369 | "qixis watchdog <watchdog_period> - set the watchdog period\n" |
370 | " period: 1s 2s 4s 8s 16s 32s 1min 2min 4min 8min\n" | |
ae6b03fe | 371 | "qixis_reset dump - display the QIXIS registers\n" |
bddec1b0 | 372 | "qixis_reset emmc - reset to emmc\n" |
c6cef92f | 373 | "qixis_reset switch - display switch\n" |
ae6b03fe | 374 | ); |
1f0ce325 | 375 | #endif |