[zynq] Add slcr commands and pull out DDR config

This commit is contained in:
Chris Anderson
2014-11-21 10:10:23 -08:00
parent 67eba69600
commit 5ed4eca1ba
4 changed files with 104 additions and 38 deletions

View File

@@ -119,6 +119,7 @@
#ifndef ASSEMBLY
/* Configuration values for each of the system PLLs. Refer to the TRM 25.10.4 */
typedef struct {
uint32_t lock_cnt;
uint32_t cp;
@@ -152,6 +153,18 @@ typedef struct {
zynq_pll_cfg_t io;
} zynq_pll_cfg_tree_t;
/* Configuration for the DDR controller and buffers. TRM Ch 10 */
typedef struct {
uint32_t addr0;
uint32_t addr1;
uint32_t data0;
uint32_t data1;
uint32_t diff0;
uint32_t diff1;
bool ibuf_disable;
bool term_disable;
} zynq_ddriob_cfg_t;;
/* SLCR registers */
struct slcr_regs {
uint32_t SCL; // Secure Configuration Lock

View File

@@ -23,6 +23,7 @@
#include <err.h>
#include <debug.h>
#include <stdio.h>
#include <string.h>
#include <arch/arm/mmu.h>
#include <kernel/vm.h>
#include <dev/uart.h>
@@ -44,6 +45,7 @@ extern const long zynq_ddr_cfg[];
extern const uint32_t zynq_ddr_cfg_cnt;
extern const zynq_pll_cfg_tree_t zynq_pll_cfg;
extern const zynq_clk_cfg_t zynq_clk_cfg;
extern const zynq_ddriob_cfg_t zynq_ddriob_cfg;
static inline int reg_poll(uint32_t addr,uint32_t mask)
@@ -65,7 +67,6 @@ static inline int reg_poll(uint32_t addr,uint32_t mask)
int zynq_pll_init(void) {
const zynq_pll_cfg_tree_t *cfg = &zynq_pll_cfg;
zynq_slcr_unlock();
SLCR_REG(ARM_PLL_CFG) = PLL_CFG_LOCK_CNT(cfg->arm.lock_cnt) | PLL_CFG_PLL_CP(cfg->arm.cp) |
PLL_CFG_PLL_RES(cfg->arm.res);
SLCR_REG(ARM_PLL_CTRL) = PLL_FDIV(cfg->arm.fdiv) | PLL_BYPASS_FORCE | PLL_RESET;
@@ -101,60 +102,31 @@ int zynq_pll_init(void) {
}
SLCR_REG(IO_PLL_CTRL) &= ~PLL_BYPASS_FORCE;
zynq_slcr_lock();
return 0;
}
int zynq_mio_init(void)
{
zynq_slcr_unlock();
/* This DDRIOB configuration applies to both zybo and uzed, but it's possible
* it may not work for all boards in the future. Just something to keep in mind
* with different memory configurations.
*/
#if ZYNQ_SDRAM_INIT
SLCR_REG(GPIOB_CTRL) = GPIOB_CTRL_VREF_EN;
SLCR_REG(DDRIOB_ADDR0) = DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_ADDR1) = DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_DATA0) = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN |
DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_DATA1) = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN |
DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_DIFF0) = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN |
DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_DIFF1) = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN |
DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3);
SLCR_REG(DDRIOB_CLOCK) = DDRIOB_OUTPUT_EN(0x3);
/* These register fields are not documented in the TRM. These
* values represent the defaults generated via the Zynq tools
*/
SLCR_REG(DDRIOB_DRIVE_SLEW_ADDR) = 0x0018C61CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_DATA) = 0x00F9861CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_DIFF) = 0x00F9861CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_CLOCK) = 0x00F9861CU;
SLCR_REG(DDRIOB_DDR_CTRL) = 0x00000E60U;
SLCR_REG(DDRIOB_DCI_CTRL) = 0x00000001U;
SLCR_REG(DDRIOB_DCI_CTRL) |= 0x00000020U;
SLCR_REG(DDRIOB_DCI_CTRL) |= 0x00000823U;
#endif
for (size_t pin = 0; pin < countof(zynq_mio_cfg); pin++) {
if (zynq_mio_cfg[pin] != 0) {
SLCR_REG(MIO_PIN_00 + (pin * sizeof(uint32_t))) = zynq_mio_cfg[pin];
SLCR_REG(MIO_PIN_00 + (pin * 4)) = zynq_mio_cfg[pin];
}
}
SLCR_REG(SD0_WP_CD_SEL) = SDIO0_WP_SEL(0x37) | SDIO0_CD_SEL(0x2F);
zynq_slcr_lock();
return 0;
}
void zynq_clk_init(void)
{
zynq_slcr_unlock();
SLCR_REG(DCI_CLK_CTRL) = zynq_clk_cfg.dci_clk;
SLCR_REG(GEM0_CLK_CTRL) = zynq_clk_cfg.gem0_clk;
SLCR_REG(GEM0_RCLK_CTRL) = zynq_clk_cfg.gem0_rclk;
@@ -170,12 +142,31 @@ void zynq_clk_init(void)
SLCR_REG(FPGA3_CLK_CTRL) = zynq_clk_cfg.fpga3_clk;
SLCR_REG(APER_CLK_CTRL) = zynq_clk_cfg.aper_clk;
SLCR_REG(CLK_621_TRUE) = zynq_clk_cfg.clk_621_true;
zynq_slcr_lock();
}
void zynq_ddr_init(void)
{
zynq_slcr_unlock();
#ifdef ZYNQ_SDRAM_INIT
SLCR_REG(DDRIOB_ADDR0) = zynq_ddriob_cfg.addr0;
SLCR_REG(DDRIOB_ADDR1) = zynq_ddriob_cfg.addr1;
SLCR_REG(DDRIOB_DATA0) = zynq_ddriob_cfg.data0;
SLCR_REG(DDRIOB_DATA1) = zynq_ddriob_cfg.data1;
SLCR_REG(DDRIOB_DIFF0) = zynq_ddriob_cfg.diff0;
SLCR_REG(DDRIOB_DIFF1) = zynq_ddriob_cfg.diff1;
SLCR_REG(DDRIOB_CLOCK) = DDRIOB_OUTPUT_EN(0x3);
/* These register fields are not documented in the TRM. These
* values represent the defaults generated via the Zynq tools
*/
SLCR_REG(DDRIOB_DRIVE_SLEW_ADDR) = 0x0018C61CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_DATA) = 0x00F9861CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_DIFF) = 0x00F9861CU;
SLCR_REG(DDRIOB_DRIVE_SLEW_CLOCK) = 0x00F9861CU;
SLCR_REG(DDRIOB_DDR_CTRL) = 0x00000E60U;
SLCR_REG(DDRIOB_DCI_CTRL) = 0x00000001U;
SLCR_REG(DDRIOB_DCI_CTRL) |= 0x00000020U;
SLCR_REG(DDRIOB_DCI_CTRL) |= 0x00000823U;
#endif
/* Write addresss / value pairs from target table */
for (size_t i = 0; i < zynq_ddr_cfg_cnt; i += 2) {
@@ -192,7 +183,19 @@ void zynq_ddr_init(void)
/* Switch timer to 64k */
*REG32(0XF8007000) = *REG32(0xF8007000) & ~0x20000000U;
zynq_slcr_lock();
if (zynq_ddriob_cfg.ibuf_disable) {
SLCR_REG(DDRIOB_DATA0) |= DDRIOB_IBUF_DISABLE_MODE;
SLCR_REG(DDRIOB_DATA1) |= DDRIOB_IBUF_DISABLE_MODE;
SLCR_REG(DDRIOB_DIFF0) |= DDRIOB_IBUF_DISABLE_MODE;
SLCR_REG(DDRIOB_DIFF1) |= DDRIOB_IBUF_DISABLE_MODE;
}
if (zynq_ddriob_cfg.term_disable) {
SLCR_REG(DDRIOB_DATA0) |= DDRIOB_TERM_DISABLE_MODE;
SLCR_REG(DDRIOB_DATA1) |= DDRIOB_TERM_DISABLE_MODE;
SLCR_REG(DDRIOB_DIFF0) |= DDRIOB_TERM_DISABLE_MODE;
SLCR_REG(DDRIOB_DIFF1) |= DDRIOB_TERM_DISABLE_MODE;
}
}
STATIC_ASSERT(IS_ALIGNED(SDRAM_BASE, MB));
@@ -288,14 +291,18 @@ void platform_init_mmu_mappings(void)
void platform_early_init(void)
{
/* Unlock the registers and leave them that way */
#if 0
ps7_init();
#else
zynq_slcr_unlock();
zynq_mio_init();
zynq_pll_init();
zynq_clk_init();
#if ZYNQ_SDRAM_INIT
zynq_ddr_init();
#endif
zynq_slcr_unlock();
#endif
/* Enable all level shifters */
SLCR_REG(LVL_SHFTR_EN) = 0xF;
@@ -305,7 +312,6 @@ void platform_early_init(void)
/* zynq manual says this is mandatory for cache init */
*REG32(SLCR_BASE + 0xa1c) = 0x020202;
zynq_slcr_lock();
/* early initialize the uart so we can printf */
uart_init_early();
@@ -370,7 +376,32 @@ static int cmd_mio(int argc, const cmd_args *argv)
return 0;
}
#define DSR(x) printf("%30s (0x%08lx): 0x%08x\n", #x, (uintptr_t)&SLCR_REG(x), SLCR_REG(x));
static int cmd_slcr(int argc, const cmd_args *argv)
{
if (argc == 2) {
bool print_lock_status = false;
if (!strcmp(argv[1].str, "lock")) {
zynq_slcr_lock();
print_lock_status = true;
} else if (!strcmp(argv[1].str, "unlock")) {
zynq_slcr_unlock();
print_lock_status = true;
} else if (print_lock_status || !strcmp(argv[1].str, "lockstatus")) {
printf("%s\n", (SLCR->SLCR_LOCKSTA & 0x1) ? "locked" : "unlocked");
}
} else {
printf("slcr lock: lock the SCL registers\n");
printf("slcr unlock: unlock the SCL registers\n");
printf("slcr lockstatus: print the SCL lock status\n");
}
return 0;
}
#undef DSR
STATIC_COMMAND_START
STATIC_COMMAND("mio", "print mio configuration", &cmd_mio)
STATIC_COMMAND("slcr", "slcr commands", &cmd_slcr)
STATIC_COMMAND_END(mio);
#endif
#endif // WITH_LIB_CONSOLE

