avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
if ARCH_ROCKCHIP
config ROCKCHIP_RK3288
bool "Support Rockchip RK3288"
help
The Rockchip RK3288 is a ARM-based SoC with a quad-core Cortex-A17
including NEON and GPU, 1MB L2 cache, Mali-T7 graphics, two
video interfaces supporting HDMI and eDP, several DDR3 options
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UART,s, SPI, I2C and PWMs.
config ROCKCHIP_RK3036
bool "Support Rockchip RK3036"
help
The Rockchip RK3036 is a ARM-based SoC with a dual-core Cortex-A7
including NEON and GPU, Mali-400 graphics, several DDR3 options
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
config SYS_MALLOC_F
default y
config SPL_SYS_MALLOC_SIMPLE
default y
config SPL_DM
default y
config DM_SERIAL
default y
config DM_SPI
default y
config DM_SPI_FLASH
default y
config DM_I2C
default y
config DM_GPIO
default y
config BLK
default y
source "arch/arm/mach-rockchip/rk3288/Kconfig"
source "arch/arm/mach-rockchip/rk3036/Kconfig"
endif

View File

@@ -0,0 +1,15 @@
#
# Copyright (c) 2014 Google, Inc
#
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o
obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
else
obj-$(CONFIG_ROCKCHIP_RK3288) += board.o
endif
obj-y += rk_timer.o
obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288/
obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/

View File

@@ -0,0 +1,104 @@
/*
* (C) Copyright 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <ram.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
{
return 0;
}
int dram_init(void)
{
struct ram_info ram;
struct udevice *dev;
int ret;
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
if (ret) {
debug("DRAM init failed: %d\n", ret);
return ret;
}
ret = ram_get_info(dev, &ram);
if (ret) {
debug("Cannot get DRAM size: %d\n", ret);
return ret;
}
debug("SDRAM base=%lx, size=%x\n", ram.base, ram.size);
gd->ram_size = ram.size;
return 0;
}
#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
#endif
void lowlevel_init(void)
{
}
static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
static const struct {
char *name;
int id;
} clks[] = {
{ "osc", CLK_OSC },
{ "apll", CLK_ARM },
{ "dpll", CLK_DDR },
{ "cpll", CLK_CODEC },
{ "gpll", CLK_GENERAL },
#ifdef CONFIG_ROCKCHIP_RK3036
{ "mpll", CLK_NEW },
#else
{ "npll", CLK_NEW },
#endif
};
int ret, i;
struct udevice *dev;
ret = uclass_get_device(UCLASS_CLK, 0, &dev);
if (ret) {
printf("clk-uclass not found\n");
return 0;
}
for (i = 0; i < ARRAY_SIZE(clks); i++) {
struct clk clk;
ulong rate;
clk.id = clks[i].id;
ret = clk_request(dev, &clk);
if (ret < 0)
continue;
rate = clk_get_rate(&clk);
printf("%s: %lu\n", clks[i].name, rate);
clk_free(&clk);
}
return 0;
}
U_BOOT_CMD(
clock, 2, 1, do_clock,
"display information about clocks",
""
);

View File

@@ -0,0 +1,62 @@
/*
* (C) Copyright 2015 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <debug_uart.h>
#include <asm/io.h>
#include <asm/arch/grf_rk3036.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sdram_rk3036.h>
#include <asm/arch/timer.h>
#include <asm/arch/uart.h>
DECLARE_GLOBAL_DATA_PTR;
#define GRF_BASE 0x20008000
static struct rk3036_grf * const grf = (void *)GRF_BASE;
#define DEBUG_UART_BASE 0x20068000
extern void back_to_bootrom(void);
void board_init_f(ulong dummy)
{
#ifdef EARLY_DEBUG
/*
* NOTE: sd card and debug uart use same iomux in rk3036,
* so if you enable uart,
* you can not boot from sdcard
*/
rk_clrsetreg(&grf->gpio1c_iomux,
GPIO1C3_MASK << GPIO1C3_SHIFT |
GPIO1C2_MASK << GPIO1C2_SHIFT,
GPIO1C3_UART2_SOUT << GPIO1C3_SHIFT |
GPIO1C2_UART2_SIN << GPIO1C2_SHIFT);
debug_uart_init();
#endif
rockchip_timer_init();
sdram_init();
/* return to maskrom */
back_to_bootrom();
}
/* Place Holders */
void board_init_r(gd_t *id, ulong dest_addr)
{
/*
* Function attribute is no-return
* This Function never executes
*/
while (1)
;
}
void hang(void)
{
while (1)
;
}

View File

@@ -0,0 +1,21 @@
if ROCKCHIP_RK3036
config TARGET_EVB_RK3036
bool "EVB_RK3036"
config TARGET_KYLIN_RK3036
bool "KYLIN_RK3036"
config SYS_SOC
default "rockchip"
config SYS_MALLOC_F_LEN
default 0x400
config ROCKCHIP_COMMON
bool "Support rk common fuction"
source "board/evb_rk3036/evb_rk3036/Kconfig"
source "board/kylin/kylin_rk3036/Kconfig"
endif

View File

@@ -0,0 +1,13 @@
#
# (C) Copyright 2015 Rockchip Electronics Co., Ltd
#
# SPDX-License-Identifier: GPL-2.0+
#
ifndef CONFIG_SPL_BUILD
obj-y += reset_rk3036.o
obj-y += syscon_rk3036.o
endif
obj-y += sdram_rk3036.o
obj-y += save_boot_param.o

View File

@@ -0,0 +1,45 @@
/*
* (C) Copyright 2015 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <sysreset.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rk3036.h>
#include <asm/arch/hardware.h>
#include <linux/err.h>
int rk3036_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
struct rk3036_cru *cru = rockchip_get_cru();
if (IS_ERR(cru))
return PTR_ERR(cru);
switch (type) {
case SYSRESET_WARM:
writel(0xeca8, &cru->cru_glb_srst_snd_value);
break;
case SYSRESET_COLD:
writel(0xfdb9, &cru->cru_glb_srst_fst_value);
break;
default:
return -EPROTONOSUPPORT;
}
return -EINPROGRESS;
}
static struct sysreset_ops rk3036_sysreset = {
.request = rk3036_sysreset_request,
};
U_BOOT_DRIVER(sysreset_rk3036) = {
.name = "rk3036_sysreset",
.id = UCLASS_SYSRESET,
.ops = &rk3036_sysreset,
};

View File

@@ -0,0 +1,32 @@
/*
* (C) Copyright 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/linkage.h>
.globl SAVE_SP_ADDR
SAVE_SP_ADDR:
.word 0
/*
* void save_boot_params
*
* Save sp, lr, r1~r12
*/
ENTRY(save_boot_params)
push {r1-r12, lr}
ldr r0, =SAVE_SP_ADDR
str sp, [r0]
b save_boot_params_ret @ back to my caller
ENDPROC(save_boot_params)
.globl back_to_bootrom
ENTRY(back_to_bootrom)
ldr r0, =SAVE_SP_ADDR
ldr sp, [r0]
mov r0, #0
pop {r1-r12, pc}
ENDPROC(back_to_bootrom)

View File

