From: Kever Yang <kever.y...@rock-chips.com> Add core architecture code to support the px30 soc. This includes a separate tpl board file due to very limited sram size as well as a non-dm sdram driver, as this also has to fit into the tiny sram.
Signed-off-by: Kever Yang <kever.y...@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko.stueb...@theobroma-systems.com> --- arch/arm/include/asm/arch-px30/boot0.h | 11 + arch/arm/include/asm/arch-px30/gpio.h | 11 + .../include/asm/arch-rockchip/sdram_px30.h | 359 +++++ arch/arm/mach-rockchip/Kconfig | 23 + arch/arm/mach-rockchip/Makefile | 2 + arch/arm/mach-rockchip/px30-board-tpl.c | 59 + arch/arm/mach-rockchip/px30/Kconfig | 48 + arch/arm/mach-rockchip/px30/Makefile | 14 + arch/arm/mach-rockchip/px30/clk_px30.c | 31 + arch/arm/mach-rockchip/px30/px30.c | 248 +++ .../px30/sdram-px30-ddr3-detect-333.inc | 70 + .../px30/sdram-px30-ddr4-detect-333.inc | 73 + .../px30/sdram-px30-ddr_skew.inc | 121 ++ .../px30/sdram-px30-lpddr2-detect-333.inc | 71 + .../px30/sdram-px30-lpddr3-detect-333.inc | 72 + arch/arm/mach-rockchip/px30/sdram_px30.c | 1405 +++++++++++++++++ arch/arm/mach-rockchip/px30/syscon_px30.c | 53 + 17 files changed, 2671 insertions(+) create mode 100644 arch/arm/include/asm/arch-px30/boot0.h create mode 100644 arch/arm/include/asm/arch-px30/gpio.h create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_px30.h create mode 100644 arch/arm/mach-rockchip/px30-board-tpl.c create mode 100644 arch/arm/mach-rockchip/px30/Kconfig create mode 100644 arch/arm/mach-rockchip/px30/Makefile create mode 100644 arch/arm/mach-rockchip/px30/clk_px30.c create mode 100644 arch/arm/mach-rockchip/px30/px30.c create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc create mode 100644 arch/arm/mach-rockchip/px30/sdram_px30.c create mode 100644 arch/arm/mach-rockchip/px30/syscon_px30.c diff --git a/arch/arm/include/asm/arch-px30/boot0.h b/arch/arm/include/asm/arch-px30/boot0.h new file mode 100644 index 0000000000..2e78b074ad --- /dev/null +++ b/arch/arm/include/asm/arch-px30/boot0.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + */ + +#ifndef __ASM_ARCH_BOOT0_H__ +#define __ASM_ARCH_BOOT0_H__ + +#include <asm/arch-rockchip/boot0.h> + +#endif diff --git a/arch/arm/include/asm/arch-px30/gpio.h b/arch/arm/include/asm/arch-px30/gpio.h new file mode 100644 index 0000000000..eca79d5159 --- /dev/null +++ b/arch/arm/include/asm/arch-px30/gpio.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + */ + +#ifndef __ASM_ARCH_GPIO_H__ +#define __ASM_ARCH_GPIO_H__ + +#include <asm/arch-rockchip/gpio.h> + +#endif diff --git a/arch/arm/include/asm/arch-rockchip/sdram_px30.h b/arch/arm/include/asm/arch-rockchip/sdram_px30.h new file mode 100644 index 0000000000..e10eb97b89 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/sdram_px30.h @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Rockchip Electronics Co., Ltd + */ + +#ifndef _ASM_ARCH_SDRAM_PX30_H +#define _ASM_ARCH_SDRAM_PX30_H + +struct ddr_pctl_regs { + u32 pctl[30][2]; +}; + +/* ddr pctl registers define */ +#define DDR_PCTL2_MSTR 0x0 +#define DDR_PCTL2_STAT 0x4 +#define DDR_PCTL2_MSTR1 0x8 +#define DDR_PCTL2_MRCTRL0 0x10 +#define DDR_PCTL2_MRCTRL1 0x14 +#define DDR_PCTL2_MRSTAT 0x18 +#define DDR_PCTL2_MRCTRL2 0x1c +#define DDR_PCTL2_DERATEEN 0x20 +#define DDR_PCTL2_DERATEINT 0x24 +#define DDR_PCTL2_PWRCTL 0x30 +#define DDR_PCTL2_PWRTMG 0x34 +#define DDR_PCTL2_HWLPCTL 0x38 +#define DDR_PCTL2_RFSHCTL0 0x50 +#define DDR_PCTL2_RFSHCTL1 0x54 +#define DDR_PCTL2_RFSHCTL2 0x58 +#define DDR_PCTL2_RFSHCTL4 0x5c +#define DDR_PCTL2_RFSHCTL3 0x60 +#define DDR_PCTL2_RFSHTMG 0x64 +#define DDR_PCTL2_RFSHTMG1 0x68 +#define DDR_PCTL2_RFSHCTL5 0x6c +#define DDR_PCTL2_INIT0 0xd0 +#define DDR_PCTL2_INIT1 0xd4 +#define DDR_PCTL2_INIT2 0xd8 +#define DDR_PCTL2_INIT3 0xdc +#define DDR_PCTL2_INIT4 0xe0 +#define DDR_PCTL2_INIT5 0xe4 +#define DDR_PCTL2_INIT6 0xe8 +#define DDR_PCTL2_INIT7 0xec +#define DDR_PCTL2_DIMMCTL 0xf0 +#define DDR_PCTL2_RANKCTL 0xf4 +#define DDR_PCTL2_CHCTL 0xfc +#define DDR_PCTL2_DRAMTMG0 0x100 +#define DDR_PCTL2_DRAMTMG1 0x104 +#define DDR_PCTL2_DRAMTMG2 0x108 +#define DDR_PCTL2_DRAMTMG3 0x10c +#define DDR_PCTL2_DRAMTMG4 0x110 +#define DDR_PCTL2_DRAMTMG5 0x114 +#define DDR_PCTL2_DRAMTMG6 0x118 +#define DDR_PCTL2_DRAMTMG7 0x11c +#define DDR_PCTL2_DRAMTMG8 0x120 +#define DDR_PCTL2_DRAMTMG9 0x124 +#define DDR_PCTL2_DRAMTMG10 0x128 +#define DDR_PCTL2_DRAMTMG11 0x12c +#define DDR_PCTL2_DRAMTMG12 0x130 +#define DDR_PCTL2_DRAMTMG13 0x134 +#define DDR_PCTL2_DRAMTMG14 0x138 +#define DDR_PCTL2_DRAMTMG15 0x13c +#define DDR_PCTL2_DRAMTMG16 0x140 +#define DDR_PCTL2_ZQCTL0 0x180 +#define DDR_PCTL2_ZQCTL1 0x184 +#define DDR_PCTL2_ZQCTL2 0x188 +#define DDR_PCTL2_ZQSTAT 0x18c +#define DDR_PCTL2_DFITMG0 0x190 +#define DDR_PCTL2_DFITMG1 0x194 +#define DDR_PCTL2_DFILPCFG0 0x198 +#define DDR_PCTL2_DFILPCFG1 0x19c +#define DDR_PCTL2_DFIUPD0 0x1a0 +#define DDR_PCTL2_DFIUPD1 0x1a4 +#define DDR_PCTL2_DFIUPD2 0x1a8 +#define DDR_PCTL2_DFIMISC 0x1b0 +#define DDR_PCTL2_DFITMG2 0x1b4 +#define DDR_PCTL2_DFITMG3 0x1b8 +#define DDR_PCTL2_DFISTAT 0x1bc +#define DDR_PCTL2_DBICTL 0x1c0 +#define DDR_PCTL2_ADDRMAP0 0x200 +#define DDR_PCTL2_ADDRMAP1 0x204 +#define DDR_PCTL2_ADDRMAP2 0x208 +#define DDR_PCTL2_ADDRMAP3 0x20c +#define DDR_PCTL2_ADDRMAP4 0x210 +#define DDR_PCTL2_ADDRMAP5 0x214 +#define DDR_PCTL2_ADDRMAP6 0x218 +#define DDR_PCTL2_ADDRMAP7 0x21c +#define DDR_PCTL2_ADDRMAP8 0x220 +#define DDR_PCTL2_ADDRMAP9 0x224 +#define DDR_PCTL2_ADDRMAP10 0x228 +#define DDR_PCTL2_ADDRMAP11 0x22c +#define DDR_PCTL2_ODTCFG 0x240 +#define DDR_PCTL2_ODTMAP 0x244 +#define DDR_PCTL2_SCHED 0x250 +#define DDR_PCTL2_SCHED1 0x254 +#define DDR_PCTL2_PERFHPR1 0x25c +#define DDR_PCTL2_PERFLPR1 0x264 +#define DDR_PCTL2_PERFWR1 0x26c +#define DDR_PCTL2_DQMAP0 0x280 +#define DDR_PCTL2_DQMAP1 0x284 +#define DDR_PCTL2_DQMAP2 0x288 +#define DDR_PCTL2_DQMAP3 0x28c +#define DDR_PCTL2_DQMAP4 0x290 +#define DDR_PCTL2_DQMAP5 0x294 +#define DDR_PCTL2_DBG0 0x300 +#define DDR_PCTL2_DBG1 0x304 +#define DDR_PCTL2_DBGCAM 0x308 +#define DDR_PCTL2_DBGCMD 0x30c +#define DDR_PCTL2_DBGSTAT 0x310 +#define DDR_PCTL2_SWCTL 0x320 +#define DDR_PCTL2_SWSTAT 0x324 +#define DDR_PCTL2_POISONCFG 0x36c +#define DDR_PCTL2_POISONSTAT 0x370 +#define DDR_PCTL2_ADVECCINDEX 0x374 +#define DDR_PCTL2_ADVECCSTAT 0x378 +#define DDR_PCTL2_PSTAT 0x3fc +#define DDR_PCTL2_PCCFG 0x400 +#define DDR_PCTL2_PCFGR_n 0x404 +#define DDR_PCTL2_PCFGW_n 0x408 +#define DDR_PCTL2_PCTRL_n 0x490 + +/* PCTL2_MRSTAT */ +#define MR_WR_BUSY BIT(0) + +#define PHY_DDR3_RON_RTT_DISABLE (0) +#define PHY_DDR3_RON_RTT_451ohm (1) +#define PHY_DDR3_RON_RTT_225ohm (2) +#define PHY_DDR3_RON_RTT_150ohm (3) +#define PHY_DDR3_RON_RTT_112ohm (4) +#define PHY_DDR3_RON_RTT_90ohm (5) +#define PHY_DDR3_RON_RTT_75ohm (6) +#define PHY_DDR3_RON_RTT_64ohm (7) +#define PHY_DDR3_RON_RTT_56ohm (16) +#define PHY_DDR3_RON_RTT_50ohm (17) +#define PHY_DDR3_RON_RTT_45ohm (18) +#define PHY_DDR3_RON_RTT_41ohm (19) +#define PHY_DDR3_RON_RTT_37ohm (20) +#define PHY_DDR3_RON_RTT_34ohm (21) +#define PHY_DDR3_RON_RTT_33ohm (22) +#define PHY_DDR3_RON_RTT_30ohm (23) +#define PHY_DDR3_RON_RTT_28ohm (24) +#define PHY_DDR3_RON_RTT_26ohm (25) +#define PHY_DDR3_RON_RTT_25ohm (26) +#define PHY_DDR3_RON_RTT_23ohm (27) +#define PHY_DDR3_RON_RTT_22ohm (28) +#define PHY_DDR3_RON_RTT_21ohm (29) +#define PHY_DDR3_RON_RTT_20ohm (30) +#define PHY_DDR3_RON_RTT_19ohm (31) + +#define PHY_DDR4_LPDDR3_RON_RTT_DISABLE (0) +#define PHY_DDR4_LPDDR3_RON_RTT_480ohm (1) +#define PHY_DDR4_LPDDR3_RON_RTT_240ohm (2) +#define PHY_DDR4_LPDDR3_RON_RTT_160ohm (3) +#define PHY_DDR4_LPDDR3_RON_RTT_120ohm (4) +#define PHY_DDR4_LPDDR3_RON_RTT_96ohm (5) +#define PHY_DDR4_LPDDR3_RON_RTT_80ohm (6) +#define PHY_DDR4_LPDDR3_RON_RTT_68ohm (7) +#define PHY_DDR4_LPDDR3_RON_RTT_60ohm (16) +#define PHY_DDR4_LPDDR3_RON_RTT_53ohm (17) +#define PHY_DDR4_LPDDR3_RON_RTT_48ohm (18) +#define PHY_DDR4_LPDDR3_RON_RTT_43ohm (19) +#define PHY_DDR4_LPDDR3_RON_RTT_40ohm (20) +#define PHY_DDR4_LPDDR3_RON_RTT_37ohm (21) +#define PHY_DDR4_LPDDR3_RON_RTT_34ohm (22) +#define PHY_DDR4_LPDDR3_RON_RTT_32ohm (23) +#define PHY_DDR4_LPDDR3_RON_RTT_30ohm (24) +#define PHY_DDR4_LPDDR3_RON_RTT_28ohm (25) +#define PHY_DDR4_LPDDR3_RON_RTT_26ohm (26) +#define PHY_DDR4_LPDDR3_RON_RTT_25ohm (27) +#define PHY_DDR4_LPDDR3_RON_RTT_24ohm (28) +#define PHY_DDR4_LPDDR3_RON_RTT_22ohm (29) +#define PHY_DDR4_LPDDR3_RON_RTT_21ohm (30) +#define PHY_DDR4_LPDDR3_RON_RTT_20ohm (31) + +struct ddr_phy_regs { + u32 phy[5][2]; +}; + +#define PHY_REG(base, n) ((base) + 4 * (n)) + +/* PHY_REG0 */ +#define DIGITAL_DERESET BIT(3) +#define ANALOG_DERESET BIT(2) +#define DIGITAL_RESET (0 << 3) +#define ANALOG_RESET (0 << 2) + +/* PHY_REG1 */ +#define PHY_DDR2 (0) +#define PHY_LPDDR2 (1) +#define PHY_DDR3 (2) +#define PHY_LPDDR3 (3) +#define PHY_DDR4 (4) +#define PHY_BL_4 (0 << 2) +#define PHY_BL_8 BIT(2) + +/* PHY_REG2 */ +#define PHY_DTT_EN BIT(0) +#define PHY_DTT_DISB (0 << 0) +#define PHY_WRITE_LEVELING_EN BIT(2) +#define PHY_WRITE_LEVELING_DISB (0 << 2) +#define PHY_SELECT_CS0 (2) +#define PHY_SELECT_CS1 (1) +#define PHY_SELECT_CS0_1 (0) +#define PHY_WRITE_LEVELING_SELECTCS(n) ((n) << 6) +#define PHY_DATA_TRAINING_SELECTCS(n) ((n) << 4) + +struct ddr_phy_skew { + u32 a0_a1_skew[15]; + u32 cs0_dm0_skew[11]; + u32 cs0_dm1_skew[11]; + u32 cs0_dm2_skew[11]; + u32 cs0_dm3_skew[11]; + u32 cs1_dm0_skew[11]; + u32 cs1_dm1_skew[11]; + u32 cs1_dm2_skew[11]; + u32 cs1_dm3_skew[11]; +}; + +#define SR_IDLE 93 +#define PD_IDLE 13 + +/* PMUGRF */ +#define PMUGRF_OS_REG0 (0x200) +#define PMUGRF_OS_REG(n) (PMUGRF_OS_REG0 + (n) * 4) + +/* DDR GRF */ +#define DDR_GRF_CON(n) (0 + (n) * 4) +#define DDR_GRF_STATUS_BASE (0X100) +#define DDR_GRF_STATUS(n) (DDR_GRF_STATUS_BASE + (n) * 4) +#define DDR_GRF_LP_CON (0x20) + +#define SPLIT_MODE_32_L16_VALID (0) +#define SPLIT_MODE_32_H16_VALID (1) +#define SPLIT_MODE_16_L8_VALID (2) +#define SPLIT_MODE_16_H8_VALID (3) + +#define DDR_GRF_SPLIT_CON (0x8) +#define SPLIT_MODE_MASK (0x3) +#define SPLIT_MODE_OFFSET (9) +#define SPLIT_BYPASS_MASK (1) +#define SPLIT_BYPASS_OFFSET (8) +#define SPLIT_SIZE_MASK (0xff) +#define SPLIT_SIZE_OFFSET (0) + +/* CRU define */ +/* CRU_PLL_CON0 */ +#define PB(n) ((0x1 << (15 + 16)) | ((n) << 15)) +#define POSTDIV1(n) ((0x7 << (12 + 16)) | ((n) << 12)) +#define FBDIV(n) ((0xFFF << 16) | (n)) + +/* CRU_PLL_CON1 */ +#define RSTMODE(n) ((0x1 << (15 + 16)) | ((n) << 15)) +#define RST(n) ((0x1 << (14 + 16)) | ((n) << 14)) +#define PD(n) ((0x1 << (13 + 16)) | ((n) << 13)) +#define DSMPD(n) ((0x1 << (12 + 16)) | ((n) << 12)) +#define LOCK(n) (((n) >> 10) & 0x1) +#define POSTDIV2(n) ((0x7 << (6 + 16)) | ((n) << 6)) +#define REFDIV(n) ((0x3F << 16) | (n)) + +/* CRU_MODE */ +#define CLOCK_FROM_XIN_OSC (0) +#define CLOCK_FROM_PLL (1) +#define CLOCK_FROM_RTC_32K (2) +#define DPLL_MODE(n) ((0x3 << (4 + 16)) | ((n) << 4)) + +/* CRU_SOFTRESET_CON1 */ +#define upctl2_psrstn_req(n) (((0x1 << 6) << 16) | ((n) << 6)) +#define upctl2_asrstn_req(n) (((0x1 << 5) << 16) | ((n) << 5)) +#define upctl2_srstn_req(n) (((0x1 << 4) << 16) | ((n) << 4)) + +/* CRU_SOFTRESET_CON2 */ +#define ddrphy_psrstn_req(n) (((0x1 << 2) << 16) | ((n) << 2)) +#define ddrphy_srstn_req(n) (((0x1 << 0) << 16) | ((n) << 0)) + +/* CRU register */ +#define CRU_PLL_CON(pll_id, n) ((pll_id) * 0x20 + (n) * 4) +#define CRU_MODE (0xa0) +#define CRU_GLB_CNT_TH (0xb0) +#define CRU_CLKSEL_CON_BASE 0x100 +#define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON_BASE + ((i) * 4)) +#define CRU_CLKGATE_CON_BASE 0x200 +#define CRU_CLKGATE_CON(i) (CRU_CLKGATE_CON_BASE + ((i) * 4)) +#define CRU_CLKSFTRST_CON_BASE 0x300 +#define CRU_CLKSFTRST_CON(i) (CRU_CLKSFTRST_CON_BASE + ((i) * 4)) + +struct px30_ddr_grf_regs { + u32 ddr_grf_con[4]; + u32 reserved1[(0x20 - 0x10) / 4]; + u32 ddr_grf_lp_con; + u32 reserved2[(0x100 - 0x24) / 4]; + u32 ddr_grf_status[11]; +}; + +struct px30_msch_timings { + u32 ddrtiminga0; + u32 ddrtimingb0; + u32 ddrtimingc0; + u32 devtodev0; + u32 ddrmode; + u32 ddr4timing; + u32 agingx0; +}; + +struct px30_sdram_channel { + unsigned int rank; + unsigned int col; + /* 3:8bank, 2:4bank */ + unsigned int bk; + /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */ + unsigned int bw; + /* die buswidth, 2:32bit, 1:16bit, 0:8bit */ + unsigned int dbw; + unsigned int row_3_4; + unsigned int cs0_row; + unsigned int cs1_row; + unsigned int cs0_high16bit_row; + unsigned int cs1_high16bit_row; + unsigned int ddrconfig; + struct px30_msch_timings noc_timings; +}; + +struct px30_base_params { + unsigned int ddr_freq; + unsigned int dramtype; + unsigned int num_channels; + unsigned int stride; + unsigned int odt; +}; + +struct px30_sdram_params { + struct px30_sdram_channel ch; + struct px30_base_params base; + struct ddr_pctl_regs pctl_regs; + struct ddr_phy_regs phy_regs; + struct ddr_phy_skew *skew; +}; + +struct px30_msch_regs { + u32 coreid; + u32 revisionid; + u32 deviceconf; + u32 devicesize; + u32 ddrtiminga0; + u32 ddrtimingb0; + u32 ddrtimingc0; + u32 devtodev0; + u32 reserved1[(0x110 - 0x20) / 4]; + u32 ddrmode; + u32 ddr4timing; + u32 reserved2[(0x1000 - 0x118) / 4]; + u32 agingx0; + u32 reserved3[(0x1040 - 0x1004) / 4]; + u32 aging0; + u32 aging1; + u32 aging2; + u32 aging3; +}; + +int sdram_init(void); + +#endif diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index f5a80b4f0c..116b40a3c5 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -1,5 +1,27 @@ if ARCH_ROCKCHIP +config ROCKCHIP_PX30 + bool "Support Rockchip PX30" + select ARM64 + select SUPPORT_SPL + select SUPPORT_TPL + select SPL + select TPL + select TPL_TINY_FRAMEWORK if TPL + select TPL_NEEDS_SEPARATE_TEXT_BASE if SPL + select TPL_NEEDS_SEPARATE_STACK if TPL + imply SPL_SEPARATE_BSS + select SPL_SERIAL_SUPPORT + select TPL_SERIAL_SUPPORT + select DEBUG_UART_BOARD_INIT + imply ROCKCHIP_COMMON_BOARD + imply SPL_ROCKCHIP_COMMON_BOARD + help + The Rockchip PX30 is a ARM-based SoC with a quad-core Cortex-A35 + 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 ROCKCHIP_RK3036 bool "Support Rockchip RK3036" select CPU_V7A @@ -315,6 +337,7 @@ config TPL_ROCKCHIP_EARLYRETURN_TO_BROM config SPL_MMC_SUPPORT default y if !SPL_ROCKCHIP_BACK_TO_BROM +source "arch/arm/mach-rockchip/px30/Kconfig" source "arch/arm/mach-rockchip/rk3036/Kconfig" source "arch/arm/mach-rockchip/rk3128/Kconfig" source "arch/arm/mach-rockchip/rk3188/Kconfig" diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index 45d9b06233..ddff566dee 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -11,6 +11,7 @@ obj-spl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o obj-spl-$(CONFIG_SPL_ROCKCHIP_COMMON_BOARD) += spl.o spl-boot-order.o obj-tpl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o obj-tpl-$(CONFIG_TPL_ROCKCHIP_COMMON_BOARD) += tpl.o +obj-tpl-$(CONFIG_ROCKCHIP_PX30) += px30-board-tpl.o obj-spl-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o @@ -27,6 +28,7 @@ endif obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram_common.o +obj-$(CONFIG_ROCKCHIP_PX30) += px30/ obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/ obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/ obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188/ diff --git a/arch/arm/mach-rockchip/px30-board-tpl.c b/arch/arm/mach-rockchip/px30-board-tpl.c new file mode 100644 index 0000000000..8c8976f61c --- /dev/null +++ b/arch/arm/mach-rockchip/px30-board-tpl.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + */ + +#include <common.h> +#include <debug_uart.h> +#include <dm.h> +#include <ram.h> +#include <spl.h> +#include <version.h> +#include <asm/io.h> +#include <asm/arch-rockchip/bootrom.h> +#include <asm/arch-rockchip/sdram_px30.h> + +#define TIMER_LOAD_COUNT0 0x00 +#define TIMER_LOAD_COUNT1 0x04 +#define TIMER_CUR_VALUE0 0x08 +#define TIMER_CUR_VALUE1 0x0c +#define TIMER_CONTROL_REG 0x10 + +#define TIMER_EN 0x1 +#define TIMER_FMODE (0 << 1) +#define TIMER_RMODE (1 << 1) + +void secure_timer_init(void) +{ + writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG); + writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT0); + writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT1); + writel(TIMER_EN | TIMER_FMODE, + CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG); +} + +void board_init_f(ulong dummy) +{ + int ret; + +#ifdef CONFIG_DEBUG_UART + debug_uart_init(); + /* + * Debug UART can be used from here if required: + * + * debug_uart_init(); + * printch('a'); + * printhex8(0x1234); + * printascii("string"); + */ + printascii("U-Boot TPL board init\n"); +#endif + + secure_timer_init(); + ret = sdram_init(); + if (ret) + printascii("sdram_init failed\n"); + + /* return to maskrom */ + back_to_bootrom(BROM_BOOT_NEXTSTAGE); +} diff --git a/arch/arm/mach-rockchip/px30/Kconfig b/arch/arm/mach-rockchip/px30/Kconfig new file mode 100644 index 0000000000..ef04afca8d --- /dev/null +++ b/arch/arm/mach-rockchip/px30/Kconfig @@ -0,0 +1,48 @@ +if ROCKCHIP_PX30 + +config TARGET_EVB_PX30 + bool "EVB_PX30" + +config ROCKCHIP_BOOT_MODE_REG + default 0xff010200 + +config SYS_SOC + default "px30" + +config SYS_MALLOC_F_LEN + default 0x400 + +config SPL_SERIAL_SUPPORT + default y + +config TPL_LDSCRIPT + default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds" + +config TPL_TEXT_BASE + default 0xff0e1000 + +config TPL_MAX_SIZE + default 10240 + +config TPL_STACK + default 0xff0e4fff + +config ROCKCHIP_RK3326 + bool "Support Rockchip RK3326 " + help + RK3326 can use most code from PX30, but at some situations we have + to distinguish between RK3326 and PX30, so this macro gives help. + It is usually selected in rk3326 board defconfig. + +config DEBUG_UART2_CHANNEL + int "Mux channel to use for debug UART2" + depends on DEBUG_UART_BOARD_INIT + default 0 + help + UART2 can use two different set of pins to route the output. + For using the UART for early debugging the route to use needs + to be declared (0 or 1). + +source "board/rockchip/evb_px30/Kconfig" + +endif diff --git a/arch/arm/mach-rockchip/px30/Makefile b/arch/arm/mach-rockchip/px30/Makefile new file mode 100644 index 0000000000..6d0742bcab --- /dev/null +++ b/arch/arm/mach-rockchip/px30/Makefile @@ -0,0 +1,14 @@ +# +# (C) Copyright 2017 Rockchip Electronics Co., Ltd. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clk_px30.o + +ifndef CONFIG_TPL_BUILD +obj-y += syscon_px30.o +endif + +obj-y += px30.o +obj-y += sdram_px30.o diff --git a/arch/arm/mach-rockchip/px30/clk_px30.c b/arch/arm/mach-rockchip/px30/clk_px30.c new file mode 100644 index 0000000000..0bd6b471da --- /dev/null +++ b/arch/arm/mach-rockchip/px30/clk_px30.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd. + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_px30.h> + +int rockchip_get_clk(struct udevice **devp) +{ + return uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(rockchip_px30_cru), devp); +} + +void *rockchip_get_cru(void) +{ + struct px30_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} diff --git a/arch/arm/mach-rockchip/px30/px30.c b/arch/arm/mach-rockchip/px30/px30.c new file mode 100644 index 0000000000..7cd2292fe2 --- /dev/null +++ b/arch/arm/mach-rockchip/px30/px30.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Rockchip Electronics Co., Ltd + */ +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <asm/armv8/mmu.h> +#include <asm/io.h> +#include <asm/arch-rockchip/grf_px30.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/uart.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_px30.h> +#include <dt-bindings/clock/px30-cru.h> + +static struct mm_region px30_mem_map[] = { + { + .virt = 0x0UL, + .phys = 0x0UL, + .size = 0xff000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + .virt = 0xff000000UL, + .phys = 0xff000000UL, + .size = 0x01000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* List terminator */ + 0, + } +}; + +struct mm_region *mem_map = px30_mem_map; + +#define PMU_PWRDN_CON 0xff000018 +#define GRF_BASE 0xff140000 +#define CRU_BASE 0xff2b0000 +#define VIDEO_PHY_BASE 0xff2e0000 +#define SERVICE_CORE_ADDR 0xff508000 +#define DDR_FW_BASE 0xff534000 + +#define FW_DDR_CON 0x40 + +#define QOS_PRIORITY 0x08 + +#define QOS_PRIORITY_LEVEL(h, l) ((((h) & 3) << 8) | ((l) & 3)) + +/* GRF_GPIO1CL_IOMUX */ +enum { + GPIO1C1_SHIFT = 4, + GPIO1C1_MASK = 0xf << GPIO1C1_SHIFT, + GPIO1C1_GPIO = 0, + GPIO1C1_UART1_TX, + + GPIO1C0_SHIFT = 0, + GPIO1C0_MASK = 0xf << GPIO1C0_SHIFT, + GPIO1C0_GPIO = 0, + GPIO1C0_UART1_RX, +}; + +/* GRF_GPIO1DL_IOMUX */ +enum { + GPIO1D3_SHIFT = 12, + GPIO1D3_MASK = 0xf << GPIO1D3_SHIFT, + GPIO1D3_GPIO = 0, + GPIO1D3_SDMMC_D1, + GPIO1D3_UART2_RXM0, + + GPIO1D2_SHIFT = 8, + GPIO1D2_MASK = 0xf << GPIO1D2_SHIFT, + GPIO1D2_GPIO = 0, + GPIO1D2_SDMMC_D0, + GPIO1D2_UART2_TXM0, +}; + +/* GRF_GPIO1DH_IOMUX */ +enum { + GPIO1D7_SHIFT = 12, + GPIO1D7_MASK = 0xf << GPIO1D7_SHIFT, + GPIO1D7_GPIO = 0, + GPIO1D7_SDMMC_CMD, + + GPIO1D6_SHIFT = 8, + GPIO1D6_MASK = 0xf << GPIO1D6_SHIFT, + GPIO1D6_GPIO = 0, + GPIO1D6_SDMMC_CLK, + + GPIO1D5_SHIFT = 4, + GPIO1D5_MASK = 0xf << GPIO1D5_SHIFT, + GPIO1D5_GPIO = 0, + GPIO1D5_SDMMC_D3, + + GPIO1D4_SHIFT = 0, + GPIO1D4_MASK = 0xf << GPIO1D4_SHIFT, + GPIO1D4_GPIO = 0, + GPIO1D4_SDMMC_D2, +}; + +/* GRF_GPIO2BH_IOMUX */ +enum { + GPIO2B6_SHIFT = 8, + GPIO2B6_MASK = 0xf << GPIO2B6_SHIFT, + GPIO2B6_GPIO = 0, + GPIO2B6_CIF_D1M0, + GPIO2B6_UART2_RXM1, + + GPIO2B4_SHIFT = 0, + GPIO2B4_MASK = 0xf << GPIO2B4_SHIFT, + GPIO2B4_GPIO = 0, + GPIO2B4_CIF_D0M0, + GPIO2B4_UART2_TXM1, +}; + +/* GRF_GPIO3AL_IOMUX */ +enum { + GPIO3A2_SHIFT = 8, + GPIO3A2_MASK = 0xf << GPIO3A2_SHIFT, + GPIO3A2_GPIO = 0, + GPIO3A2_UART5_TX = 4, + + GPIO3A1_SHIFT = 4, + GPIO3A1_MASK = 0xf << GPIO3A1_SHIFT, + GPIO3A1_GPIO = 0, + GPIO3A1_UART5_RX = 4, +}; + +int arch_cpu_init(void) +{ + static struct px30_grf * const grf = (void *)GRF_BASE; + u32 __maybe_unused val; + +#ifdef CONFIG_SPL_BUILD + /* We do some SoC one time setting here. */ + /* Disable the ddr secure region setting to make it non-secure */ + writel(0x0, DDR_FW_BASE + FW_DDR_CON); + + /* Set cpu qos priority */ + writel(QOS_PRIORITY_LEVEL(1, 1), SERVICE_CORE_ADDR + QOS_PRIORITY); + +#if !defined(CONFIG_DEBUG_UART_BOARD_INIT) || \ + (CONFIG_DEBUG_UART_BASE != 0xff160000) || \ + (CONFIG_DEBUG_UART_CHANNEL != 0) + /* fix sdmmc pinmux if not using uart2-channel0 as debug uart */ + rk_clrsetreg(&grf->gpio1dl_iomux, + GPIO1D3_MASK | GPIO1D2_MASK, + GPIO1D3_SDMMC_D1 << GPIO1D3_SHIFT | + GPIO1D2_SDMMC_D0 << GPIO1D2_SHIFT); + rk_clrsetreg(&grf->gpio1dh_iomux, + GPIO1D7_MASK | GPIO1D6_MASK | GPIO1D5_MASK | GPIO1D4_MASK, + GPIO1D7_SDMMC_CMD << GPIO1D7_SHIFT | + GPIO1D6_SDMMC_CLK << GPIO1D6_SHIFT | + GPIO1D5_SDMMC_D3 << GPIO1D5_SHIFT | + GPIO1D4_SDMMC_D2 << GPIO1D4_SHIFT); +#endif + +#endif + + /* Enable PD_VO (default disable at reset) */ + rk_clrreg(PMU_PWRDN_CON, 1 << 13); + + /* Disable video phy bandgap by default */ + writel(0x82, VIDEO_PHY_BASE + 0x0000); + writel(0x05, VIDEO_PHY_BASE + 0x03ac); + + /* Clear the force_jtag */ + rk_clrreg(&grf->cpu_con[1], 1 << 7); + + return 0; +} + +#ifdef CONFIG_DEBUG_UART_BOARD_INIT +void board_debug_uart_init(void) +{ + static struct px30_grf * const grf = (void *)GRF_BASE; + static struct px30_cru * const cru = (void *)CRU_BASE; + +#if defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff158000) + /* uart_sel_clk default select 24MHz */ + rk_clrsetreg(&cru->clksel_con[34], + UART1_PLL_SEL_MASK | UART1_DIV_CON_MASK, + UART1_PLL_SEL_24M << UART1_PLL_SEL_SHIFT | 0); + rk_clrsetreg(&cru->clksel_con[35], + UART1_CLK_SEL_MASK, + UART1_CLK_SEL_UART1 << UART1_CLK_SEL_SHIFT); + + rk_clrsetreg(&grf->gpio1cl_iomux, + GPIO1C1_MASK | GPIO1C0_MASK, + GPIO1C1_UART1_TX << GPIO1C1_SHIFT | + GPIO1C0_UART1_RX << GPIO1C0_SHIFT); +#elif defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff178000) + /* uart_sel_clk default select 24MHz */ + rk_clrsetreg(&cru->clksel_con[46], + UART5_PLL_SEL_MASK | UART5_DIV_CON_MASK, + UART5_PLL_SEL_24M << UART5_PLL_SEL_SHIFT | 0); + rk_clrsetreg(&cru->clksel_con[47], + UART5_CLK_SEL_MASK, + UART5_CLK_SEL_UART5 << UART5_CLK_SEL_SHIFT); + + rk_clrsetreg(&grf->gpio3al_iomux, + GPIO3A2_MASK | GPIO3A1_MASK, + GPIO3A2_UART5_TX << GPIO3A2_SHIFT | + GPIO3A1_UART5_RX << GPIO3A1_SHIFT); +#else + /* GRF_IOFUNC_CON0 */ + enum { + CON_IOMUX_UART2SEL_SHIFT = 10, + CON_IOMUX_UART2SEL_MASK = 3 << CON_IOMUX_UART2SEL_SHIFT, + CON_IOMUX_UART2SEL_M0 = 0, + CON_IOMUX_UART2SEL_M1, + CON_IOMUX_UART2SEL_USBPHY, + }; + + /* uart_sel_clk default select 24MHz */ + rk_clrsetreg(&cru->clksel_con[37], + UART2_PLL_SEL_MASK | UART2_DIV_CON_MASK, + UART2_PLL_SEL_24M << UART2_PLL_SEL_SHIFT | 0); + rk_clrsetreg(&cru->clksel_con[38], + UART2_CLK_SEL_MASK, + UART2_CLK_SEL_UART2 << UART2_CLK_SEL_SHIFT); + +#if (CONFIG_DEBUG_UART2_CHANNEL == 1) + /* Enable early UART2 */ + rk_clrsetreg(&grf->iofunc_con0, + CON_IOMUX_UART2SEL_MASK, + CON_IOMUX_UART2SEL_M1 << CON_IOMUX_UART2SEL_SHIFT); + + rk_clrsetreg(&grf->gpio2bh_iomux, + GPIO2B6_MASK | GPIO2B4_MASK, + GPIO2B6_UART2_RXM1 << GPIO2B6_SHIFT | + GPIO2B4_UART2_TXM1 << GPIO2B4_SHIFT); +#else + rk_clrsetreg(&grf->iofunc_con0, + CON_IOMUX_UART2SEL_MASK, + CON_IOMUX_UART2SEL_M0 << CON_IOMUX_UART2SEL_SHIFT); + + rk_clrsetreg(&grf->gpio1dl_iomux, + GPIO1D3_MASK | GPIO1D2_MASK, + GPIO1D3_UART2_RXM0 << GPIO1D3_SHIFT | + GPIO1D2_UART2_TXM0 << GPIO1D2_SHIFT); +#endif /* CONFIG_DEBUG_UART2_CHANNEL == 1 */ + +#endif /* CONFIG_DEBUG_UART_BASE && CONFIG_DEBUG_UART_BASE == ... */ +} +#endif /* CONFIG_DEBUG_UART_BOARD_INIT */ diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc new file mode 100644 index 0000000000..e17b2ed86c --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc @@ -0,0 +1,70 @@ +{ + { + .rank = 0x1, + .col = 0xC, + .bk = 0x3, + .bw = 0x1, + .dbw = 0x0, + .row_3_4 = 0x0, + .cs0_row = 0x10, + .cs1_row = 0x10, + .cs0_high16bit_row = 0x10, + .cs1_high16bit_row = 0x10, + .ddrconfig = 0, + { + 0x290b0609, + 0x08020401, + 0x00000002, + 0x00001111, + 0x0000000c, + 0x00000222, + 0x000000ff + } + }, + { + .ddr_freq = 333, + .dramtype = DDR3, + .num_channels = 1, + .stride = 0, + .odt = 0, + }, + { + { + {0x00000000, 0x43041001}, /* MSTR */ + {0x00000064, 0x0028003b}, /* RFSHTMG */ + {0x000000d0, 0x00020053}, /* INIT0 */ + {0x000000d4, 0x00020000}, /* INIT1 */ + {0x000000d8, 0x00000100}, /* INIT2 */ + {0x000000dc, 0x03200000}, /* INIT3 */ + {0x000000e0, 0x00000000}, /* INIT4 */ + {0x000000e4, 0x00090000}, /* INIT5 */ + {0x000000f4, 0x000f012f}, /* RANKCTL */ + {0x00000100, 0x07090b06}, /* DRAMTMG0 */ + {0x00000104, 0x00050209}, /* DRAMTMG1 */ + {0x00000108, 0x03030407}, /* DRAMTMG2 */ + {0x0000010c, 0x00202006}, /* DRAMTMG3 */ + {0x00000110, 0x03020204}, /* DRAMTMG4 */ + {0x00000114, 0x03030202}, /* DRAMTMG5 */ + {0x00000120, 0x00000903}, /* DRAMTMG8 */ + {0x00000180, 0x00800020}, /* ZQCTL0 */ + {0x00000184, 0x00000000}, /* ZQCTL1 */ + {0x00000190, 0x07010001}, /* DFITMG0 */ + {0x00000198, 0x07000101}, /* DFILPCFG0 */ + {0x000001a0, 0xc0400003}, /* DFIUPD0 */ + {0x00000240, 0x06000604}, /* ODTCFG */ + {0x00000244, 0x00000201}, /* ODTMAP */ + {0x00000250, 0x00001f00}, /* SCHED */ + {0x00000490, 0x00000001}, /* PCTRL_0 */ + {0xffffffff, 0xffffffff} + } + }, + { + { + {0x00000004, 0x0000000a}, /* PHYREG01 */ + {0x00000028, 0x00000006}, /* PHYREG0A */ + {0x0000002c, 0x00000000}, /* PHYREG0B */ + {0x00000030, 0x00000005}, /* PHYREG0C */ + {0xffffffff, 0xffffffff} + } + } +}, diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc new file mode 100644 index 0000000000..cdc417405a --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc @@ -0,0 +1,73 @@ +{ + { + .rank = 0x1, + .col = 0xA, + .bk = 0x2, + .bw = 0x1, + .dbw = 0x0, + .row_3_4 = 0x0, + .cs0_row = 0x11, + .cs1_row = 0x0, + .cs0_high16bit_row = 0x11, + .cs1_high16bit_row = 0x0, + .ddrconfig = 0, + { + 0x4d110a08, + 0x06020501, + 0x00000002, + 0x00001111, + 0x0000000c, + 0x0000022a, + 0x000000ff + } + }, + { + .ddr_freq = 333, + .dramtype = DDR4, + .num_channels = 1, + .stride = 0, + .odt = 0, + }, + { + { + {0x00000000, 0x43049010}, /* MSTR */ + {0x00000064, 0x0028003b}, /* RFSHTMG */ + {0x000000d0, 0x00020053}, /* INIT0 */ + {0x000000d4, 0x00220000}, /* INIT1 */ + {0x000000d8, 0x00000100}, /* INIT2 */ + {0x000000dc, 0x00040000}, /* INIT3 */ + {0x000000e0, 0x00000000}, /* INIT4 */ + {0x000000e4, 0x00110000}, /* INIT5 */ + {0x000000e8, 0x00000420}, /* INIT6 */ + {0x000000ec, 0x00000400}, /* INIT7 */ + {0x000000f4, 0x000f012f}, /* RANKCTL */ + {0x00000100, 0x09060b06}, /* DRAMTMG0 */ + {0x00000104, 0x00020209}, /* DRAMTMG1 */ + {0x00000108, 0x0505040a}, /* DRAMTMG2 */ + {0x0000010c, 0x0040400c}, /* DRAMTMG3 */ + {0x00000110, 0x05030206}, /* DRAMTMG4 */ + {0x00000114, 0x03030202}, /* DRAMTMG5 */ + {0x00000120, 0x03030b03}, /* DRAMTMG8 */ + {0x00000124, 0x00020208}, /* DRAMTMG9 */ + {0x00000180, 0x01000040}, /* ZQCTL0 */ + {0x00000184, 0x00000000}, /* ZQCTL1 */ + {0x00000190, 0x07030003}, /* DFITMG0 */ + {0x00000198, 0x07000101}, /* DFILPCFG0 */ + {0x000001a0, 0xc0400003}, /* DFIUPD0 */ + {0x00000240, 0x06000604}, /* ODTCFG */ + {0x00000244, 0x00000201}, /* ODTMAP */ + {0x00000250, 0x00001f00}, /* SCHED */ + {0x00000490, 0x00000001}, /* PCTRL_0 */ + {0xffffffff, 0xffffffff} + } + }, + { + { + {0x00000004, 0x0000000c}, /* PHYREG01 */ + {0x00000028, 0x0000000a}, /* PHYREG0A */ + {0x0000002c, 0x00000000}, /* PHYREG0B */ + {0x00000030, 0x00000009}, /* PHYREG0C */ + {0xffffffff, 0xffffffff} + } + } +}, \ No newline at end of file diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc new file mode 100644 index 0000000000..f24343dda1 --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc @@ -0,0 +1,121 @@ + { + 0x77, + 0x88, + 0x79, + 0x79, + 0x87, + 0x97, + 0x87, + 0x78, + 0x77, + 0x78, + 0x87, + 0x88, + 0x87, + 0x87, + 0x77 + }, + { + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x69, + 0x9, + }, + { + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x79, + 0x9, + }, + { + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x69, + 0x9, + }, + { + 0x77, + 0x78, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x79, + 0x9, + }, + { + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x69, + 0x9, + }, + { + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x78, + 0x77, + 0x79, + 0x9, + }, + { + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x78, + 0x69, + 0x9, + }, + { + 0x77, + 0x78, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x77, + 0x79, + 0x9, + } diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc new file mode 100644 index 0000000000..3bde062d62 --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc @@ -0,0 +1,71 @@ +{ + { + .rank = 0x1, + .col = 0xC, + .bk = 0x3, + .bw = 0x1, + .dbw = 0x0, + .row_3_4 = 0x0, + .cs0_row = 0xF, + .cs1_row = 0xF, + .cs0_high16bit_row = 0xF, + .cs1_high16bit_row = 0xF, + .ddrconfig = 0, + { + 0x2b0c070a, + 0x08020303, + 0x00000002, + 0x00001111, + 0x0000000c, + 0x00000219, + 0x000000ff + } + }, + { + .ddr_freq = 333, + .dramtype = LPDDR2, + .num_channels = 1, + .stride = 0, + .odt = 0, + }, + { + { + {0x00000000, 0x41041004}, /* MSTR */ + {0x00000064, 0x00140023}, /* RFSHTMG */ + {0x000000d0, 0x00220002}, /* INIT0 */ + {0x000000d4, 0x00010000}, /* INIT1 */ + {0x000000d8, 0x00000703}, /* INIT2 */ + {0x000000dc, 0x00630005}, /* INIT3 */ + {0x000000e0, 0x00010000}, /* INIT4 */ + {0x000000e4, 0x00070003}, /* INIT5 */ + {0x000000f4, 0x000f012f}, /* RANKCTL */ + {0x00000100, 0x07090b07}, /* DRAMTMG0 */ + {0x00000104, 0x0002010b}, /* DRAMTMG1 */ + {0x00000108, 0x02040506}, /* DRAMTMG2 */ + {0x0000010c, 0x00303000}, /* DRAMTMG3 */ + {0x00000110, 0x04010204}, /* DRAMTMG4 */ + {0x00000114, 0x01010303}, /* DRAMTMG5 */ + {0x00000118, 0x02020003}, /* DRAMTMG6 */ + {0x00000120, 0x00000303}, /* DRAMTMG8 */ + {0x00000138, 0x00000025}, /* DRAMTMG14 */ + {0x00000180, 0x003c000f}, /* ZQCTL0 */ + {0x00000184, 0x00900000}, /* ZQCTL1 */ + {0x00000190, 0x07020001}, /* DFITMG0 */ + {0x00000198, 0x07000101}, /* DFILPCFG0 */ + {0x000001a0, 0xc0400003}, /* DFIUPD0 */ + {0x00000240, 0x07030718}, /* ODTCFG */ + {0x00000250, 0x00001f00}, /* SCHED */ + {0x00000490, 0x00000001}, /* PCTRL_0 */ + {0xffffffff, 0xffffffff} + } + }, + { + { + {0x00000004, 0x00000009}, /* PHYREG01 */ + {0x00000028, 0x00000007}, /* PHYREG0A */ + {0x0000002c, 0x00000000}, /* PHYREG0B */ + {0x00000030, 0x00000004}, /* PHYREG0C */ + {0xffffffff, 0xffffffff} + } + } +}, diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc new file mode 100644 index 0000000000..a205fc9332 --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc @@ -0,0 +1,72 @@ +{ + { + .rank = 0x1, + .col = 0xC, + .bk = 0x3, + .bw = 0x1, + .dbw = 0x0, + .row_3_4 = 0x0, + .cs0_row = 0x10, + .cs1_row = 0x10, + .cs0_high16bit_row = 0x10, + .cs1_high16bit_row = 0x10, + .ddrconfig = 0, + { + 0x290a060a, + 0x08020303, + 0x00000002, + 0x00001111, + 0x0000000c, + 0x0000021a, + 0x000000ff + } + }, + { + .ddr_freq = 333, + .dramtype = LPDDR3, + .num_channels = 1, + .stride = 0, + .odt = 0, + }, + { + { + {0x00000000, 0x43041008}, /* MSTR */ + {0x00000064, 0x00140023}, /* RFSHTMG */ + {0x000000d0, 0x00220002}, /* INIT0 */ + {0x000000d4, 0x00010000}, /* INIT1 */ + {0x000000d8, 0x00000703}, /* INIT2 */ + {0x000000dc, 0x00830004}, /* INIT3 */ + {0x000000e0, 0x00010000}, /* INIT4 */ + {0x000000e4, 0x00070003}, /* INIT5 */ + {0x000000f4, 0x000f012f}, /* RANKCTL */ + {0x00000100, 0x06090b07}, /* DRAMTMG0 */ + {0x00000104, 0x0002020b}, /* DRAMTMG1 */ + {0x00000108, 0x02030506}, /* DRAMTMG2 */ + {0x0000010c, 0x00505000}, /* DRAMTMG3 */ + {0x00000110, 0x03020204}, /* DRAMTMG4 */ + {0x00000114, 0x01010303}, /* DRAMTMG5 */ + {0x00000118, 0x02020003}, /* DRAMTMG6 */ + {0x00000120, 0x00000303}, /* DRAMTMG8 */ + {0x00000138, 0x00000025}, /* DRAMTMG14 */ + {0x00000180, 0x003c000f}, /* ZQCTL0 */ + {0x00000184, 0x00900000}, /* ZQCTL1 */ + {0x00000190, 0x07020000}, /* DFITMG0 */ + {0x00000198, 0x07000101}, /* DFILPCFG0 */ + {0x000001a0, 0xc0400003}, /* DFIUPD0 */ + {0x00000240, 0x0900090c}, /* ODTCFG */ + {0x00000244, 0x00000101}, /* ODTMAP */ + {0x00000250, 0x00001f00}, /* SCHED */ + {0x00000490, 0x00000001}, /* PCTRL_0 */ + {0xffffffff, 0xffffffff} + } + }, + { + { + {0x00000004, 0x0000000b}, /* PHYREG01 */ + {0x00000028, 0x00000006}, /* PHYREG0A */ + {0x0000002c, 0x00000000}, /* PHYREG0B */ + {0x00000030, 0x00000003}, /* PHYREG0C */ + {0xffffffff, 0xffffffff} + } + } +}, diff --git a/arch/arm/mach-rockchip/px30/sdram_px30.c b/arch/arm/mach-rockchip/px30/sdram_px30.c new file mode 100644 index 0000000000..2590d9366e --- /dev/null +++ b/arch/arm/mach-rockchip/px30/sdram_px30.c @@ -0,0 +1,1405 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2018 Rockchip Electronics Co., Ltd. + */ + +#include <common.h> +#include <debug_uart.h> +#include <dm.h> +#include <ram.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_px30.h> +#include <asm/arch-rockchip/grf_px30.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/sdram_common.h> +#include <asm/arch-rockchip/sdram_px30.h> + +#define TIMER_CUR_VALUE0 0x08 +#define TIMER_CUR_VALUE1 0x0c + +static u64 rockchip_get_ticks(void) +{ + u64 timebase_h, timebase_l; + + timebase_l = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE0); + timebase_h = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE1); + + return timebase_h << 32 | timebase_l; +} + +void rockchip_udelay(unsigned int usec) +{ + u64 tmp; + + /* get timestamp */ + tmp = rockchip_get_ticks() + usec_to_tick(usec); + + /* loop till event */ + while (rockchip_get_ticks() < tmp + 1) + ; +} + +u8 ddr_cfg_2_rbc[] = { + /* + * [6:4] max row: 13+n + * [3] bank(0:4bank,1:8bank) + * [2:0] col(10+n) + */ + ((5 << 4) | (1 << 3) | 0), /* 0 */ + ((5 << 4) | (1 << 3) | 1), /* 1 */ + ((4 << 4) | (1 << 3) | 2), /* 2 */ + ((3 << 4) | (1 << 3) | 3), /* 3 */ + ((2 << 4) | (1 << 3) | 4), /* 4 */ + ((5 << 4) | (0 << 3) | 2), /* 5 */ + ((4 << 4) | (1 << 3) | 2), /* 6 */ +}; + +#ifdef CONFIG_TPL_BUILD + +/* + * for ddr4 if ddrconfig=7, upctl should set 7 and noc should + * set to 1 for more efficient. + * noc ddrconf, upctl addrmap + * 1 7 + * 2 8 + * 3 9 + * 12 10 + * 5 11 + */ +static u8 d4_rbc_2_d3_rbc[] = { + 1, /* 7 */ + 2, /* 8 */ + 3, /* 9 */ + 12, /* 10 */ + 5, /* 11 */ +}; + +/* + * row higher than cs should be disabled by set to 0xf + * rank addrmap calculate by real cap. + */ +static u32 addrmap[][8] = { + /* map0 map1, map2, map3, map4, map5 + * map6, map7, map8 + * ------------------------------------------------------- + * bk2-0 col 5-2 col 9-6 col 11-10 row 11-0 + * row 15-12 row 17-16 bg1,0 + * ------------------------------------------------------- + * 4,3,2 5-2 9-6 6 + * 3,2 + */ + {0x00060606, 0x00000000, 0x1f1f0000, 0x00001f1f, 0x05050505, + 0x05050505, 0x00000505, 0x3f3f}, /* 0 */ + {0x00070707, 0x00000000, 0x1f000000, 0x00001f1f, 0x06060606, + 0x06060606, 0x06060606, 0x3f3f}, /* 1 */ + {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707, + 0x07070707, 0x00000f07, 0x3f3f}, /* 2 */ + {0x00090909, 0x00000000, 0x00000000, 0x00001f00, 0x08080808, + 0x08080808, 0x00000f0f, 0x3f3f}, /* 3 */ + {0x000a0a0a, 0x00000000, 0x00000000, 0x00000000, 0x09090909, + 0x0f090909, 0x00000f0f, 0x3f3f}, /* 4 */ + {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x06060606, + 0x06060606, 0x00000606, 0x3f3f}, /* 5 */ + {0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707, + 0x07070707, 0x00000f0f, 0x3f3f}, /* 6 */ + {0x003f0808, 0x00000006, 0x1f1f0000, 0x00001f1f, 0x06060606, + 0x06060606, 0x00000606, 0x0600}, /* 7 */ + {0x003f0909, 0x00000007, 0x1f000000, 0x00001f1f, 0x07070707, + 0x07070707, 0x00000f07, 0x0700}, /* 8 */ + {0x003f0a0a, 0x01010100, 0x01010101, 0x00001f1f, 0x08080808, + 0x08080808, 0x00000f0f, 0x0801}, /* 9 */ + {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707, + 0x07070707, 0x00000f07, 0x3f01}, /* 10 */ + {0x003f0808, 0x00000007, 0x1f000000, 0x00001f1f, 0x06060606, + 0x06060606, 0x00000606, 0x3f00}, /* 11 */ + /* when ddr4 12 map to 10, when ddr3 12 unused */ + {0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707, + 0x07070707, 0x00000f07, 0x3f01}, /* 10 */ + {0x00070706, 0x00000000, 0x1f010000, 0x00001f1f, 0x06060606, + 0x06060606, 0x00000606, 0x3f3f}, /* 13 */ +}; + +DECLARE_GLOBAL_DATA_PTR; +struct dram_info { + struct ddr_pctl_regs *pctl; + struct ddr_phy_regs *phy; + struct px30_cru *cru; + struct px30_msch_regs *msch; + struct px30_ddr_grf_regs *ddr_grf; + struct px30_grf *grf; + struct ram_info info; + struct px30_pmugrf *pmugrf; +}; + +#define PMUGRF_BASE_ADDR 0xFF010000 +#define CRU_BASE_ADDR 0xFF2B0000 +#define GRF_BASE_ADDR 0xFF140000 +#define DDRC_BASE_ADDR 0xFF600000 +#define DDR_PHY_BASE_ADDR 0xFF2A0000 +#define SERVER_MSCH0_BASE_ADDR 0xFF530000 +#define DDR_GRF_BASE_ADDR 0xff630000 + +struct dram_info dram_info; + +struct px30_sdram_params sdram_configs[] = { +#include "sdram-px30-ddr3-detect-333.inc" +}; + +struct ddr_phy_skew skew = { +#include "sdram-px30-ddr_skew.inc" +}; + +#define PATTERN (0x5aa5f00f) + +/* + * cs: 0:cs0 + * 1:cs1 + * else cs0+cs1 + * note: it didn't consider about row_3_4 + */ +u64 sdram_get_cs_cap(struct px30_sdram_channel *cap_info, u32 cs, u32 dram_type) +{ + u32 bg; + u64 cap[2]; + + if (dram_type == DDR4) + /* DDR4 8bit dram BG = 2(4bank groups), + * 16bit dram BG = 1 (2 bank groups) + */ + bg = (cap_info->dbw == 0) ? 2 : 1; + else + bg = 0; + cap[0] = 1llu << (cap_info->bw + cap_info->col + + bg + cap_info->bk + cap_info->cs0_row); + + if (cap_info->rank == 2) + cap[1] = 1llu << (cap_info->bw + cap_info->col + + bg + cap_info->bk + cap_info->cs1_row); + else + cap[1] = 0; + + if (cs == 0) + return cap[0]; + else if (cs == 1) + return cap[1]; + else + return (cap[0] + cap[1]); +} + +/* n: Unit bytes */ +void sdram_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 sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq) +{ + u32 tmp; + u32 i, j; + + setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4); + clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3); + for (i = 0; i < 4; i++) { + j = 0x26 + i * 0x10; + setbits_le32(PHY_REG(phy_base, j), 1 << 4); + clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3); + } + + if (freq <= (400000000)) + /* DLL bypass */ + setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); + else + clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); + + if (freq <= (801000000)) + tmp = 2; + else + tmp = 1; + + for (i = 0; i < 4; i++) { + j = 0x28 + i * 0x10; + writel(tmp, PHY_REG(phy_base, j)); + } +} + +static void sdram_phy_set_ds_odt(void __iomem *phy_base, + u32 dram_type) +{ + u32 cmd_drv, clk_drv, dqs_drv, dqs_odt; + u32 i, j; + + if (dram_type == DDR3) { + cmd_drv = PHY_DDR3_RON_RTT_34ohm; + clk_drv = PHY_DDR3_RON_RTT_45ohm; + dqs_drv = PHY_DDR3_RON_RTT_34ohm; + dqs_odt = PHY_DDR3_RON_RTT_225ohm; + } else { + cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; + clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm; + dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; + if (dram_type == LPDDR2) + dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE; + else + dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm; + } + /* DS */ + writel(cmd_drv, PHY_REG(phy_base, 0x11)); + clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3); + writel(clk_drv, PHY_REG(phy_base, 0x16)); + writel(clk_drv, PHY_REG(phy_base, 0x18)); + + for (i = 0; i < 4; i++) { + j = 0x20 + i * 0x10; + writel(dqs_drv, PHY_REG(phy_base, j)); + writel(dqs_drv, PHY_REG(phy_base, j + 0xf)); + /* ODT */ + writel(dqs_odt, PHY_REG(phy_base, j + 0x1)); + writel(dqs_odt, PHY_REG(phy_base, j + 0xe)); + } +} + +static void phy_soft_reset(void __iomem *phy_base) +{ + clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2); + udelay(1); + setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET); + udelay(5); + setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET); + udelay(1); +} + +static void phy_dram_set_bw(void __iomem *phy_base, u32 bw) +{ + if (bw == 2) { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); + setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); + setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); + } else if (bw == 1) { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4); + clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); + } else if (bw == 0) { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4); + clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); + } + + phy_soft_reset(phy_base); +} + +static int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype) +{ + u32 ret; + u32 odt_val; + u32 i, j; + + odt_val = readl(PHY_REG(phy_base, 0x2e)); + + for (i = 0; i < 4; i++) { + j = 0x20 + i * 0x10; + writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1)); + writel(0, PHY_REG(phy_base, j + 0xe)); + } + + if (dramtype == DDR4) { + clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0); + clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0); + clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0); + clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0); + } + /* choose training cs */ + clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs)); + /* enable gate training */ + clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1); + udelay(50); + ret = readl(PHY_REG(phy_base, 0xff)); + /* disable gate training */ + clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0); + clrbits_le32(PHY_REG(phy_base, 2), 0x30); + + if (dramtype == DDR4) { + clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2); + clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2); + clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2); + clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2); + } + + if (ret & 0x10) { + ret = -1; + } else { + ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4); + ret = (ret == 0) ? 0 : -1; + } + + for (i = 0; i < 4; i++) { + j = 0x20 + i * 0x10; + writel(odt_val, PHY_REG(phy_base, j + 0x1)); + writel(odt_val, PHY_REG(phy_base, j + 0xe)); + } + + return ret; +} + +static void phy_cfg(void __iomem *phy_base, + struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew, + struct px30_base_params *base, u32 bw) +{ + u32 i; + + sdram_phy_dll_bypass_set(phy_base, base->ddr_freq); + for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) { + writel(phy_regs->phy[i][1], + phy_base + phy_regs->phy[i][0]); + } + if (bw == 2) { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); + } else if (bw == 1) { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4); + /* disable DQS2,DQS3 tx dll for saving power */ + clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); + } else { + clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4); + /* disable DQS2,DQS3 tx dll for saving power */ + clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); + clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); + } + sdram_phy_set_ds_odt(phy_base, base->dramtype); + + /* deskew */ + setbits_le32(PHY_REG(phy_base, 2), 8); + sdram_copy_to_reg(PHY_REG(phy_base, 0xb0), + &skew->a0_a1_skew[0], 15 * 4); + sdram_copy_to_reg(PHY_REG(phy_base, 0x70), + &skew->cs0_dm0_skew[0], 44 * 4); + sdram_copy_to_reg(PHY_REG(phy_base, 0xc0), + &skew->cs1_dm0_skew[0], 44 * 4); +} + +void sdram_org_config(struct px30_sdram_channel *info, + struct px30_base_params *base, + u32 *p_os_reg2, u32 *p_os_reg3, u32 channel) +{ + *p_os_reg2 |= base->dramtype << SYS_REG_DDRTYPE_SHIFT; + *p_os_reg2 |= (base->num_channels - 1) << SYS_REG_NUM_CH_SHIFT; + *p_os_reg2 |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel); + *p_os_reg2 |= 1 << SYS_REG_CHINFO_SHIFT(channel); + *p_os_reg2 |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel); + *p_os_reg2 |= (info->col - 9) << SYS_REG_COL_SHIFT(channel); + *p_os_reg2 |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel); + *p_os_reg2 |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel); + if (info->cs1_row >= 13) + *p_os_reg2 |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(channel); + *p_os_reg2 |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel); + *p_os_reg2 |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel); +} + +void sdram_msch_config(struct px30_msch_regs *msch, + struct px30_msch_timings *noc_timings, + struct px30_sdram_channel *cap_info, + struct px30_base_params *base) +{ + u64 cs_cap[2]; + + cs_cap[0] = sdram_get_cs_cap(cap_info, 0, base->dramtype); + cs_cap[1] = sdram_get_cs_cap(cap_info, 1, base->dramtype); + writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) | + (((cs_cap[0] >> 20) / 64) & 0xff), + &msch->devicesize); + + writel(noc_timings->ddrtiminga0, &msch->ddrtiminga0); + writel(noc_timings->ddrtimingb0, &msch->ddrtimingb0); + writel(noc_timings->ddrtimingc0, &msch->ddrtimingc0); + writel(noc_timings->devtodev0, &msch->devtodev0); + writel(noc_timings->ddrmode, &msch->ddrmode); + writel(noc_timings->ddr4timing, &msch->ddr4timing); + writel(noc_timings->agingx0, &msch->agingx0); + writel(noc_timings->agingx0, &msch->aging0); + writel(noc_timings->agingx0, &msch->aging1); + writel(noc_timings->agingx0, &msch->aging2); + writel(noc_timings->agingx0, &msch->aging3); +} + +int sdram_detect_bw(struct px30_sdram_channel *cap_info) +{ + return 0; +} + +int sdram_detect_cs(struct px30_sdram_channel *cap_info) +{ + return 0; +} + +int sdram_detect_col(struct px30_sdram_channel *cap_info, + u32 coltmp) +{ + void __iomem *test_addr; + u32 col; + u32 bw = cap_info->bw; + + for (col = coltmp; col >= 9; col -= 1) { + writel(0, CONFIG_SYS_SDRAM_BASE); + test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + (1ul << (col + bw - 1ul))); + writel(PATTERN, test_addr); + if ((readl(test_addr) == PATTERN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + printascii("col error\n"); + return -1; + } + + cap_info->col = col; + + return 0; +} + +int sdram_detect_bank(struct px30_sdram_channel *cap_info, + u32 coltmp, u32 bktmp) +{ + void __iomem *test_addr; + u32 bk; + u32 bw = cap_info->bw; + + test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + (1ul << (coltmp + bktmp + bw - 1ul))); + writel(0, CONFIG_SYS_SDRAM_BASE); + writel(PATTERN, test_addr); + if ((readl(test_addr) == PATTERN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + bk = 3; + else + bk = 2; + + cap_info->bk = bk; + + return 0; +} + +/* detect bg for ddr4 */ +int sdram_detect_bg(struct px30_sdram_channel *cap_info, + u32 coltmp) +{ + void __iomem *test_addr; + u32 dbw; + u32 bw = cap_info->bw; + + test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + (1ul << (coltmp + bw + 1ul))); + writel(0, CONFIG_SYS_SDRAM_BASE); + writel(PATTERN, test_addr); + if ((readl(test_addr) == PATTERN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + dbw = 0; + else + dbw = 1; + + cap_info->dbw = dbw; + + return 0; +} + +/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */ +int sdram_detect_dbw(struct px30_sdram_channel *cap_info, u32 dram_type) +{ + u32 row, col, bk, bw, cs_cap, cs; + u32 die_bw_0 = 0, die_bw_1 = 0; + + if (dram_type == DDR3 || dram_type == LPDDR4) { + cap_info->dbw = 1; + } else if (dram_type == LPDDR3 || dram_type == LPDDR2) { + row = cap_info->cs0_row; + col = cap_info->col; + bk = cap_info->bk; + cs = cap_info->rank; + bw = cap_info->bw; + cs_cap = (1 << (row + col + bk + bw - 20)); + if (bw == 2) { + if (cs_cap <= 0x2000000) /* 256Mb */ + die_bw_0 = (col < 9) ? 2 : 1; + else if (cs_cap <= 0x10000000) /* 2Gb */ + die_bw_0 = (col < 10) ? 2 : 1; + else if (cs_cap <= 0x40000000) /* 8Gb */ + die_bw_0 = (col < 11) ? 2 : 1; + else + die_bw_0 = (col < 12) ? 2 : 1; + if (cs > 1) { + row = cap_info->cs1_row; + cs_cap = (1 << (row + col + bk + bw - 20)); + if (cs_cap <= 0x2000000) /* 256Mb */ + die_bw_0 = (col < 9) ? 2 : 1; + else if (cs_cap <= 0x10000000) /* 2Gb */ + die_bw_0 = (col < 10) ? 2 : 1; + else if (cs_cap <= 0x40000000) /* 8Gb */ + die_bw_0 = (col < 11) ? 2 : 1; + else + die_bw_0 = (col < 12) ? 2 : 1; + } + } else { + die_bw_1 = 1; + die_bw_0 = 1; + } + cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1; + } + + return 0; +} + +int sdram_detect_row(struct px30_sdram_channel *cap_info, + u32 coltmp, u32 bktmp, u32 rowtmp) +{ + u32 row; + u32 bw = cap_info->bw; + void __iomem *test_addr; + + for (row = rowtmp; row > 12; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + (1ul << (row + bktmp + coltmp + bw - 1ul))); + writel(PATTERN, test_addr); + if ((readl(test_addr) == PATTERN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 12) { + printascii("row error"); + return -1; + } + + cap_info->cs0_row = row; + + return 0; +} + +int sdram_detect_row_3_4(struct px30_sdram_channel *cap_info, + u32 coltmp, u32 bktmp) +{ + u32 row_3_4; + u32 bw = cap_info->bw; + u32 row = cap_info->cs0_row; + void __iomem *test_addr, *test_addr1; + + test_addr = CONFIG_SYS_SDRAM_BASE; + test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul))); + + writel(0, test_addr); + writel(PATTERN, test_addr1); + if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN)) + row_3_4 = 0; + else + row_3_4 = 1; + + cap_info->row_3_4 = row_3_4; + + return 0; +} + +int sdram_detect_high_row(struct px30_sdram_channel *cap_info) +{ + cap_info->cs0_high16bit_row = cap_info->cs0_row; + cap_info->cs1_high16bit_row = cap_info->cs1_row; + + return 0; +} + +int sdram_detect_cs1_row(struct px30_sdram_channel *cap_info, u32 dram_type) +{ + void __iomem *test_addr; + u32 row = 0, bktmp, coltmp, bw; + ulong cs0_cap; + u32 byte_mask; + + if (cap_info->rank == 2) { + cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type); + + if (dram_type == DDR4) { + if (cap_info->dbw == 0) + bktmp = cap_info->bk + 2; + else + bktmp = cap_info->bk + 1; + } else { + bktmp = cap_info->bk; + } + bw = cap_info->bw; + coltmp = cap_info->col; + + /* + * because px30 support axi split,min bandwidth + * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit + * so we check low 16bit data when detect cs1 row. + * if cs0 is 16bit/8bit, we check low 8bit data. + */ + if (bw == 2) + byte_mask = 0xFFFF; + else + byte_mask = 0xFF; + + /* detect cs1 row */ + for (row = cap_info->cs0_row; row > 12; row--) { + test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + + cs0_cap + + (1ul << (row + bktmp + coltmp + bw - 1ul))); + writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap); + writel(PATTERN, test_addr); + + if (((readl(test_addr) & byte_mask) == + (PATTERN & byte_mask)) && + ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) & + byte_mask) == 0)) { + break; + } + } + } + + cap_info->cs1_row = row; + + return 0; +} + +static void rkclk_ddr_reset(struct dram_info *dram, + u32 ctl_srstn, u32 ctl_psrstn, + u32 phy_srstn, u32 phy_psrstn) +{ + writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) | + upctl2_asrstn_req(ctl_srstn), + &dram->cru->softrst_con[1]); + writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn), + &dram->cru->softrst_con[2]); +} + +static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz) +{ + unsigned int refdiv, postdiv1, postdiv2, fbdiv; + int delay = 1000; + u32 mhz = hz / MHz; + + refdiv = 1; + if (mhz <= 300) { + postdiv1 = 4; + postdiv2 = 2; + } else if (mhz <= 400) { + postdiv1 = 6; + postdiv2 = 1; + } else if (mhz <= 600) { + postdiv1 = 4; + postdiv2 = 1; + } else if (mhz <= 800) { + postdiv1 = 3; + postdiv2 = 1; + } else if (mhz <= 1600) { + postdiv1 = 2; + postdiv2 = 1; + } else { + postdiv1 = 1; + postdiv2 = 1; + } + fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24; + + writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode); + + writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0); + writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv), + &dram->cru->pll[1].con1); + + while (delay > 0) { + rockchip_udelay(1); + if (LOCK(readl(&dram->cru->pll[1].con1))) + break; + delay--; + } + + writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode); +} + +static void rkclk_configure_ddr(struct dram_info *dram, + struct px30_sdram_params *sdram_params) +{ + /* for inno ddr phy need 2*freq */ + rkclk_set_dpll(dram, sdram_params->base.ddr_freq * MHz * 2); +} + +/* return ddrconfig value + * (-1), find ddrconfig fail + * other, the ddrconfig value + * only support cs0_row >= cs1_row + */ +static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + u32 bw, die_bw, col, bank; + u32 i, tmp; + u32 ddrconf = -1; + + bw = cap_info->bw; + die_bw = cap_info->dbw; + col = cap_info->col; + bank = cap_info->bk; + + if (sdram_params->base.dramtype == DDR4) { + if (die_bw == 0) + ddrconf = 7 + bw; + else + ddrconf = 12 - bw; + ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7]; + } else { + tmp = ((bank - 2) << 3) | (col + bw - 10); + for (i = 0; i < 7; i++) + if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) { + ddrconf = i; + break; + } + if (i > 6) + printascii("calculate ddrconfig error\n"); + } + + return ddrconf; +} + +/* + * rank = 1: cs0 + * rank = 2: cs1 + */ +static void pctl_read_mr(void __iomem *pctl_base, u32 rank, u32 mr_num) +{ + writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0); + writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1); + setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); + while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) + continue; + while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) + continue; +} + +/* rank = 1: cs0 + * rank = 2: cs1 + * rank = 3: cs0 & cs1 + * note: be careful of keep mr original val + */ +static int pctl_write_mr(void __iomem *pctl_base, u32 rank, u32 mr_num, u32 arg, + u32 dramtype) +{ + while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) + continue; + if (dramtype == DDR3 || dramtype == DDR4) { + writel((mr_num << 12) | (rank << 4) | (0 << 0), + pctl_base + DDR_PCTL2_MRCTRL0); + writel(arg, pctl_base + DDR_PCTL2_MRCTRL1); + } else { + writel((rank << 4) | (0 << 0), + pctl_base + DDR_PCTL2_MRCTRL0); + writel((mr_num << 8) | (arg & 0xff), + pctl_base + DDR_PCTL2_MRCTRL1); + } + + setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); + while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) + continue; + while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) + continue; + + return 0; +} + +static int upctl2_update_ref_reg(void __iomem *pctl_base) +{ + u32 ret; + + ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1); + writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3); + + return 0; +} + +static u32 pctl_dis_zqcs_aref(void __iomem *pctl_base) +{ + u32 dis_auto_zq = 0; + + /* disable zqcs */ + if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) & + (1ul << 31))) { + dis_auto_zq = 1; + setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); + } + + /* disable auto refresh */ + setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); + + upctl2_update_ref_reg(pctl_base); + + return dis_auto_zq; +} + +static void pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq) +{ + /* restore zqcs */ + if (dis_auto_zq) + clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); + + /* restore auto refresh */ + clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); + + upctl2_update_ref_reg(pctl_base); +} + +/* + * rank : 1:cs0, 2:cs1, 3:cs0&cs1 + * vrefrate: 4500: 45%, + */ +static int pctl_write_vrefdq(void __iomem *pctl_base, u32 rank, u32 vrefrate, + u32 dramtype) +{ + u32 tccd_l, value; + u32 dis_auto_zq = 0; + + if (dramtype != DDR4 || vrefrate < 4500 || + vrefrate > 9200) + return (-1); + + tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf; + tccd_l = (tccd_l - 4) << 10; + + if (vrefrate > 7500) { + /* range 1 */ + value = ((vrefrate - 6000) / 65) | tccd_l; + } else { + /* range 2 */ + value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6); + } + + dis_auto_zq = pctl_dis_zqcs_aref(pctl_base); + + /* enable vrefdq calibratin */ + pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype); + udelay(1);/* tvrefdqe */ + /* write vrefdq value */ + pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype); + udelay(1);/* tvref_time */ + pctl_write_mr(pctl_base, rank, 6, value | (0 << 7), dramtype); + udelay(1);/* tvrefdqx */ + + pctl_rest_zqcs_aref(pctl_base, dis_auto_zq); + + return 0; +} + +static u32 pctl_remodify_sdram_params(struct ddr_pctl_regs *pctl_regs, + struct px30_sdram_channel *cap_info, + u32 dram_type) +{ + u32 tmp = 0, tmp_adr = 0, i; + + for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) { + if (pctl_regs->pctl[i][0] == 0) { + tmp = pctl_regs->pctl[i][1];/* MSTR */ + tmp_adr = i; + } + } + + tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12)); + + switch (cap_info->dbw) { + case 2: + tmp |= (3ul << 30); + break; + case 1: + tmp |= (2ul << 30); + break; + case 0: + default: + tmp |= (1ul << 30); + break; + } + + /* + * If DDR3 or DDR4 MSTR.active_ranks=1, + * it will gate memory clock when enter power down. + * Force set active_ranks to 3 to workaround it. + */ + if (cap_info->rank == 2 || dram_type == DDR3 || + dram_type == DDR4) + tmp |= 3 << 24; + else + tmp |= 1 << 24; + + tmp |= (2 - cap_info->bw) << 12; + + pctl_regs->pctl[tmp_adr][1] = tmp; + + return 0; +} + +static int pctl_cfg(void __iomem *pctl_base, struct ddr_pctl_regs *pctl_regs, + u32 sr_idle, u32 pd_idle) +{ + u32 i; + + for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) { + writel(pctl_regs->pctl[i][1], + pctl_base + pctl_regs->pctl[i][0]); + } + clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG, + (0xff << 16) | 0x1f, + ((sr_idle & 0xff) << 16) | (pd_idle & 0x1f)); + + clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL, + 0xfff << 16, + 5 << 16); + /* disable zqcs */ + setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31); + + return 0; +} + +/* + * calculate controller dram address map, and setting to register. + * argument sdram_params->ch.ddrconf must be right value before + * call this function. + */ +static void set_ctl_address_map(struct dram_info *dram, + struct px30_sdram_params *sdram_params) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + void __iomem *pctl_base = dram->pctl; + u32 cs_pst, bg, max_row, ddrconf; + u32 i; + + if (sdram_params->base.dramtype == DDR4) + /* + * DDR4 8bit dram BG = 2(4bank groups), + * 16bit dram BG = 1 (2 bank groups) + */ + bg = (cap_info->dbw == 0) ? 2 : 1; + else + bg = 0; + + cs_pst = cap_info->bw + cap_info->col + + bg + cap_info->bk + cap_info->cs0_row; + if (cs_pst >= 32 || cap_info->rank == 1) + writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0); + else + writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0); + + ddrconf = cap_info->ddrconfig; + if (sdram_params->base.dramtype == DDR4) { + for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) { + if (d4_rbc_2_d3_rbc[i] == ddrconf) { + ddrconf = 7 + i; + break; + } + } + } + + sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1), + &addrmap[ddrconf][0], 8 * 4); + max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf); + + if (max_row < 12) + printascii("set addrmap fail\n"); + /* need to disable row ahead of rank by set to 0xf */ + for (i = 17; i > max_row; i--) + clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 + + ((i - 12) * 8 / 32) * 4, + 0xf << ((i - 12) * 8 % 32), + 0xf << ((i - 12) * 8 % 32)); + + if ((sdram_params->base.dramtype == LPDDR3 || + sdram_params->base.dramtype == LPDDR2) && + cap_info->row_3_4) + setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31); + if (sdram_params->base.dramtype == DDR4 && cap_info->bw != 0x2) + setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8); +} + +/* + * rank = 1: cs0 + * rank = 2: cs1 + */ +int read_mr(struct dram_info *dram, u32 rank, u32 mr_num) +{ + void __iomem *ddr_grf_base = dram->ddr_grf; + + pctl_read_mr(dram->pctl, rank, mr_num); + + return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff); +} + +#define MIN(a, b) (((a) > (b)) ? (b) : (a)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +static u32 check_rd_gate(struct dram_info *dram) +{ + void __iomem *phy_base = dram->phy; + + u32 max_val = 0; + u32 min_val = 0xff; + u32 gate[4]; + u32 i, bw; + + bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf; + switch (bw) { + case 0x1: + bw = 1; + break; + case 0x3: + bw = 2; + break; + case 0xf: + default: + bw = 4; + break; + } + + for (i = 0; i < bw; i++) { + gate[i] = readl(PHY_REG(phy_base, 0xfb + i)); + max_val = MAX(max_val, gate[i]); + min_val = MIN(min_val, gate[i]); + } + + if (max_val > 0x80 || min_val < 0x20) + return -1; + else + return 0; +} + +static int data_training(struct dram_info *dram, u32 cs, u32 dramtype) +{ + void __iomem *pctl_base = dram->pctl; + u32 dis_auto_zq = 0; + u32 pwrctl; + u32 ret; + + /* disable auto low-power */ + pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL); + writel(0, pctl_base + DDR_PCTL2_PWRCTL); + + dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl); + + ret = phy_data_training(dram->phy, cs, dramtype); + + pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq); + + /* restore auto low-power */ + writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL); + + return ret; +} + +static void dram_set_bw(struct dram_info *dram, u32 bw) +{ + phy_dram_set_bw(dram->phy, bw); +} + +static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig) +{ + writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf); + rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14); +} + +static void dram_all_config(struct dram_info *dram, + struct px30_sdram_params *sdram_params) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + u32 sys_reg2 = 0; + u32 sys_reg3 = 0; + + set_ddrconfig(dram, cap_info->ddrconfig); + sdram_org_config(cap_info, &sdram_params->base, &sys_reg2, + &sys_reg3, 0); + writel(sys_reg2, &dram->pmugrf->os_reg[2]); + writel(sys_reg3, &dram->pmugrf->os_reg[3]); + sdram_msch_config(dram->msch, &sdram_params->ch.noc_timings, cap_info, + &sdram_params->base); +} + +static void enable_low_power(struct dram_info *dram, + struct px30_sdram_params *sdram_params) +{ + void __iomem *pctl_base = dram->pctl; + void __iomem *phy_base = dram->phy; + void __iomem *ddr_grf_base = dram->ddr_grf; + u32 grf_lp_con; + + /* + * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating + * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access + * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating + * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr + * bit4: grf_upctl_syscreq_cg_en = 1 + * ungating coreclk when c_sysreq assert + * bit8-11: grf_auto_sr_dly = 6 + */ + writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]); + + if (sdram_params->base.dramtype == DDR4) + grf_lp_con = (0x7 << 16) | (1 << 1); + else if (sdram_params->base.dramtype == DDR3) + grf_lp_con = (0x7 << 16) | (1 << 0); + else + grf_lp_con = (0x7 << 16) | (1 << 2); + + /* en lpckdis_en */ + grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9); + writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON); + + /* off digit module clock when enter power down */ + setbits_le32(PHY_REG(phy_base, 7), 1 << 7); + + /* enable sr, pd */ + if (PD_IDLE == 0) + clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); + else + setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); + if (SR_IDLE == 0) + clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); + else + setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); + setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3)); +} + +/* + * pre_init: 0: pre init for dram cap detect + * 1: detect correct cap(except cs1 row)info, than reinit + * 2: after reinit, we detect cs1_row, if cs1_row not equal + * to cs0_row and cs is in middle on ddrconf map, we need + * to reinit dram, than set the correct ddrconf. + */ +static int sdram_init_(struct dram_info *dram, + struct px30_sdram_params *sdram_params, u32 pre_init) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + void __iomem *pctl_base = dram->pctl; + + rkclk_ddr_reset(dram, 1, 1, 1, 1); + rockchip_udelay(10); + /* + * dereset ddr phy psrstn to config pll, + * if using phy pll psrstn must be dereset + * before config pll + */ + rkclk_ddr_reset(dram, 1, 1, 1, 0); + rkclk_configure_ddr(dram, sdram_params); + + /* release phy srst to provide clk to ctrl */ + rkclk_ddr_reset(dram, 1, 1, 0, 0); + rockchip_udelay(10); + phy_soft_reset(dram->phy); + + /* release ctrl presetn, and config ctl registers */ + rkclk_ddr_reset(dram, 1, 0, 0, 0); + pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE); + cap_info->ddrconfig = calculate_ddrconfig(sdram_params); + set_ctl_address_map(dram, sdram_params); + phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew, + &sdram_params->base, cap_info->bw); + + /* enable dfi_init_start to init phy after ctl srstn deassert */ + setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4)); + + rkclk_ddr_reset(dram, 0, 0, 0, 0); + /* wait for dfi_init_done and dram init complete */ + while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0) + continue; + + if (sdram_params->base.dramtype == LPDDR3) + pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3); + + /* do ddr gate training */ +redo_cs0_training: + if (data_training(dram, 0, sdram_params->base.dramtype) != 0) { + if (pre_init != 0) + printascii("DTT cs0 error\n"); + return -1; + } + if (check_rd_gate(dram)) { + printascii("re training cs0"); + goto redo_cs0_training; + } + + if (sdram_params->base.dramtype == LPDDR3) { + if ((read_mr(dram, 1, 8) & 0x3) != 0x3) + return -1; + } else if (sdram_params->base.dramtype == LPDDR2) { + if ((read_mr(dram, 1, 8) & 0x3) != 0x0) + return -1; + } + + /* for px30: when 2cs, both 2 cs should be training */ + if (pre_init != 0 && cap_info->rank == 2) { +redo_cs1_training: + if (data_training(dram, 1, sdram_params->base.dramtype) != 0) { + printascii("DTT cs1 error\n"); + return -1; + } + if (check_rd_gate(dram)) { + printascii("re training cs1"); + goto redo_cs1_training; + } + } + + if (sdram_params->base.dramtype == DDR4) + pctl_write_vrefdq(dram->pctl, 0x3, 5670, + sdram_params->base.dramtype); + + dram_all_config(dram, sdram_params); + enable_low_power(dram, sdram_params); + + return 0; +} + +static int dram_detect_cap(struct dram_info *dram, + struct px30_sdram_params *sdram_params, + unsigned char channel) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + + /* + * for ddr3: ddrconf = 3 + * for ddr4: ddrconf = 12 + * for lpddr3: ddrconf = 3 + * default bw = 1 + */ + u32 bk, bktmp; + u32 col, coltmp; + u32 rowtmp; + u32 cs; + u32 bw = 1; + u32 dram_type = sdram_params->base.dramtype; + + if (dram_type != DDR4) { + /* detect col and bk for ddr3/lpddr3 */ + coltmp = 12; + bktmp = 3; + if (dram_type == LPDDR2) + rowtmp = 15; + else + rowtmp = 16; + + if (sdram_detect_col(cap_info, coltmp) != 0) + goto cap_err; + sdram_detect_bank(cap_info, coltmp, bktmp); + sdram_detect_dbw(cap_info, dram_type); + } else { + /* detect bg for ddr4 */ + coltmp = 10; + bktmp = 4; + rowtmp = 17; + + col = 10; + bk = 2; + cap_info->col = col; + cap_info->bk = bk; + sdram_detect_bg(cap_info, coltmp); + } + + /* detect row */ + if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0) + goto cap_err; + + /* detect row_3_4 */ + sdram_detect_row_3_4(cap_info, coltmp, bktmp); + + /* bw and cs detect using data training */ + if (data_training(dram, 1, dram_type) == 0) + cs = 1; + else + cs = 0; + cap_info->rank = cs + 1; + + dram_set_bw(dram, 2); + if (data_training(dram, 0, dram_type) == 0) + bw = 2; + else + bw = 1; + cap_info->bw = bw; + + cap_info->cs0_high16bit_row = cap_info->cs0_row; + if (cs) { + cap_info->cs1_row = cap_info->cs0_row; + cap_info->cs1_high16bit_row = cap_info->cs0_row; + } else { + cap_info->cs1_row = 0; + cap_info->cs1_high16bit_row = 0; + } + + return 0; +cap_err: + return -1; +} + +static int sdram_init_detect(struct dram_info *dram, + struct px30_sdram_params *sdram_params) +{ + struct px30_sdram_channel *cap_info = &sdram_params->ch; + u32 ret; + u32 sys_reg = 0; + u32 sys_reg3 = 0; + + if (sdram_init_(dram, sdram_params, 0) != 0) + return -1; + + if (dram_detect_cap(dram, sdram_params, 0) != 0) + return -1; + + /* modify bw, cs related timing */ + pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info, + sdram_params->base.dramtype); + /* reinit sdram by real dram cap */ + ret = sdram_init_(dram, sdram_params, 1); + if (ret != 0) + goto out; + + /* redetect cs1 row */ + sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype); + if (cap_info->cs1_row) { + sys_reg = readl(&dram->pmugrf->os_reg[2]); + sys_reg3 = readl(&dram->pmugrf->os_reg[3]); + writel(sys_reg, &dram->pmugrf->os_reg[2]); + writel(sys_reg3, &dram->pmugrf->os_reg[3]); + } + + ret = sdram_detect_high_row(cap_info); + +out: + return ret; +} + +struct px30_sdram_params *get_default_sdram_config(void) +{ + sdram_configs[0].skew = &skew; + + return &sdram_configs[0]; +} + +int sdram_init(void) +{ + struct px30_sdram_params *sdram_params; + int ret = 0; + + dram_info.phy = (void *)DDR_PHY_BASE_ADDR; + dram_info.pctl = (void *)DDRC_BASE_ADDR; + dram_info.grf = (void *)GRF_BASE_ADDR; + dram_info.cru = (void *)CRU_BASE_ADDR; + dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR; + dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR; + dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR; + + sdram_params = get_default_sdram_config(); + ret = sdram_init_detect(&dram_info, sdram_params); + if (ret) + return ret; + + return ret; +} +#endif /* CONFIG_TPL_BUILD */ diff --git a/arch/arm/mach-rockchip/px30/syscon_px30.c b/arch/arm/mach-rockchip/px30/syscon_px30.c new file mode 100644 index 0000000000..0331491b40 --- /dev/null +++ b/arch/arm/mach-rockchip/px30/syscon_px30.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch-rockchip/clock.h> + +static const struct udevice_id px30_syscon_ids[] = { + { .compatible = "rockchip,px30-pmu", .data = ROCKCHIP_SYSCON_PMU }, + { .compatible = "rockchip,px30-pmugrf", .data = ROCKCHIP_SYSCON_PMUGRF }, + { .compatible = "rockchip,px30-grf", .data = ROCKCHIP_SYSCON_GRF }, + { } +}; + +U_BOOT_DRIVER(syscon_px30) = { + .id = UCLASS_SYSCON, + .name = "px30_syscon", + .of_match = px30_syscon_ids, +}; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int px30_syscon_bind_of_platdata(struct udevice *dev) +{ + dev->driver_data = dev->driver->of_match->data; + debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data); + + return 0; +} + +U_BOOT_DRIVER(rockchip_px30_pmu) = { + .name = "rockchip_px30_pmu", + .id = UCLASS_SYSCON, + .of_match = px30_syscon_ids, + .bind = px30_syscon_bind_of_platdata, +}; + +U_BOOT_DRIVER(rockchip_px30_pmugrf) = { + .name = "rockchip_px30_pmugrf", + .id = UCLASS_SYSCON, + .of_match = px30_syscon_ids + 1, + .bind = px30_syscon_bind_of_platdata, +}; + +U_BOOT_DRIVER(rockchip_px30_grf) = { + .name = "rockchip_px30_grf", + .id = UCLASS_SYSCON, + .of_match = px30_syscon_ids + 2, + .bind = px30_syscon_bind_of_platdata, +}; +#endif -- 2.23.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot