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