@@ -0,0 +1,768 @@
/*
* (C) Copyright 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/types.h>
#include <asm/arch/cru_rk3036.h>
#include <asm/arch/grf_rk3036.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sdram_rk3036.h>
#include <asm/arch/timer.h>
#include <asm/arch/uart.h>
/*
* we can not fit the code to access the device tree in SPL
* (due to 4K SRAM size limits), so these are hard-coded
*/
#define CRU_BASE 0x20000000
#define GRF_BASE 0x20008000
#define DDR_PHY_BASE 0x2000a000
#define DDR_PCTL_BASE 0x20004000
#define CPU_AXI_BUS_BASE 0x10128000
struct rk3036_sdram_priv {
struct rk3036_cru *cru;
struct rk3036_grf *grf;
struct rk3036_ddr_phy *phy;
struct rk3036_ddr_pctl *pctl;
struct rk3036_service_sys *axi_bus;
/* ddr die config */
struct rk3036_ddr_config ddr_config;
};
/* use integer mode, 396MHz dpll setting
* refdiv, fbdiv, postdiv1, postdiv2
*/
const struct pll_div dpll_init_cfg = {1, 50, 3, 1};
/* 396Mhz ddr timing */
const struct rk3036_ddr_timing ddr_timing = {0x18c,
{0x18c, 0xc8, 0x1f4, 0x27, 0x4e,
0x4, 0x8b, 0x06, 0x03, 0x0, 0x06, 0x05, 0x0f, 0x15, 0x06, 0x04, 0x04,
0x06, 0x04, 0x200, 0x03, 0x0a, 0x40, 0x2710, 0x01, 0x05, 0x05, 0x03,
0x0c, 0x28, 0x100, 0x0, 0x04, 0x0},
{{0x420, 0x42, 0x0, 0x0}, 0x01, 0x60},
{0x24717315} };
/*
* [7:6] bank(n:n bit bank)
* [5:4] row(13+n)
* [3] cs(0:1 cs, 1:2 cs)
* [2:1] bank(n:n bit bank)
* [0] col(10+n)
*/
const char ddr_cfg_2_rbc[] = {
((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 1),
((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 0),
((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 0),
((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 0),
((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 1),
((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 1),
((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 1),
((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 0),
((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 1),
((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 0),
((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 1),
((1 << 6) | (2 << 4) | (0 << 3) | (2 << 1) | 0),
((3 << 6) | (2 << 4) | (0 << 3) | (0 << 1) | 1),
((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 0),
};
/* DDRPHY REG */
enum {
/* DDRPHY_REG1 */
SOFT_RESET_MASK = 3,
SOFT_RESET_SHIFT = 2,
/* DDRPHY_REG2 */
MEMORY_SELECT_DDR3 = 0 << 6,
DQS_SQU_CAL_NORMAL_MODE = 0 << 1,
DQS_SQU_CAL_START = 1 << 0,
DQS_SQU_NO_CAL = 0 << 0,
/* DDRPHY_REG2A */
CMD_DLL_BYPASS = 1 << 4,
CMD_DLL_BYPASS_DISABLE = 0 << 4,
HIGH_8BIT_DLL_BYPASS = 1 << 3,
HIGH_8BIT_DLL_BYPASS_DISABLE = 0 << 3,
LOW_8BIT_DLL_BYPASS = 1 << 2,
LOW_8BIT_DLL_BYPASS_DISABLE = 0 << 2,
/* DDRPHY_REG19 */
CMD_FEEDBACK_ENABLE = 1 << 5,
CMD_SLAVE_DLL_INVERSE_MODE = 1 << 4,
CMD_SLAVE_DLL_NO_INVERSE_MODE = 0 << 4,
CMD_SLAVE_DLL_ENALBE = 1 << 3,
CMD_TX_SLAVE_DLL_DELAY_MASK = 7,
CMD_TX_SLAVE_DLL_DELAY_SHIFT = 0,
/* DDRPHY_REG6 */
LEFT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4,
LEFT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4,
LEFT_CHN_TX_DQ_DLL_ENABLE = 1 << 3,
LEFT_CHN_TX_DQ_DLL_DELAY_MASK = 7,
LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0,
/* DDRPHY_REG8 */
LEFT_CHN_RX_DQS_DELAY_TAP_MASK = 3,
LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0,
/* DDRPHY_REG9 */
RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4,
RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4,
RIGHT_CHN_TX_DQ_DLL_ENABLE = 1 << 3,
RIGHT_CHN_TX_DQ_DLL_DELAY_MASK = 7,
RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0,
/* DDRPHY_REG11 */
RIGHT_CHN_RX_DQS_DELAY_TAP_MASK = 3,
RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0,
/* DDRPHY_REG62 */
CAL_DONE_MASK = 3,
HIGH_8BIT_CAL_DONE = 1 << 1,
LOW_8BIT_CAL_DONE = 1 << 0,
};
/* PTCL */
enum {
/* PCTL_DFISTCFG0 */
DFI_INIT_START = 1 << 0,
DFI_DATA_BYTE_DISABLE_EN = 1 << 2,
/* PCTL_DFISTCFG1 */
DFI_DRAM_CLK_SR_EN = 1 << 0,
DFI_DRAM_CLK_DPD_EN = 1 << 1,
/* PCTL_DFISTCFG2 */
DFI_PARITY_INTR_EN = 1 << 0,
DFI_PARITY_EN = 1 << 1,
/* PCTL_DFILPCFG0 */
TLP_RESP_TIME_SHIFT = 16,
LP_SR_EN = 1 << 8,
LP_PD_EN = 1 << 0,
/* PCTL_DFIODTCFG */
RANK0_ODT_WRITE_SEL = 1 << 3,
RANK1_ODT_WRITE_SEL = 1 << 11,
/* PCTL_DFIODTCFG1 */
ODT_LEN_BL8_W_SHIFT = 16,
/* PCTL_MCFG */
TFAW_CFG_MASK = 3,
TFAW_CFG_SHIFT = 18,
PD_EXIT_SLOW_MODE = 0 << 17,
PD_ACTIVE_POWER_DOWN = 1 << 16,
PD_IDLE_MASK = 0xff,
PD_IDLE_SHIFT = 8,
MEM_BL4 = 0 << 0,
MEM_BL8 = 1 << 0,
/* PCTL_MCFG1 */
HW_EXIT_IDLE_EN_MASK = 1,
HW_EXIT_IDLE_EN_SHIFT = 31,
SR_IDLE_MASK = 0x1ff,
SR_IDLE_SHIFT = 0,
/* PCTL_SCFG */
HW_LOW_POWER_EN = 1 << 0,
/* PCTL_POWCTL */
POWER_UP_START = 1 << 0,
/* PCTL_POWSTAT */
POWER_UP_DONE = 1 << 0,
/* PCTL_MCMD */
START_CMD = 1 << 31,
BANK_ADDR_MASK = 7,
BANK_ADDR_SHIFT = 17,
CMD_ADDR_MASK = 0x1fff,
CMD_ADDR_SHIFT = 4,
DESELECT_CMD = 0,
PREA_CMD,
REF_CMD,
MRS_CMD,
ZQCS_CMD,
ZQCL_CMD,
RSTL_CMD,
MRR_CMD = 8,
/* PCTL_STAT */
INIT_MEM = 0,
CONFIG,
CONFIG_REQ,
ACCESS,
ACCESS_REQ,
LOW_POWER,
LOW_POWER_ENTRY_REQ,
LOW_POWER_EXIT_REQ,
PCTL_STAT_MASK = 7,
/* PCTL_SCTL */
INIT_STATE = 0,
CFG_STATE = 1,
GO_STATE = 2,
SLEEP_STATE = 3,
WAKEUP_STATE = 4,
};
/* GRF_SOC_CON2 */
#define MSCH4_MAINDDR3 (1 << 7)
#define PHY_DRV_ODT_SET(n) ((n << 4) | n)
#define DDR3_DLL_RESET (1 << 8)
/* CK pull up/down driver strength control */
enum {
PHY_RON_DISABLE = 0,
PHY_RON_309OHM = 1,
PHY_RON_155OHM,
PHY_RON_103OHM = 3,
PHY_RON_63OHM = 5,
PHY_RON_45OHM = 7,
PHY_RON_77OHM,
PHY_RON_62OHM,
PHY_RON_52OHM,
PHY_RON_44OHM,
PHY_RON_39OHM,
PHY_RON_34OHM,
PHY_RON_31OHM,
PHY_RON_28OHM,
};
/* DQ pull up/down control */
enum {
PHY_RTT_DISABLE = 0,
PHY_RTT_861OHM = 1,
PHY_RTT_431OHM,
PHY_RTT_287OHM,
PHY_RTT_216OHM,
PHY_RTT_172OHM,
PHY_RTT_145OHM,
PHY_RTT_124OHM,
PHY_RTT_215OHM,
PHY_RTT_144OHM = 0xa,
PHY_RTT_123OHM,
PHY_RTT_108OHM,
PHY_RTT_96OHM,
PHY_RTT_86OHM,
PHY_RTT_78OHM,
};
/* DQS squelch DLL delay */
enum {
DQS_DLL_NO_DELAY = 0,
DQS_DLL_22P5_DELAY,
DQS_DLL_45_DELAY,
DQS_DLL_67P5_DELAY,
DQS_DLL_90_DELAY,
DQS_DLL_112P5_DELAY,
DQS_DLL_135_DELAY,
DQS_DLL_157P5_DELAY,
};
/* GRF_OS_REG1 */
enum {
/*
* 000: lpddr
* 001: ddr
* 010: ddr2
* 011: ddr3
* 100: lpddr2-s2
* 101: lpddr2-s4
* 110: lpddr3
*/
DDR_TYPE_MASK = 7,
DDR_TYPE_SHIFT = 13,
/* 0: 1 chn, 1: 2 chn */
DDR_CHN_CNT_SHIFT = 12,
/* 0: 1 rank, 1: 2 rank */
DDR_RANK_CNT_MASK = 1,
DDR_RANK_CNT_SHIFT = 11,
/*
* 00: 9col
* 01: 10col
* 10: 11col
* 11: 12col
*/
DDR_COL_MASK = 3,
DDR_COL_SHIFT = 9,
/* 0: 8 bank, 1: 4 bank*/
DDR_BANK_MASK = 1,
DDR_BANK_SHIFT = 8,
/*
* 00: 13 row
* 01: 14 row
* 10: 15 row
* 11: 16 row
*/
DDR_CS0_ROW_MASK = 3,
DDR_CS0_ROW_SHIFT = 6,
DDR_CS1_ROW_MASK = 3,
DDR_CS1_ROW_SHIFT = 4,
/*
* 00: 32 bit
* 01: 16 bit
* 10: 8 bit
* rk3036 only support 16bit
*/
DDR_BW_MASK = 3,
DDR_BW_SHIFT = 2,
DDR_DIE_BW_MASK = 3,
DDR_DIE_BW_SHIFT = 0,
};
static void rkdclk_init(struct rk3036_sdram_priv *priv)
{
struct rk3036_pll *pll = &priv->cru->pll[1];
/* pll enter slow-mode */
rk_clrsetreg(&priv->cru->cru_mode_con,
DPLL_MODE_MASK << DPLL_MODE_SHIFT,
DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
/* use integer mode */
rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
rk_clrsetreg(&pll->con0,
PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK,
(dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) |
dpll_init_cfg.fbdiv);
rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
PLL_REFDIV_MASK << PLL_REFDIV_SHIFT,
(dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT |
dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT));
/* waiting for pll lock */
while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
rockchip_udelay(1);
/* PLL enter normal-mode */
rk_clrsetreg(&priv->cru->cru_mode_con,
DPLL_MODE_MASK << DPLL_MODE_SHIFT,
DPLL_MODE_NORM << DPLL_MODE_SHIFT);
}
static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
{
int i;
for (i = 0; i < n / sizeof(u32); i++) {
writel(*src, dest);
src++;
dest++;
}
}
void phy_pctrl_reset(struct rk3036_sdram_priv *priv)
{
struct rk3036_ddr_phy *ddr_phy = priv->phy;
rk_clrsetreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT,
1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
rockchip_udelay(10);
rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT);
rockchip_udelay(10);
rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT);
rockchip_udelay(10);
clrsetbits_le32(&ddr_phy->ddrphy_reg1,
SOFT_RESET_MASK << SOFT_RESET_SHIFT,
0 << SOFT_RESET_SHIFT);
rockchip_udelay(10);
clrsetbits_le32(&ddr_phy->ddrphy_reg1,
SOFT_RESET_MASK << SOFT_RESET_SHIFT,
3 << SOFT_RESET_SHIFT);
rockchip_udelay(1);
}
void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq)
{
struct rk3036_ddr_phy *ddr_phy = priv->phy;
if (freq < ddr_timing.freq) {
writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS |
LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a);
writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_90 |
LEFT_CHN_TX_DQ_DLL_ENABLE |
(0 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) <<
LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg6);
writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 |
RIGHT_CHN_TX_DQ_DLL_ENABLE |
(0 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) <<
RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT,
&ddr_phy->ddrphy_reg9);
} else {
writel(CMD_DLL_BYPASS_DISABLE | HIGH_8BIT_DLL_BYPASS_DISABLE |
LOW_8BIT_DLL_BYPASS_DISABLE, &ddr_phy->ddrphy_reg2a);
writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_0 |
LEFT_CHN_TX_DQ_DLL_ENABLE |
(4 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) <<
LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT,
&ddr_phy->ddrphy_reg6);
writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 |
RIGHT_CHN_TX_DQ_DLL_ENABLE |
(4 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) <<
RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT,
&ddr_phy->ddrphy_reg9);
}
writel(CMD_SLAVE_DLL_NO_INVERSE_MODE | CMD_SLAVE_DLL_ENALBE |
(0 & CMD_TX_SLAVE_DLL_DELAY_MASK) <<
CMD_TX_SLAVE_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg19);
/* 45 degree delay */
writel((DQS_DLL_45_DELAY & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) <<
LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8);
writel((DQS_DLL_45_DELAY & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) <<
RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11);
}
static void send_command(struct rk3036_ddr_pctl *pctl,
u32 rank, u32 cmd, u32 arg)
{
writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
rockchip_udelay(1);
while (readl(&pctl->mcmd) & START_CMD)
;
}
static void memory_init(struct rk3036_sdram_priv *priv)
{
struct rk3036_ddr_pctl *pctl = priv->pctl;
send_command(pctl, 3, DESELECT_CMD, 0);
rockchip_udelay(1);
send_command(pctl, 3, PREA_CMD, 0);
send_command(pctl, 3, MRS_CMD,
(0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(pctl, 3, MRS_CMD,
(0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(pctl, 3, MRS_CMD,
(0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(pctl, 3, MRS_CMD,
(0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[0] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT | DDR3_DLL_RESET);
send_command(pctl, 3, ZQCL_CMD, 0);
}
static void data_training(struct rk3036_sdram_priv *priv)
{
struct rk3036_ddr_phy *ddr_phy = priv->phy;
struct rk3036_ddr_pctl *pctl = priv->pctl;
u32 value;
/* disable auto refresh */
value = readl(&pctl->trefi),
writel(0, &pctl->trefi);
clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03,
DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START);
rockchip_udelay(1);
while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) !=
(HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) {
;
}
clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03,
DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_NO_CAL);
/*
* since data training will take about 20us, so send some auto
* refresh(about 7.8us) to complement the lost time
*/
send_command(pctl, 3, REF_CMD, 0);
send_command(pctl, 3, REF_CMD, 0);
send_command(pctl, 3, REF_CMD, 0);
writel(value, &pctl->trefi);
}
static void move_to_config_state(struct rk3036_sdram_priv *priv)
{
unsigned int state;
struct rk3036_ddr_pctl *pctl = priv->pctl;
while (1) {
state = readl(&pctl->stat) & PCTL_STAT_MASK;
switch (state) {
case LOW_POWER:
writel(WAKEUP_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK)
!= ACCESS)
;
/*
* If at low power state, need wakeup first, and then
* enter the config, so fallthrough
*/
case ACCESS:
/* fallthrough */
case INIT_MEM:
writel(CFG_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
;
break;
case CONFIG:
return;
default:
break;
}
}
}
static void move_to_access_state(struct rk3036_sdram_priv *priv)
{
unsigned int state;
struct rk3036_ddr_pctl *pctl = priv->pctl;
while (1) {
state = readl(&pctl->stat) & PCTL_STAT_MASK;
switch (state) {
case LOW_POWER:
writel(WAKEUP_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
;
break;
case INIT_MEM:
writel(CFG_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
;
/* fallthrough */
case CONFIG:
writel(GO_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
;
break;
case ACCESS:
return;
default:
break;
}
}
}
static void pctl_cfg(struct rk3036_sdram_priv *priv)
{
struct rk3036_ddr_pctl *pctl = priv->pctl;
u32 burst_len;
u32 reg;
writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0);
writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1);
writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2);
writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN,
&pctl->dfilpcfg0);
writel(1, &pctl->dfitphyupdtype0);
writel(0x0d, &pctl->dfitphyrdlat);
/* cs0 and cs1 write odt enable */
writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
&pctl->dfiodtcfg);
/* odt write length */
writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1);
/* phyupd and ctrlupd disabled */
writel(0, &pctl->dfiupdcfg);
if ((ddr_timing.noc_timing.burstlen << 1) == 4)
burst_len = MEM_BL4;
else
burst_len = MEM_BL8;
copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u,
sizeof(struct rk3036_pctl_timing));
reg = readl(&pctl->tcl);
writel(reg - 3, &pctl->dfitrddataen);
reg = readl(&pctl->tcwl);
writel(reg - 1, &pctl->dfitphywrlat);
writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT |
PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN |
(0 & PD_IDLE_MASK) << PD_IDLE_SHIFT,
&pctl->mcfg);
writel(RK_SETBITS(MSCH4_MAINDDR3), &priv->grf->soc_con2);
setbits_le32(&pctl->scfg, HW_LOW_POWER_EN);
}
static void phy_cfg(struct rk3036_sdram_priv *priv)
{
struct rk3036_ddr_phy *ddr_phy = priv->phy;
struct rk3036_service_sys *axi_bus = priv->axi_bus;
writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming);
writel(0x3f, &axi_bus->readlatency);
writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE,
&ddr_phy->ddrphy_reg2);
clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl);
writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a);
writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16);
writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22);
writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25);
writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26);
writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27);
writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28);
}
void dram_cfg_rbc(struct rk3036_sdram_priv *priv)
{
char noc_config;
int i = 0;
struct rk3036_ddr_config config = priv->ddr_config;
struct rk3036_service_sys *axi_bus = priv->axi_bus;
move_to_config_state(priv);
/* 2bit in BIT1, 2 */
if (config.rank == 2) {
noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
1 << 3 | (config.col - 10);
if (noc_config == ddr_cfg_2_rbc[9]) {
i = 9;
goto finish;
} else if (noc_config == ddr_cfg_2_rbc[10]) {
i = 10;
goto finish;
}
}
noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
(config.col - 10);
for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) {
if (noc_config == ddr_cfg_2_rbc[i])
goto finish;
}
/* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */
noc_config = 1 << 6 | (config.cs0_row - 13) << 4 |
2 << 1 | (config.col - 10);
if (noc_config == ddr_cfg_2_rbc[11]) {
i = 11;
goto finish;
}
/* bank: 2bit in BIT6,7 */
noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 |
(config.col - 10);
if (noc_config == ddr_cfg_2_rbc[0])
i = 0;
else if (noc_config == ddr_cfg_2_rbc[12])
i = 12;
else if (noc_config == ddr_cfg_2_rbc[13])
i = 13;
finish:
writel(i, &axi_bus->ddrconf);
move_to_access_state(priv);
}
static void sdram_all_config(struct rk3036_sdram_priv *priv)
{
u32 os_reg = 0;
u32 cs1_row = 0;
struct rk3036_ddr_config config = priv->ddr_config;
if (config.rank > 1)
cs1_row = config.cs1_row - 13;
os_reg = config.ddr_type << DDR_TYPE_SHIFT |
0 << DDR_CHN_CNT_SHIFT |
(config.rank - 1) << DDR_RANK_CNT_SHIFT |
(config.col - 1) << DDR_COL_SHIFT |
(config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT |
(config.cs0_row - 13) << DDR_CS0_ROW_SHIFT |
cs1_row << DDR_CS1_ROW_SHIFT |
1 << DDR_BW_SHIFT | config.bw << DDR_DIE_BW_SHIFT;
writel(os_reg, &priv->grf->os_reg[1]);
}
size_t sdram_size(void)
{
u32 size, os_reg, cs0_row, cs1_row, col, bank, rank;
struct rk3036_grf *grf = (void *)GRF_BASE;
os_reg = readl(&grf->os_reg[1]);
cs0_row = 13 + ((os_reg >> DDR_CS0_ROW_SHIFT) & DDR_CS0_ROW_MASK);
cs1_row = 13 + ((os_reg >> DDR_CS1_ROW_SHIFT) & DDR_CS1_ROW_MASK);
col = 9 + ((os_reg >> DDR_COL_SHIFT) & DDR_COL_MASK);
bank = 3 - ((os_reg >> DDR_BANK_SHIFT) & DDR_BANK_MASK);
rank = 1 + ((os_reg >> DDR_RANK_CNT_SHIFT) & DDR_RANK_CNT_MASK);
/* row + col + bank + bw(rk3036 only support 16bit, so fix in 1) */
size = 1 << (cs0_row + col + bank + 1);
if (rank > 1)
size += size >> (cs0_row - cs1_row);
return size;
}
void sdram_init(void)
{
struct rk3036_sdram_priv sdram_priv;
sdram_priv.cru = (void *)CRU_BASE;
sdram_priv.grf = (void *)GRF_BASE;
sdram_priv.phy = (void *)DDR_PHY_BASE;
sdram_priv.pctl = (void *)DDR_PCTL_BASE;
sdram_priv.axi_bus = (void *)CPU_AXI_BUS_BASE;
get_ddr_config(&sdram_priv.ddr_config);
sdram_all_config(&sdram_priv);
rkdclk_init(&sdram_priv);
phy_pctrl_reset(&sdram_priv);
phy_dll_bypass_set(&sdram_priv, ddr_timing.freq);
pctl_cfg(&sdram_priv);
phy_cfg(&sdram_priv);
writel(POWER_UP_START, &sdram_priv.pctl->powctl);
while (!(readl(&sdram_priv.pctl->powstat) & POWER_UP_DONE))
;
memory_init(&sdram_priv);
move_to_config_state(&sdram_priv);
data_training(&sdram_priv);
move_to_access_state(&sdram_priv);
dram_cfg_rbc(&sdram_priv);
}

View File

@@ -0,0 +1,21 @@
/*
* (C) Copyright 2015 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <syscon.h>
#include <asm/arch/clock.h>
static const struct udevice_id rk3036_syscon_ids[] = {
{ .compatible = "rockchip,rk3036-grf", .data = ROCKCHIP_SYSCON_GRF },
{ }
};
U_BOOT_DRIVER(syscon_rk3036) = {
.name = "rk3036_syscon",
.id = UCLASS_SYSCON,
.of_match = rk3036_syscon_ids,
};

View File

@@ -0,0 +1,280 @@
/*
* (C) Copyright 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <debug_uart.h>
#include <dm.h>
#include <fdtdec.h>
#include <led.h>
#include <malloc.h>
#include <ram.h>
#include <spl.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/hardware.h>
#include <asm/arch/periph.h>
#include <asm/arch/sdram.h>
#include <asm/arch/timer.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <dm/test.h>
#include <dm/util.h>
#include <power/regulator.h>
DECLARE_GLOBAL_DATA_PTR;
u32 spl_boot_device(void)
{
const void *blob = gd->fdt_blob;
struct udevice *dev;
const char *bootdev;
int node;
int ret;
bootdev = fdtdec_get_config_string(blob, "u-boot,boot0");
debug("Boot device %s\n", bootdev);
if (!bootdev)
goto fallback;
node = fdt_path_offset(blob, bootdev);
if (node < 0) {
debug("node=%d\n", node);
goto fallback;
}
ret = device_get_global_by_of_offset(node, &dev);
if (ret) {
debug("device at node %s/%d not found: %d\n", bootdev, node,
ret);
goto fallback;
}
debug("Found device %s\n", dev->name);
switch (device_get_uclass_id(dev)) {
case UCLASS_SPI_FLASH:
return BOOT_DEVICE_SPI;
case UCLASS_MMC:
return BOOT_DEVICE_MMC1;
default:
debug("Booting from device uclass '%s' not supported\n",
dev_get_uclass_name(dev));
}
fallback:
return BOOT_DEVICE_MMC1;
}
u32 spl_boot_mode(const u32 boot_device)
{
return MMCSD_MODE_RAW;
}
/* read L2 control register (L2CTLR) */
static inline uint32_t read_l2ctlr(void)
{
uint32_t val = 0;
asm volatile ("mrc p15, 1, %0, c9, c0, 2" : "=r" (val));
return val;
}
/* write L2 control register (L2CTLR) */
static inline void write_l2ctlr(uint32_t val)
{
/*
* Note: L2CTLR can only be written when the L2 memory system
* is idle, ie before the MMU is enabled.
*/
asm volatile("mcr p15, 1, %0, c9, c0, 2" : : "r" (val) : "memory");
isb();
}
static void configure_l2ctlr(void)
{
uint32_t l2ctlr;
l2ctlr = read_l2ctlr();
l2ctlr &= 0xfffc0000; /* clear bit0~bit17 */
/*
* Data RAM write latency: 2 cycles
* Data RAM read latency: 2 cycles
* Data RAM setup latency: 1 cycle
* Tag RAM write latency: 1 cycle
* Tag RAM read latency: 1 cycle
* Tag RAM setup latency: 1 cycle
*/
l2ctlr |= (1 << 3 | 1 << 0);
write_l2ctlr(l2ctlr);
}
#ifdef CONFIG_SPL_MMC_SUPPORT
static int configure_emmc(struct udevice *pinctrl)
{
#if !defined(CONFIG_TARGET_ROCK2) && !defined(CONFIG_TARGET_FIREFLY_RK3288)
struct gpio_desc desc;
int ret;
pinctrl_request_noflags(pinctrl, PERIPH_ID_EMMC);
/*
* TODO(sjg@chromium.org): Pick this up from device tree or perhaps
* use the EMMC_PWREN setting.
*/
ret = dm_gpio_lookup_name("D9", &desc);
if (ret) {
debug("gpio ret=%d\n", ret);
return ret;
}
ret = dm_gpio_request(&desc, "emmc_pwren");
if (ret) {
debug("gpio_request ret=%d\n", ret);
return ret;
}
ret = dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
if (ret) {
debug("gpio dir ret=%d\n", ret);
return ret;
}
ret = dm_gpio_set_value(&desc, 1);
if (ret) {
debug("gpio value ret=%d\n", ret);
return ret;
}
#endif
return 0;
}
#endif
void board_init_f(ulong dummy)
{
struct udevice *pinctrl;
struct udevice *dev;
int ret;
/* Example code showing how to enable the debug UART on RK3288 */
#ifdef EARLY_UART
#include <asm/arch/grf_rk3288.h>
/* Enable early UART on the RK3288 */
#define GRF_BASE 0xff770000
struct rk3288_grf * const grf = (void *)GRF_BASE;
rk_clrsetreg(&grf->gpio7ch_iomux, GPIO7C7_MASK << GPIO7C7_SHIFT |
GPIO7C6_MASK << GPIO7C6_SHIFT,
GPIO7C7_UART2DBG_SOUT << GPIO7C7_SHIFT |
GPIO7C6_UART2DBG_SIN << GPIO7C6_SHIFT);
/*
* Debug UART can be used from here if required:
*
* debug_uart_init();
* printch('a');
* printhex8(0x1234);
* printascii("string");
*/
debug_uart_init();
#endif
ret = spl_init();
if (ret) {
debug("spl_init() failed: %d\n", ret);
hang();
}
rockchip_timer_init();
configure_l2ctlr();
ret = uclass_get_device(UCLASS_CLK, 0, &dev);
if (ret) {
debug("CLK init failed: %d\n", ret);
return;
}
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
if (ret) {
debug("Pinctrl init failed: %d\n", ret);
return;
}
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
if (ret) {
debug("DRAM init failed: %d\n", ret);
return;
}
}
static int setup_led(void)
{
#ifdef CONFIG_SPL_LED
struct udevice *dev;
char *led_name;
int ret;
led_name = fdtdec_get_config_string(gd->fdt_blob, "u-boot,boot-led");
if (!led_name)
return 0;
ret = led_get_by_label(led_name, &dev);
if (ret) {
debug("%s: get=%d\n", __func__, ret);
return ret;
}
ret = led_set_on(dev, 1);
if (ret)
return ret;
#endif
return 0;
}
void spl_board_init(void)
{
struct udevice *pinctrl;
int ret;
ret = setup_led();
if (ret) {
debug("LED ret=%d\n", ret);
hang();
}
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
if (ret) {
debug("%s: Cannot find pinctrl device\n", __func__);
goto err;
}
#ifdef CONFIG_SPL_MMC_SUPPORT
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
if (ret) {
debug("%s: Failed to set up SD card\n", __func__);
goto err;
}
ret = configure_emmc(pinctrl);
if (ret) {
debug("%s: Failed to set up eMMC\n", __func__);
goto err;
}
#endif
/* Enable debug UART */
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_UART_DBG);
if (ret) {
debug("%s: Failed to set up console UART\n", __func__);
goto err;
}
preloader_console_init();
return;
err:
printf("spl_board_init: Error %d\n", ret);
/* No way to report error here */
hang();
}
void lowlevel_init(void)
{
}

View File

@@ -0,0 +1,48 @@
if ROCKCHIP_RK3288
config TARGET_FIREFLY_RK3288
bool "Firefly-RK3288"
help
Firefly is a RK3288-based development board with 2 USB ports,
HDMI, VGA, micro-SD card, audio, WiFi and Gigabit Ethernet, It
also includes on-board eMMC and 1GB of SDRAM. Expansion connectors
provide access to display pins, I2C, SPI, UART and GPIOs.
config TARGET_CHROMEBOOK_JERRY
bool "Google/Rockchip Veyron-Jerry Chromebook"
help
Jerry is a RK3288-based clamshell device with 2 USB 3.0 ports,
HDMI, an 11.9 inch EDP display, micro-SD card, touchpad and
WiFi. It includes a Chrome OS EC (Cortex-M3) to provide access to
the keyboard and battery functions.
config TARGET_ROCK2
bool "Radxa Rock 2"
help
Rock 2 is a SOM and base-board combination based on RK3288. It
includes Ethernet, HDMI, 3 USB, micro-SD, audio, SATA, WiFi and
space for a real-time-clock battery. There is also an expansion
interface which provides access to many pins.
config ROCKCHIP_FAST_SPL
bool "Change the CPU to full speed in SPL"
depends on TARGET_CHROMEBOOK_JERRY
help
Some boards want to boot as fast as possible. We can increase the
CPU frequency in SPL if the power supply is configured to the correct
voltage. This option is only available on boards which support it
and have the required PMIC code.
config SYS_SOC
default "rockchip"
config SYS_MALLOC_F_LEN
default 0x0800
source "board/google/chromebook_jerry/Kconfig"
source "board/firefly/firefly-rk3288/Kconfig"
source "board/radxa/rock2/Kconfig"
endif

