u-boot-brain/board/freescale/common/qixis.c
Gong Qianyu 98d9aa4013 freescale/qixis: Add support for booting from SD/QSPI
1.Use "qixis_reset sd" to boot from SD
2.Use "qixis_reset sd_qspi" to boot from SD with QSPI support
3.Use "qixis_reset qspi" to boot from QSPI flash

On some SoCs such as LS1021A and LS1043A, IFC and QSPI could be
pin-multiplexed. So the switches are different between SD boot with
IFC support and SD boot with QSPI support. The default booting from
SD is with IFC support.

Once QSPI is enabled(IFC disabled), only use I2C to access QIXIS.

Signed-off-by: Gong Qianyu <Qianyu.Gong@freescale.com>
Reviewed-by: York Sun <york.sun@nxp.com>
2016-01-25 08:24:15 -08:00

299 lines
7.1 KiB
C

/*
* Copyright 2011 Freescale Semiconductor
* Author: Shengzhou Liu <Shengzhou.Liu@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This file provides support for the QIXIS of some Freescale reference boards.
*/
#include <common.h>
#include <command.h>
#include <asm/io.h>
#include <linux/time.h>
#include <i2c.h>
#include "qixis.h"
#ifdef CONFIG_SYS_I2C_FPGA_ADDR
u8 qixis_read_i2c(unsigned int reg)
{
return i2c_reg_read(CONFIG_SYS_I2C_FPGA_ADDR, reg);
}
void qixis_write_i2c(unsigned int reg, u8 value)
{
u8 val = value;
i2c_reg_write(CONFIG_SYS_I2C_FPGA_ADDR, reg, val);
}
#endif
u8 qixis_read(unsigned int reg)
{
void *p = (void *)QIXIS_BASE;
return in_8(p + reg);
}
void qixis_write(unsigned int reg, u8 value)
{
void *p = (void *)QIXIS_BASE;
out_8(p + reg, value);
}
u16 qixis_read_minor(void)
{
u16 minor;
/* this data is in little endian */
QIXIS_WRITE(tagdata, 5);
minor = QIXIS_READ(tagdata);
QIXIS_WRITE(tagdata, 6);
minor += QIXIS_READ(tagdata) << 8;
return minor;
}
char *qixis_read_time(char *result)
{
time_t time = 0;
int i;
/* timestamp is in 32-bit big endian */
for (i = 8; i <= 11; i++) {
QIXIS_WRITE(tagdata, i);
time = (time << 8) + QIXIS_READ(tagdata);
}
return ctime_r(&time, result);
}
char *qixis_read_tag(char *buf)
{
int i;
char tag, *ptr = buf;
for (i = 16; i <= 63; i++) {
QIXIS_WRITE(tagdata, i);
tag = QIXIS_READ(tagdata);
*(ptr++) = tag;
if (!tag)
break;
}
if (i > 63)
*ptr = '\0';
return buf;
}
/*
* return the string of binary of u8 in the format of
* 1010 10_0. The masked bit is filled as underscore.
*/
const char *byte_to_binary_mask(u8 val, u8 mask, char *buf)
{
char *ptr;
int i;
ptr = buf;
for (i = 0x80; i > 0x08 ; i >>= 1, ptr++)
*ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0');
*(ptr++) = ' ';
for (i = 0x08; i > 0 ; i >>= 1, ptr++)
*ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0');
*ptr = '\0';
return buf;
}
#ifdef QIXIS_RST_FORCE_MEM
void board_assert_mem_reset(void)
{
u8 rst;
rst = QIXIS_READ(rst_frc[0]);
if (!(rst & QIXIS_RST_FORCE_MEM))
QIXIS_WRITE(rst_frc[0], rst | QIXIS_RST_FORCE_MEM);
}
void board_deassert_mem_reset(void)
{
u8 rst;
rst = QIXIS_READ(rst_frc[0]);
if (rst & QIXIS_RST_FORCE_MEM)
QIXIS_WRITE(rst_frc[0], rst & ~QIXIS_RST_FORCE_MEM);
}
#endif
void qixis_reset(void)
{
QIXIS_WRITE(rst_ctl, QIXIS_RST_CTL_RESET);
}
void qixis_bank_reset(void)
{
QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE);
QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START);
}
static void __maybe_unused set_lbmap(int lbmap)
{
u8 reg;
reg = QIXIS_READ(brdcfg[0]);
reg = (reg & ~QIXIS_LBMAP_MASK) | lbmap;
QIXIS_WRITE(brdcfg[0], reg);
}
static void __maybe_unused set_rcw_src(int rcw_src)
{
u8 reg;
reg = QIXIS_READ(dutcfg[1]);
reg = (reg & ~1) | (rcw_src & 1);
QIXIS_WRITE(dutcfg[1], reg);
QIXIS_WRITE(dutcfg[0], (rcw_src >> 1) & 0xff);
}
static void qixis_dump_regs(void)
{
int i;
printf("id = %02x\n", QIXIS_READ(id));
printf("arch = %02x\n", QIXIS_READ(arch));
printf("scver = %02x\n", QIXIS_READ(scver));
printf("model = %02x\n", QIXIS_READ(model));
printf("rst_ctl = %02x\n", QIXIS_READ(rst_ctl));
printf("aux = %02x\n", QIXIS_READ(aux));
for (i = 0; i < 16; i++)
printf("brdcfg%02d = %02x\n", i, QIXIS_READ(brdcfg[i]));
for (i = 0; i < 16; i++)
printf("dutcfg%02d = %02x\n", i, QIXIS_READ(dutcfg[i]));
printf("sclk = %02x%02x%02x\n", QIXIS_READ(sclk[0]),
QIXIS_READ(sclk[1]), QIXIS_READ(sclk[2]));
printf("dclk = %02x%02x%02x\n", QIXIS_READ(dclk[0]),
QIXIS_READ(dclk[1]), QIXIS_READ(dclk[2]));
printf("aux = %02x\n", QIXIS_READ(aux));
printf("watch = %02x\n", QIXIS_READ(watch));
printf("ctl_sys = %02x\n", QIXIS_READ(ctl_sys));
printf("rcw_ctl = %02x\n", QIXIS_READ(rcw_ctl));
printf("present = %02x\n", QIXIS_READ(present));
printf("present2 = %02x\n", QIXIS_READ(present2));
printf("clk_spd = %02x\n", QIXIS_READ(clk_spd));
printf("stat_dut = %02x\n", QIXIS_READ(stat_dut));
printf("stat_sys = %02x\n", QIXIS_READ(stat_sys));
printf("stat_alrm = %02x\n", QIXIS_READ(stat_alrm));
}
static void __qixis_dump_switch(void)
{
puts("Reverse engineering switch is not implemented for this board\n");
}
void qixis_dump_switch(void)
__attribute__((weak, alias("__qixis_dump_switch")));
int qixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int i;
if (argc <= 1) {
set_lbmap(QIXIS_LBMAP_DFLTBANK);
qixis_reset();
} else if (strcmp(argv[1], "altbank") == 0) {
set_lbmap(QIXIS_LBMAP_ALTBANK);
qixis_bank_reset();
} else if (strcmp(argv[1], "nand") == 0) {
#ifdef QIXIS_LBMAP_NAND
QIXIS_WRITE(rst_ctl, 0x30);
QIXIS_WRITE(rcfg_ctl, 0);
set_lbmap(QIXIS_LBMAP_NAND);
set_rcw_src(QIXIS_RCW_SRC_NAND);
QIXIS_WRITE(rcfg_ctl, 0x20);
QIXIS_WRITE(rcfg_ctl, 0x21);
#else
printf("Not implemented\n");
#endif
} else if (strcmp(argv[1], "sd") == 0) {
#ifdef QIXIS_LBMAP_SD
QIXIS_WRITE(rst_ctl, 0x30);
QIXIS_WRITE(rcfg_ctl, 0);
set_lbmap(QIXIS_LBMAP_SD);
set_rcw_src(QIXIS_RCW_SRC_SD);
QIXIS_WRITE(rcfg_ctl, 0x20);
QIXIS_WRITE(rcfg_ctl, 0x21);
#else
printf("Not implemented\n");
#endif
} else if (strcmp(argv[1], "sd_qspi") == 0) {
#ifdef QIXIS_LBMAP_SD_QSPI
QIXIS_WRITE(rst_ctl, 0x30);
QIXIS_WRITE(rcfg_ctl, 0);
set_lbmap(QIXIS_LBMAP_SD_QSPI);
set_rcw_src(QIXIS_RCW_SRC_SD);
qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x20);
qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x21);
#else
printf("Not implemented\n");
#endif
} else if (strcmp(argv[1], "qspi") == 0) {
#ifdef QIXIS_LBMAP_QSPI
QIXIS_WRITE(rst_ctl, 0x30);
QIXIS_WRITE(rcfg_ctl, 0);
set_lbmap(QIXIS_LBMAP_QSPI);
set_rcw_src(QIXIS_RCW_SRC_QSPI);
qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x20);
qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x21);
#else
printf("Not implemented\n");
#endif
} else if (strcmp(argv[1], "watchdog") == 0) {
static char *period[9] = {"2s", "4s", "8s", "16s", "32s",
"1min", "2min", "4min", "8min"};
u8 rcfg = QIXIS_READ(rcfg_ctl);
if (argv[2] == NULL) {
printf("qixis watchdog <watchdog_period>\n");
return 0;
}
for (i = 0; i < ARRAY_SIZE(period); i++) {
if (strcmp(argv[2], period[i]) == 0) {
/* disable watchdog */
QIXIS_WRITE(rcfg_ctl,
rcfg & ~QIXIS_RCFG_CTL_WATCHDOG_ENBLE);
QIXIS_WRITE(watch, ((i<<2) - 1));
QIXIS_WRITE(rcfg_ctl, rcfg);
return 0;
}
}
} else if (strcmp(argv[1], "dump") == 0) {
qixis_dump_regs();
return 0;
} else if (strcmp(argv[1], "switch") == 0) {
qixis_dump_switch();
return 0;
} else {
printf("Invalid option: %s\n", argv[1]);
return 1;
}
return 0;
}
U_BOOT_CMD(
qixis_reset, CONFIG_SYS_MAXARGS, 1, qixis_reset_cmd,
"Reset the board using the FPGA sequencer",
"- hard reset to default bank\n"
"qixis_reset altbank - reset to alternate bank\n"
"qixis_reset nand - reset to nand\n"
"qixis_reset sd - reset to sd\n"
"qixis_reset sd_qspi - reset to sd with qspi support\n"
"qixis_reset qspi - reset to qspi\n"
"qixis watchdog <watchdog_period> - set the watchdog period\n"
" period: 1s 2s 4s 8s 16s 32s 1min 2min 4min 8min\n"
"qixis_reset dump - display the QIXIS registers\n"
"qixis_reset switch - display switch\n"
);