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:
49
u-boot/arch/arm/mach-rockchip/Kconfig
Normal file
49
u-boot/arch/arm/mach-rockchip/Kconfig
Normal 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
|
||||
15
u-boot/arch/arm/mach-rockchip/Makefile
Normal file
15
u-boot/arch/arm/mach-rockchip/Makefile
Normal 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/
|
||||
104
u-boot/arch/arm/mach-rockchip/board.c
Normal file
104
u-boot/arch/arm/mach-rockchip/board.c
Normal 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",
|
||||
""
|
||||
);
|
||||
62
u-boot/arch/arm/mach-rockchip/rk3036-board-spl.c
Normal file
62
u-boot/arch/arm/mach-rockchip/rk3036-board-spl.c
Normal 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)
|
||||
;
|
||||
}
|
||||
21
u-boot/arch/arm/mach-rockchip/rk3036/Kconfig
Normal file
21
u-boot/arch/arm/mach-rockchip/rk3036/Kconfig
Normal 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
|
||||
13
u-boot/arch/arm/mach-rockchip/rk3036/Makefile
Normal file
13
u-boot/arch/arm/mach-rockchip/rk3036/Makefile
Normal 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
|
||||
45
u-boot/arch/arm/mach-rockchip/rk3036/reset_rk3036.c
Normal file
45
u-boot/arch/arm/mach-rockchip/rk3036/reset_rk3036.c
Normal 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,
|
||||
};
|
||||
32
u-boot/arch/arm/mach-rockchip/rk3036/save_boot_param.S
Normal file
32
u-boot/arch/arm/mach-rockchip/rk3036/save_boot_param.S
Normal 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)
|
||||
768
u-boot/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
Normal file
768
u-boot/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
Normal 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);
|
||||
}
|
||||
21
u-boot/arch/arm/mach-rockchip/rk3036/syscon_rk3036.c
Normal file
21
u-boot/arch/arm/mach-rockchip/rk3036/syscon_rk3036.c
Normal 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,
|
||||
};
|
||||
280
u-boot/arch/arm/mach-rockchip/rk3288-board-spl.c
Normal file
280
u-boot/arch/arm/mach-rockchip/rk3288-board-spl.c
Normal 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)
|
||||
{
|
||||
}
|
||||
48
u-boot/arch/arm/mach-rockchip/rk3288/Kconfig
Normal file
48
u-boot/arch/arm/mach-rockchip/rk3288/Kconfig
Normal 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
|
||||
9
u-boot/arch/arm/mach-rockchip/rk3288/Makefile
Normal file
9
u-boot/arch/arm/mach-rockchip/rk3288/Makefile
Normal 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
|
||||
47
u-boot/arch/arm/mach-rockchip/rk3288/reset_rk3288.c
Normal file
47
u-boot/arch/arm/mach-rockchip/rk3288/reset_rk3288.c
Normal 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,
|
||||
};
|
||||
907
u-boot/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
Normal file
907
u-boot/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
Normal 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 *)¶ms.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 *)¶ms.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 *)¶ms.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 *)¶ms.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, ¶ms);
|
||||
}
|
||||
#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),
|
||||
};
|
||||
25
u-boot/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c
Normal file
25
u-boot/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c
Normal 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,
|
||||
};
|
||||
48
u-boot/arch/arm/mach-rockchip/rk_timer.c
Normal file
48
u-boot/arch/arm/mach-rockchip/rk_timer.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user