View File

@@ -0,0 +1,9 @@
#
# Copyright (c) 2015 Google, Inc
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += reset_rk3288.o
obj-y += sdram_rk3288.o
obj-y += syscon_rk3288.o

View File

@@ -0,0 +1,47 @@
/*
* (C) Copyright 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <sysreset.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rk3288.h>
#include <asm/arch/hardware.h>
#include <linux/err.h>
int rk3288_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
struct rk3288_cru *cru = rockchip_get_cru();
if (IS_ERR(cru))
return PTR_ERR(cru);
switch (type) {
case SYSRESET_WARM:
rk_clrreg(&cru->cru_mode_con, 0xffff);
writel(0xeca8, &cru->cru_glb_srst_snd_value);
break;
case SYSRESET_COLD:
rk_clrreg(&cru->cru_mode_con, 0xffff);
writel(0xfdb9, &cru->cru_glb_srst_fst_value);
break;
default:
return -EPROTONOSUPPORT;
}
return -EINPROGRESS;
}
static struct sysreset_ops rk3288_sysreset = {
.request = rk3288_sysreset_request,
};
U_BOOT_DRIVER(sysreset_rk3288) = {
.name = "rk3288_sysreset",
.id = UCLASS_SYSRESET,
.ops = &rk3288_sysreset,
};

View File

@@ -0,0 +1,907 @@
/*
* (C) Copyright 2015 Google, Inc
* Copyright 2014 Rockchip Inc.
*
* SPDX-License-Identifier: GPL-2.0
*
* Adapted from coreboot.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <ram.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rk3288.h>
#include <asm/arch/ddr_rk3288.h>
#include <asm/arch/grf_rk3288.h>
#include <asm/arch/pmu_rk3288.h>
#include <asm/arch/sdram.h>
#include <linux/err.h>
#include <power/regulator.h>
#include <power/rk808_pmic.h>
DECLARE_GLOBAL_DATA_PTR;
struct chan_info {
struct rk3288_ddr_pctl *pctl;
struct rk3288_ddr_publ *publ;
struct rk3288_msch *msch;
};
struct dram_info {
struct chan_info chan[2];
struct ram_info info;
struct clk ddr_clk;
struct rk3288_cru *cru;
struct rk3288_grf *grf;
struct rk3288_sgrf *sgrf;
struct rk3288_pmu *pmu;
};
#ifdef CONFIG_SPL_BUILD
static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
{
int i;
for (i = 0; i < n / sizeof(u32); i++) {
writel(*src, dest);
src++;
dest++;
}
}
static void ddr_reset(struct rk3288_cru *cru, u32 ch, u32 ctl, u32 phy)
{
u32 phy_ctl_srstn_shift = 4 + 5 * ch;
u32 ctl_psrstn_shift = 3 + 5 * ch;
u32 ctl_srstn_shift = 2 + 5 * ch;
u32 phy_psrstn_shift = 1 + 5 * ch;
u32 phy_srstn_shift = 5 * ch;
rk_clrsetreg(&cru->cru_softrst_con[10],
1 << phy_ctl_srstn_shift | 1 << ctl_psrstn_shift |
1 << ctl_srstn_shift | 1 << phy_psrstn_shift |
1 << phy_srstn_shift,
phy << phy_ctl_srstn_shift | ctl << ctl_psrstn_shift |
ctl << ctl_srstn_shift | phy << phy_psrstn_shift |
phy << phy_srstn_shift);
}
static void ddr_phy_ctl_reset(struct rk3288_cru *cru, u32 ch, u32 n)
{
u32 phy_ctl_srstn_shift = 4 + 5 * ch;
rk_clrsetreg(&cru->cru_softrst_con[10],
1 << phy_ctl_srstn_shift, n << phy_ctl_srstn_shift);
}
static void phy_pctrl_reset(struct rk3288_cru *cru,
struct rk3288_ddr_publ *publ,
u32 channel)
{
int i;
ddr_reset(cru, channel, 1, 1);
udelay(1);
clrbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST);
for (i = 0; i < 4; i++)
clrbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
udelay(10);
setbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST);
for (i = 0; i < 4; i++)
setbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
udelay(10);
ddr_reset(cru, channel, 1, 0);
udelay(10);
ddr_reset(cru, channel, 0, 0);
udelay(10);
}
static void phy_dll_bypass_set(struct rk3288_ddr_publ *publ,
u32 freq)
{
int i;
if (freq <= 250000000) {
if (freq <= 150000000)
clrbits_le32(&publ->dllgcr, SBIAS_BYPASS);
else
setbits_le32(&publ->dllgcr, SBIAS_BYPASS);
setbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS);
for (i = 0; i < 4; i++)
setbits_le32(&publ->datx8[i].dxdllcr,
DXDLLCR_DLLDIS);
setbits_le32(&publ->pir, PIR_DLLBYP);
} else {
clrbits_le32(&publ->dllgcr, SBIAS_BYPASS);
clrbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS);
for (i = 0; i < 4; i++) {
clrbits_le32(&publ->datx8[i].dxdllcr,
DXDLLCR_DLLDIS);
}
clrbits_le32(&publ->pir, PIR_DLLBYP);
}
}
static void dfi_cfg(struct rk3288_ddr_pctl *pctl, u32 dramtype)
{
writel(DFI_INIT_START, &pctl->dfistcfg0);
writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN,
&pctl->dfistcfg1);
writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2);
writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN,
&pctl->dfilpcfg0);
writel(2 << TCTRL_DELAY_TIME_SHIFT, &pctl->dfitctrldelay);
writel(1 << TPHY_WRDATA_TIME_SHIFT, &pctl->dfitphywrdata);
writel(0xf << TPHY_RDLAT_TIME_SHIFT, &pctl->dfitphyrdlat);
writel(2 << TDRAM_CLK_DIS_TIME_SHIFT, &pctl->dfitdramclkdis);
writel(2 << TDRAM_CLK_EN_TIME_SHIFT, &pctl->dfitdramclken);
writel(1, &pctl->dfitphyupdtype0);
/* cs0 and cs1 write odt enable */
writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
&pctl->dfiodtcfg);
/* odt write length */
writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1);
/* phyupd and ctrlupd disabled */
writel(0, &pctl->dfiupdcfg);
}
static void ddr_set_enable(struct rk3288_grf *grf, uint channel, bool enable)
{
uint val = 0;
if (enable) {
val = 1 << (channel ? DDR1_16BIT_EN_SHIFT :
DDR0_16BIT_EN_SHIFT);
}
rk_clrsetreg(&grf->soc_con0,
1 << (channel ? DDR1_16BIT_EN_SHIFT : DDR0_16BIT_EN_SHIFT),
val);
}
static void ddr_set_ddr3_mode(struct rk3288_grf *grf, uint channel,
bool ddr3_mode)
{
uint mask, val;
mask = 1 << (channel ? MSCH1_MAINDDR3_SHIFT : MSCH0_MAINDDR3_SHIFT);
val = ddr3_mode << (channel ? MSCH1_MAINDDR3_SHIFT :
MSCH0_MAINDDR3_SHIFT);
rk_clrsetreg(&grf->soc_con0, mask, val);
}
static void ddr_set_en_bst_odt(struct rk3288_grf *grf, uint channel,
bool enable, bool enable_bst, bool enable_odt)
{
uint mask;
bool disable_bst = !enable_bst;
mask = channel ?
(1 << LPDDR3_EN1_SHIFT | 1 << UPCTL1_BST_DIABLE_SHIFT |
1 << UPCTL1_LPDDR3_ODT_EN_SHIFT) :
(1 << LPDDR3_EN0_SHIFT | 1 << UPCTL0_BST_DIABLE_SHIFT |
1 << UPCTL0_LPDDR3_ODT_EN_SHIFT);
rk_clrsetreg(&grf->soc_con2, mask,
enable << (channel ? LPDDR3_EN1_SHIFT : LPDDR3_EN0_SHIFT) |
disable_bst << (channel ? UPCTL1_BST_DIABLE_SHIFT :
UPCTL0_BST_DIABLE_SHIFT) |
enable_odt << (channel ? UPCTL1_LPDDR3_ODT_EN_SHIFT :
UPCTL0_LPDDR3_ODT_EN_SHIFT));
}
static void pctl_cfg(u32 channel, struct rk3288_ddr_pctl *pctl,
const struct rk3288_sdram_params *sdram_params,
struct rk3288_grf *grf)
{
unsigned int burstlen;
burstlen = (sdram_params->base.noc_timing >> 18) & 0x7;
copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u,
sizeof(sdram_params->pctl_timing));
switch (sdram_params->base.dramtype) {
case LPDDR3:
writel(sdram_params->pctl_timing.tcl - 1,
&pctl->dfitrddataen);
writel(sdram_params->pctl_timing.tcwl,
&pctl->dfitphywrlat);
burstlen >>= 1;
writel(LPDDR2_S4 | 0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT |
LPDDR2_EN | burstlen << BURSTLENGTH_SHIFT |
(6 - 4) << TFAW_SHIFT | PD_EXIT_FAST |
1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT,
&pctl->mcfg);
ddr_set_ddr3_mode(grf, channel, false);
ddr_set_enable(grf, channel, true);
ddr_set_en_bst_odt(grf, channel, true, false,
sdram_params->base.odt);
break;
case DDR3:
if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE) {
writel(sdram_params->pctl_timing.tcl - 3,
&pctl->dfitrddataen);
} else {
writel(sdram_params->pctl_timing.tcl - 2,
&pctl->dfitrddataen);
}
writel(sdram_params->pctl_timing.tcwl - 1,
&pctl->dfitphywrlat);
writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN |
DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW |
1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT,
&pctl->mcfg);
ddr_set_ddr3_mode(grf, channel, true);
ddr_set_enable(grf, channel, true);
ddr_set_en_bst_odt(grf, channel, false, true, false);
break;
}
setbits_le32(&pctl->scfg, 1);
}
static void phy_cfg(const struct chan_info *chan, u32 channel,
const struct rk3288_sdram_params *sdram_params)
{
struct rk3288_ddr_publ *publ = chan->publ;
struct rk3288_msch *msch = chan->msch;
uint ddr_freq_mhz = sdram_params->base.ddr_freq / 1000000;
u32 dinit2, tmp;
int i;
dinit2 = DIV_ROUND_UP(ddr_freq_mhz * 200000, 1000);
/* DDR PHY Timing */
copy_to_reg(&publ->dtpr[0], &sdram_params->phy_timing.dtpr0,
sizeof(sdram_params->phy_timing));
writel(sdram_params->base.noc_timing, &msch->ddrtiming);
writel(0x3f, &msch->readlatency);
writel(sdram_params->base.noc_activate, &msch->activate);
writel(2 << BUSWRTORD_SHIFT | 2 << BUSRDTOWR_SHIFT |
1 << BUSRDTORD_SHIFT, &msch->devtodev);
writel(DIV_ROUND_UP(ddr_freq_mhz * 5120, 1000) << PRT_DLLLOCK_SHIFT |
DIV_ROUND_UP(ddr_freq_mhz * 50, 1000) << PRT_DLLSRST_SHIFT |
8 << PRT_ITMSRST_SHIFT, &publ->ptr[0]);
writel(DIV_ROUND_UP(ddr_freq_mhz * 500000, 1000) << PRT_DINIT0_SHIFT |
DIV_ROUND_UP(ddr_freq_mhz * 400, 1000) << PRT_DINIT1_SHIFT,
&publ->ptr[1]);
writel(min(dinit2, 0x1ffffU) << PRT_DINIT2_SHIFT |
DIV_ROUND_UP(ddr_freq_mhz * 1000, 1000) << PRT_DINIT3_SHIFT,
&publ->ptr[2]);
switch (sdram_params->base.dramtype) {
case LPDDR3:
clrsetbits_le32(&publ->pgcr, 0x1F,
0 << PGCR_DFTLMT_SHIFT |
0 << PGCR_DFTCMP_SHIFT |
1 << PGCR_DQSCFG_SHIFT |
0 << PGCR_ITMDMD_SHIFT);
/* DDRMODE select LPDDR3 */
clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT,
DDRMD_LPDDR2_LPDDR3 << DDRMD_SHIFT);
clrsetbits_le32(&publ->dxccr,
DQSNRES_MASK << DQSNRES_SHIFT |
DQSRES_MASK << DQSRES_SHIFT,
4 << DQSRES_SHIFT | 0xc << DQSNRES_SHIFT);
tmp = readl(&publ->dtpr[1]);
tmp = ((tmp >> TDQSCKMAX_SHIFT) & TDQSCKMAX_MASK) -
((tmp >> TDQSCK_SHIFT) & TDQSCK_MASK);
clrsetbits_le32(&publ->dsgcr,
DQSGE_MASK << DQSGE_SHIFT |
DQSGX_MASK << DQSGX_SHIFT,
tmp << DQSGE_SHIFT | tmp << DQSGX_SHIFT);
break;
case DDR3:
clrbits_le32(&publ->pgcr, 0x1f);
clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT,
DDRMD_DDR3 << DDRMD_SHIFT);
break;
}
if (sdram_params->base.odt) {
/*dynamic RTT enable */
for (i = 0; i < 4; i++)
setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT);
} else {
/*dynamic RTT disable */
for (i = 0; i < 4; i++)
clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT);
}
}
static void phy_init(struct rk3288_ddr_publ *publ)
{
setbits_le32(&publ->pir, PIR_INIT | PIR_DLLSRST
| PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR);
udelay(1);
while ((readl(&publ->pgsr) &
(PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) !=
(PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE))
;
}
static void send_command(struct rk3288_ddr_pctl *pctl, u32 rank,
u32 cmd, u32 arg)
{
writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
udelay(1);
while (readl(&pctl->mcmd) & START_CMD)
;
}
static inline void send_command_op(struct rk3288_ddr_pctl *pctl,
u32 rank, u32 cmd, u32 ma, u32 op)
{
send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT |
(op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT);
}
static void memory_init(struct rk3288_ddr_publ *publ,
u32 dramtype)
{
setbits_le32(&publ->pir,
(PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP
| PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC
| (dramtype == DDR3 ? PIR_DRAMRST : 0)));
udelay(1);
while ((readl(&publ->pgsr) & (PGSR_IDONE | PGSR_DLDONE))
!= (PGSR_IDONE | PGSR_DLDONE))
;
}
static void move_to_config_state(struct rk3288_ddr_publ *publ,
struct rk3288_ddr_pctl *pctl)
{
unsigned int state;
while (1) {
state = readl(&pctl->stat) & PCTL_STAT_MSK;
switch (state) {
case LOW_POWER:
writel(WAKEUP_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MSK)
!= ACCESS)
;
/* wait DLL lock */
while ((readl(&publ->pgsr) & PGSR_DLDONE)
!= PGSR_DLDONE)
;
/* if at low power state,need wakeup first,
* and then enter the config
* so here no break.
*/
case ACCESS:
/* no break */
case INIT_MEM:
writel(CFG_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG)
;
break;
case CONFIG:
return;
default:
break;
}
}
}
static void set_bandwidth_ratio(const struct chan_info *chan, u32 channel,
u32 n, struct rk3288_grf *grf)
{
struct rk3288_ddr_pctl *pctl = chan->pctl;
struct rk3288_ddr_publ *publ = chan->publ;
struct rk3288_msch *msch = chan->msch;
if (n == 1) {
setbits_le32(&pctl->ppcfg, 1);
rk_setreg(&grf->soc_con0, 1 << (8 + channel));
setbits_le32(&msch->ddrtiming, 1 << 31);
/* Data Byte disable*/
clrbits_le32(&publ->datx8[2].dxgcr, 1);
clrbits_le32(&publ->datx8[3].dxgcr, 1);
/* disable DLL */
setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS);
setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS);
} else {
clrbits_le32(&pctl->ppcfg, 1);
rk_clrreg(&grf->soc_con0, 1 << (8 + channel));
clrbits_le32(&msch->ddrtiming, 1 << 31);
/* Data Byte enable*/
setbits_le32(&publ->datx8[2].dxgcr, 1);
setbits_le32(&publ->datx8[3].dxgcr, 1);
/* enable DLL */
clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS);
clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS);
/* reset DLL */
clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST);
clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST);
udelay(10);
setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST);
setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST);
}
setbits_le32(&pctl->dfistcfg0, 1 << 2);
}
static int data_training(const struct chan_info *chan, u32 channel,
const struct rk3288_sdram_params *sdram_params)
{
unsigned int j;
int ret = 0;
u32 rank;
int i;
u32 step[2] = { PIR_QSTRN, PIR_RVTRN };
struct rk3288_ddr_publ *publ = chan->publ;
struct rk3288_ddr_pctl *pctl = chan->pctl;
/* disable auto refresh */
writel(0, &pctl->trefi);
if (sdram_params->base.dramtype != LPDDR3)
setbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT);
rank = sdram_params->ch[channel].rank | 1;
for (j = 0; j < ARRAY_SIZE(step); j++) {
/*
* trigger QSTRN and RVTRN
* clear DTDONE status
*/
setbits_le32(&publ->pir, PIR_CLRSR);
/* trigger DTT */
setbits_le32(&publ->pir,
PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP |
PIR_CLRSR);
udelay(1);
/* wait echo byte DTDONE */
while ((readl(&publ->datx8[0].dxgsr[0]) & rank)
!= rank)
;
while ((readl(&publ->datx8[1].dxgsr[0]) & rank)
!= rank)
;
if (!(readl(&pctl->ppcfg) & 1)) {
while ((readl(&publ->datx8[2].dxgsr[0])
& rank) != rank)
;
while ((readl(&publ->datx8[3].dxgsr[0])
& rank) != rank)
;
}
if (readl(&publ->pgsr) &
(PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) {
ret = -1;
break;
}
}
/* send some auto refresh to complement the lost while DTT */
for (i = 0; i < (rank > 1 ? 8 : 4); i++)
send_command(pctl, rank, REF_CMD, 0);
if (sdram_params->base.dramtype != LPDDR3)
clrbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT);
/* resume auto refresh */
writel(sdram_params->pctl_timing.trefi, &pctl->trefi);
return ret;
}
static void move_to_access_state(const struct chan_info *chan)
{
struct rk3288_ddr_publ *publ = chan->publ;
struct rk3288_ddr_pctl *pctl = chan->pctl;
unsigned int state;
while (1) {
state = readl(&pctl->stat) & PCTL_STAT_MSK;
switch (state) {
case LOW_POWER:
if (((readl(&pctl->stat) >> LP_TRIG_SHIFT) &
LP_TRIG_MASK) == 1)
return;
writel(WAKEUP_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MSK) != ACCESS)
;
/* wait DLL lock */
while ((readl(&publ->pgsr) & PGSR_DLDONE)
!= PGSR_DLDONE)
;
break;
case INIT_MEM:
writel(CFG_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG)
;
case CONFIG:
writel(GO_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MSK) == CONFIG)
;
break;
case ACCESS:
return;
default:
break;
}
}
}
static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum,
const struct rk3288_sdram_params *sdram_params)
{
struct rk3288_ddr_publ *publ = chan->publ;
if (sdram_params->ch[chnum].bk == 3)
clrsetbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT,
1 << PDQ_SHIFT);
else
clrbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT);
writel(sdram_params->base.ddrconfig, &chan->msch->ddrconf);
}
static void dram_all_config(const struct dram_info *dram,
const struct rk3288_sdram_params *sdram_params)
{
unsigned int chan;
u32 sys_reg = 0;
sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT;
sys_reg |= (sdram_params->num_channels - 1) << SYS_REG_NUM_CH_SHIFT;
for (chan = 0; chan < sdram_params->num_channels; chan++) {
const struct rk3288_sdram_channel *info =
&sdram_params->ch[chan];
sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(chan);
sys_reg |= chan << SYS_REG_CHINFO_SHIFT(chan);
sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(chan);
sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(chan);
sys_reg |= info->bk == 3 ? 1 << SYS_REG_BK_SHIFT(chan) : 0;
sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(chan);
sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(chan);
sys_reg |= info->bw << SYS_REG_BW_SHIFT(chan);
sys_reg |= info->dbw << SYS_REG_DBW_SHIFT(chan);
dram_cfg_rbc(&dram->chan[chan], chan, sdram_params);
}
writel(sys_reg, &dram->pmu->sys_reg[2]);
rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride);
}
static int sdram_init(struct dram_info *dram,
const struct rk3288_sdram_params *sdram_params)
{
int channel;
int zqcr;
int ret;
debug("%s start\n", __func__);
if ((sdram_params->base.dramtype == DDR3 &&
sdram_params->base.ddr_freq > 800000000) ||
(sdram_params->base.dramtype == LPDDR3 &&
sdram_params->base.ddr_freq > 533000000)) {
debug("SDRAM frequency is too high!");
return -E2BIG;
}
debug("ddr clk dpll\n");
ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq);
debug("ret=%d\n", ret);
if (ret) {
debug("Could not set DDR clock\n");
return ret;
}
for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct rk3288_ddr_pctl *pctl = chan->pctl;
struct rk3288_ddr_publ *publ = chan->publ;
phy_pctrl_reset(dram->cru, publ, channel);
phy_dll_bypass_set(publ, sdram_params->base.ddr_freq);
if (channel >= sdram_params->num_channels)
continue;
dfi_cfg(pctl, sdram_params->base.dramtype);
pctl_cfg(channel, pctl, sdram_params, dram->grf);
phy_cfg(chan, channel, sdram_params);
phy_init(publ);
writel(POWER_UP_START, &pctl->powctl);
while (!(readl(&pctl->powstat) & POWER_UP_DONE))
;
memory_init(publ, sdram_params->base.dramtype);
move_to_config_state(publ, pctl);
if (sdram_params->base.dramtype == LPDDR3) {
send_command(pctl, 3, DESELECT_CMD, 0);
udelay(1);
send_command(pctl, 3, PREA_CMD, 0);
udelay(1);
send_command_op(pctl, 3, MRS_CMD, 63, 0xfc);
udelay(1);
send_command_op(pctl, 3, MRS_CMD, 1,
sdram_params->phy_timing.mr[1]);
udelay(1);
send_command_op(pctl, 3, MRS_CMD, 2,
sdram_params->phy_timing.mr[2]);
udelay(1);
send_command_op(pctl, 3, MRS_CMD, 3,
sdram_params->phy_timing.mr[3]);
udelay(1);
}
set_bandwidth_ratio(chan, channel,
sdram_params->ch[channel].bw, dram->grf);
/*
* set cs
* CS0, n=1
* CS1, n=2
* CS0 & CS1, n = 3
*/
clrsetbits_le32(&publ->pgcr, 0xF << 18,
(sdram_params->ch[channel].rank | 1) << 18);
/* DS=40ohm,ODT=155ohm */
zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT |
2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT |
0x19 << PD_OUTPUT_SHIFT;
writel(zqcr, &publ->zq1cr[0]);
writel(zqcr, &publ->zq0cr[0]);
if (sdram_params->base.dramtype == LPDDR3) {
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
udelay(10);
send_command_op(pctl,
sdram_params->ch[channel].rank | 1,
MRS_CMD, 11,
sdram_params->base.odt ? 3 : 0);
if (channel == 0) {
writel(0, &pctl->mrrcfg0);
send_command_op(pctl, 1, MRR_CMD, 8, 0);
/* S8 */
if ((readl(&pctl->mrrstat0) & 0x3) != 3) {
debug("failed!");
return -EREMOTEIO;
}
}
}
if (-1 == data_training(chan, channel, sdram_params)) {
if (sdram_params->base.dramtype == LPDDR3) {
ddr_phy_ctl_reset(dram->cru, channel, 1);
udelay(10);
ddr_phy_ctl_reset(dram->cru, channel, 0);
udelay(10);
}
debug("failed!");
return -EIO;
}
if (sdram_params->base.dramtype == LPDDR3) {
u32 i;
writel(0, &pctl->mrrcfg0);
for (i = 0; i < 17; i++)
send_command_op(pctl, 1, MRR_CMD, i, 0);
}
move_to_access_state(chan);
}
dram_all_config(dram, sdram_params);
debug("%s done\n", __func__);
return 0;
}
#endif
size_t sdram_size_mb(struct rk3288_pmu *pmu)
{
u32 rank, col, bk, cs0_row, cs1_row, bw, row_3_4;
size_t chipsize_mb = 0;
size_t size_mb = 0;
u32 ch;
u32 sys_reg = readl(&pmu->sys_reg[2]);
u32 chans;
chans = 1 + ((sys_reg >> SYS_REG_NUM_CH_SHIFT) & SYS_REG_NUM_CH_MASK);
for (ch = 0; ch < chans; ch++) {
rank = 1 + (sys_reg >> SYS_REG_RANK_SHIFT(ch) &
SYS_REG_RANK_MASK);
col = 9 + (sys_reg >> SYS_REG_COL_SHIFT(ch) & SYS_REG_COL_MASK);
bk = sys_reg & (1 << SYS_REG_BK_SHIFT(ch)) ? 3 : 0;
cs0_row = 13 + (sys_reg >> SYS_REG_CS0_ROW_SHIFT(ch) &
SYS_REG_CS0_ROW_MASK);
cs1_row = 13 + (sys_reg >> SYS_REG_CS1_ROW_SHIFT(ch) &
SYS_REG_CS1_ROW_MASK);
bw = (sys_reg >> SYS_REG_BW_SHIFT(ch)) &
SYS_REG_BW_MASK;
row_3_4 = sys_reg >> SYS_REG_ROW_3_4_SHIFT(ch) &
SYS_REG_ROW_3_4_MASK;
chipsize_mb = (1 << (cs0_row + col + bk + bw - 20));
if (rank > 1)
chipsize_mb += chipsize_mb >>
(cs0_row - cs1_row);
if (row_3_4)
chipsize_mb = chipsize_mb * 3 / 4;
size_mb += chipsize_mb;
}
/*
* we use the 0x00000000~0xfeffffff space since 0xff000000~0xffffffff
* is SoC register space (i.e. reserved)
*/
size_mb = min(size_mb, 0xff000000 >> 20);
return size_mb;
}
#ifdef CONFIG_SPL_BUILD
# ifdef CONFIG_ROCKCHIP_FAST_SPL
static int veyron_init(struct dram_info *priv)
{
struct udevice *pmic;
int ret;
ret = uclass_first_device_err(UCLASS_PMIC, &pmic);
if (ret)
return ret;
/* Slowly raise to max CPU voltage to prevent overshoot */
ret = rk808_spl_configure_buck(pmic, 1, 1200000);
if (ret)
return ret;
udelay(175);/* Must wait for voltage to stabilize, 2mV/us */
ret = rk808_spl_configure_buck(pmic, 1, 1400000);
if (ret)
return ret;
udelay(100);/* Must wait for voltage to stabilize, 2mV/us */
rkclk_configure_cpu(priv->cru, priv->grf);
return 0;
}
# endif
static int setup_sdram(struct udevice *dev)
{
struct dram_info *priv = dev_get_priv(dev);
struct rk3288_sdram_params params;
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
int i, ret;
params.num_channels = fdtdec_get_int(blob, node,
"rockchip,num-channels", 1);
for (i = 0; i < params.num_channels; i++) {
ret = fdtdec_get_byte_array(blob, node,
"rockchip,sdram-channel",
(u8 *)&params.ch[i],
sizeof(params.ch[i]));
if (ret) {
debug("%s: Cannot read rockchip,sdram-channel\n",
__func__);
return -EINVAL;
}
}
ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing",
(u32 *)&params.pctl_timing,
sizeof(params.pctl_timing) / sizeof(u32));
if (ret) {
debug("%s: Cannot read rockchip,pctl-timing\n", __func__);
return -EINVAL;
}
ret = fdtdec_get_int_array(blob, node, "rockchip,phy-timing",
(u32 *)&params.phy_timing,
sizeof(params.phy_timing) / sizeof(u32));
if (ret) {
debug("%s: Cannot read rockchip,phy-timing\n", __func__);
return -EINVAL;
}
ret = fdtdec_get_int_array(blob, node, "rockchip,sdram-params",
(u32 *)&params.base,
sizeof(params.base) / sizeof(u32));
if (ret) {
debug("%s: Cannot read rockchip,sdram-params\n", __func__);
return -EINVAL;
}
# ifdef CONFIG_ROCKCHIP_FAST_SPL
if (!fdt_node_check_compatible(blob, 0, "google,veyron")) {
ret = veyron_init(priv);
if (ret)
return ret;
}
# endif
return sdram_init(priv, &params);
}
#endif
static int rk3288_dmc_probe(struct udevice *dev)
{
struct dram_info *priv = dev_get_priv(dev);
struct regmap *map;
int ret;
struct udevice *dev_clk;
map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC);
if (IS_ERR(map))
return PTR_ERR(map);
priv->chan[0].msch = regmap_get_range(map, 0);
priv->chan[1].msch = (struct rk3288_msch *)
(regmap_get_range(map, 0) + 0x80);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
priv->sgrf = syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
ret = regmap_init_mem(dev, &map);
if (ret)
return ret;
priv->chan[0].pctl = regmap_get_range(map, 0);
priv->chan[0].publ = regmap_get_range(map, 1);
priv->chan[1].pctl = regmap_get_range(map, 2);
priv->chan[1].publ = regmap_get_range(map, 3);
ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
if (ret)
return ret;
priv->ddr_clk.id = CLK_DDR;
ret = clk_request(dev_clk, &priv->ddr_clk);
if (ret)
return ret;
priv->cru = rockchip_get_cru();
if (IS_ERR(priv->cru))
return PTR_ERR(priv->cru);
#ifdef CONFIG_SPL_BUILD
ret = setup_sdram(dev);
if (ret)
return ret;
#endif
priv->info.base = 0;
priv->info.size = sdram_size_mb(priv->pmu) << 20;
return 0;
}
static int rk3288_dmc_get_info(struct udevice *dev, struct ram_info *info)
{
struct dram_info *priv = dev_get_priv(dev);
*info = priv->info;
return 0;
}
static struct ram_ops rk3288_dmc_ops = {
.get_info = rk3288_dmc_get_info,
};
static const struct udevice_id rk3288_dmc_ids[] = {
{ .compatible = "rockchip,rk3288-dmc" },
{ }
};
U_BOOT_DRIVER(dmc_rk3288) = {
.name = "rk3288_dmc",
.id = UCLASS_RAM,
.of_match = rk3288_dmc_ids,
.ops = &rk3288_dmc_ops,
.probe = rk3288_dmc_probe,
.priv_auto_alloc_size = sizeof(struct dram_info),
};

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <syscon.h>
#include <asm/arch/clock.h>
static const struct udevice_id rk3288_syscon_ids[] = {
{ .compatible = "rockchip,rk3288-noc", .data = ROCKCHIP_SYSCON_NOC },
{ .compatible = "rockchip,rk3288-grf", .data = ROCKCHIP_SYSCON_GRF },
{ .compatible = "rockchip,rk3288-sgrf", .data = ROCKCHIP_SYSCON_SGRF },
{ .compatible = "rockchip,rk3288-pmu", .data = ROCKCHIP_SYSCON_PMU },
{ }
};
U_BOOT_DRIVER(syscon_rk3288) = {
.name = "rk3288_syscon",
.id = UCLASS_SYSCON,
.of_match = rk3288_syscon_ids,
};

View File

@@ -0,0 +1,48 @@
/*
* (C) Copyright 2015 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/arch/timer.h>
#include <asm/io.h>
#include <common.h>
#include <linux/types.h>
struct rk_timer * const timer_ptr = (void *)CONFIG_SYS_TIMER_BASE;
static uint64_t rockchip_get_ticks(void)
{
uint64_t timebase_h, timebase_l;
timebase_l = readl(&timer_ptr->timer_curr_value0);
timebase_h = readl(&timer_ptr->timer_curr_value1);
return timebase_h << 32 | timebase_l;
}
static uint64_t usec_to_tick(unsigned int usec)
{
uint64_t tick = usec;
tick *= CONFIG_SYS_TIMER_RATE / (1000 * 1000);
return tick;
}
void rockchip_udelay(unsigned int usec)
{
uint64_t tmp;
/* get timestamp */
tmp = rockchip_get_ticks() + usec_to_tick(usec);
/* loop till event */
while (rockchip_get_ticks() < tmp+1)
;
}
void rockchip_timer_init(void)
{
writel(0xffffffff, &timer_ptr->timer_load_count0);
writel(0xffffffff, &timer_ptr->timer_load_count1);
writel(1, &timer_ptr->timer_ctrl_reg);
}