View File

@@ -76,6 +76,17 @@ const unsigned long zynq_ddr_cfg[] = {
const unsigned long zynq_ddr_cfg_cnt = countof(zynq_ddr_cfg);
const zynq_ddriob_cfg_t zynq_ddriob_cfg = {
.addr0 = DDRIOB_OUTPUT_EN(0x3),
.addr1 = DDRIOB_OUTPUT_EN(0x3),
.data0 = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.data1 = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.diff0 = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.diff1 = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.ibuf_disable = false,
.term_disable = false,
};
const uint32_t zynq_mio_cfg[ZYNQ_MIO_CNT] = {
[0] = MIO_IO_TYPE_LVCMOS33,
[1] = MIO_L0_SEL | MIO_IO_TYPE_LVCMOS33,

View File

@@ -77,6 +77,17 @@ const unsigned long zynq_ddr_cfg[] = {
const unsigned long zynq_ddr_cfg_cnt = countof(zynq_ddr_cfg);
const zynq_ddriob_cfg_t zynq_ddriob_cfg = {
.addr0 = DDRIOB_OUTPUT_EN(0x3),
.addr1 = DDRIOB_OUTPUT_EN(0x3),
.data0 = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.data1 = DDRIOB_INP_TYPE(1) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.diff0 = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.diff1 = DDRIOB_INP_TYPE(2) | DDRIOB_TERM_EN | DDRIOB_DCI_TYPE(0x3) | DDRIOB_OUTPUT_EN(0x3),
.ibuf_disable = false,
.term_disable = false,
};
const uint32_t zynq_mio_cfg[ZYNQ_MIO_CNT] = {
[1] = MIO_L0_SEL | MIO_SPEED_FAST | MIO_IO_TYPE_LVCMOS33,
[2] = MIO_L0_SEL | MIO_SPEED_FAST | MIO_IO_TYPE_LVCMOS33,