From mboxrd@z Thu Jan 1 00:00:00 1970 From: Simon Glass Date: Fri, 13 Nov 2015 11:13:43 -0700 Subject: [U-Boot] [PATCH v5 16/21] rockchip: add rk3036 sdram driver In-Reply-To: <1447151098-2628-17-git-send-email-hl@rock-chips.com> References: <1447151098-2628-1-git-send-email-hl@rock-chips.com> <1447151098-2628-17-git-send-email-hl@rock-chips.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Lin, On 10 November 2015 at 03:24, Lin Huang wrote: > add rk3036 sdram driver so we can set up sdram in SPL > > Signed-off-by: Lin Huang > --- > Changes in v1: None > Changes in v2: None > Changes in v3: > - fix some code style error > Changes in v4: > - modify code advice by Simon Glass > Changes in v5: > - Advice by Simon: > - move some global variables to local variables > - delete __weak get_ddr_config() function > > arch/arm/include/asm/arch-rockchip/sdram_rk3036.h | 341 ++++++++++ > arch/arm/mach-rockchip/rk3036/Makefile | 2 + > arch/arm/mach-rockchip/rk3036/sdram_rk3036.c | 766 ++++++++++++++++++++++ > 3 files changed, 1109 insertions(+) > create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3036.h > create mode 100644 arch/arm/mach-rockchip/rk3036/sdram_rk3036.c > This looks good but a few things remain so I think it needs another pass. > diff --git a/arch/arm/include/asm/arch-rockchip/sdram_rk3036.h b/arch/arm/include/asm/arch-rockchip/sdram_rk3036.h > new file mode 100644 > index 0000000..4ce2ba5 > --- /dev/null > +++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3036.h > @@ -0,0 +1,341 @@ > +/* > + * (C) Copyright 2015 Rockchip Electronics Co., Ltd > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef _ASM_ARCH_SDRAM_RK3036_H > +#define _ASM_ARCH_SDRAM_RK3036_H > + > +#include > + > +struct rk3036_ddr_pctl { > + u32 scfg; > + u32 sctl; > + u32 stat; > + u32 intrstat; > + u32 reserved0[12]; > + u32 mcmd; > + u32 powctl; > + u32 powstat; > + u32 cmdtstat; > + u32 cmdtstaten; > + u32 reserved1[3]; > + u32 mrrcfg0; > + u32 mrrstat0; > + u32 mrrstat1; > + u32 reserved2[4]; > + u32 mcfg1; > + u32 mcfg; > + u32 ppcfg; > + u32 mstat; > + u32 lpddr2zqcfg; > + u32 reserved3; > + u32 dtupdes; > + u32 dtuna; > + u32 dtune; > + u32 dtuprd0; > + u32 dtuprd1; > + u32 dtuprd2; > + u32 dtuprd3; > + u32 dtuawdt; > + u32 reserved4[3]; > + u32 togcnt1u; > + u32 tinit; > + u32 trsth; > + u32 togcnt100n; > + u32 trefi; > + u32 tmrd; > + u32 trfc; > + u32 trp; > + u32 trtw; > + u32 tal; > + u32 tcl; > + u32 tcwl; > + u32 tras; > + u32 trc; > + u32 trcd; > + u32 trrd; > + u32 trtp; > + u32 twr; > + u32 twtr; > + u32 texsr; > + u32 txp; > + u32 txpdll; > + u32 tzqcs; > + u32 tzqcsi; > + u32 tdqs; > + u32 tcksre; > + u32 tcksrx; > + u32 tcke; > + u32 tmod; > + u32 trstl; > + u32 tzqcl; > + u32 tmrr; > + u32 tckesr; > + u32 reserved5[47]; > + u32 dtuwactl; > + u32 dturactl; > + u32 dtucfg; > + u32 dtuectl; > + u32 dtuwd0; > + u32 dtuwd1; > + u32 dtuwd2; > + u32 dtuwd3; > + u32 dtuwdm; > + u32 dturd0; > + u32 dturd1; > + u32 dturd2; > + u32 dturd3; > + u32 dtulfsrwd; > + u32 dtulfsrrd; > + u32 dtueaf; > + u32 dfitctrldelay; > + u32 dfiodtcfg; > + u32 dfiodtcfg1; > + u32 dfiodtrankmap; > + u32 dfitphywrdata; > + u32 dfitphywrlat; > + u32 reserved7[2]; > + u32 dfitrddataen; > + u32 dfitphyrdlat; > + u32 reserved8[2]; > + u32 dfitphyupdtype0; > + u32 dfitphyupdtype1; > + u32 dfitphyupdtype2; > + u32 dfitphyupdtype3; > + u32 dfitctrlupdmin; > + u32 dfitctrlupdmax; > + u32 dfitctrlupddly; > + u32 reserved9; > + u32 dfiupdcfg; > + u32 dfitrefmski; > + u32 dfitctrlupdi; > + u32 reserved10[4]; > + u32 dfitrcfg0; > + u32 dfitrstat0; > + u32 dfitrwrlvlen; > + u32 dfitrrdlvlen; > + u32 dfitrrdlvlgateen; > + u32 dfiststat0; > + u32 dfistcfg0; > + u32 dfistcfg1; > + u32 reserved11; > + u32 dfitdramclken; > + u32 dfitdramclkdis; > + u32 dfistcfg2; > + u32 dfistparclr; > + u32 dfistparlog; > + u32 reserved12[3]; > + u32 dfilpcfg0; > + u32 reserved13[3]; > + u32 dfitrwrlvlresp0; > + u32 dfitrwrlvlresp1; > + u32 dfitrwrlvlresp2; > + u32 dfitrrdlvlresp0; > + u32 dfitrrdlvlresp1; > + u32 dfitrrdlvlresp2; > + u32 dfitrwrlvldelay0; > + u32 dfitrwrlvldelay1; > + u32 dfitrwrlvldelay2; > + u32 dfitrrdlvldelay0; > + u32 dfitrrdlvldelay1; > + u32 dfitrrdlvldelay2; > + u32 dfitrrdlvlgatedelay0; > + u32 dfitrrdlvlgatedelay1; > + u32 dfitrrdlvlgatedelay2; > + u32 dfitrcmd; > + u32 reserved14[46]; > + u32 ipvr; > + u32 iptr; > +}; > +check_member(rk3036_ddr_pctl, iptr, 0x03fc); > + > +struct rk3036_ddr_phy { > + u32 ddrphy_reg1; > + u32 ddrphy_reg3; > + u32 ddrphy_reg2; > + u32 reserve[11]; > + u32 ddrphy_reg4a; > + u32 ddrphy_reg4b; > + u32 reserve1[5]; > + u32 ddrphy_reg16; > + u32 reserve2; > + u32 ddrphy_reg18; > + u32 ddrphy_reg19; > + u32 reserve3; > + u32 ddrphy_reg21; > + u32 reserve4; > + u32 ddrphy_reg22; > + u32 reserve5[3]; > + u32 ddrphy_reg25; > + u32 ddrphy_reg26; > + u32 ddrphy_reg27; > + u32 ddrphy_reg28; > + u32 reserve6[17]; > + u32 ddrphy_reg6; > + u32 ddrphy_reg7; > + u32 reserve7; > + u32 ddrphy_reg8; > + u32 ddrphy_reg0e4; > + u32 reserve8[11]; > + u32 ddrphy_reg9; > + u32 ddrphy_reg10; > + u32 reserve9; > + u32 ddrphy_reg11; > + u32 ddrphy_reg124; > + u32 reserve10[38]; > + u32 ddrphy_reg29; > + u32 reserve11[40]; > + u32 ddrphy_reg264; > + u32 reserve12[18]; > + u32 ddrphy_reg2a; > + u32 reserve13[4]; > + u32 ddrphy_reg30; > + u32 ddrphy_reg31; > + u32 ddrphy_reg32; > + u32 ddrphy_reg33; > + u32 ddrphy_reg34; > + u32 ddrphy_reg35; > + u32 ddrphy_reg36; > + u32 ddrphy_reg37; > + u32 ddrphy_reg38; > + u32 ddrphy_reg39; > + u32 ddrphy_reg40; > + u32 ddrphy_reg41; > + u32 ddrphy_reg42; > + u32 ddrphy_reg43; > + u32 ddrphy_reg44; > + u32 ddrphy_reg45; > + u32 ddrphy_reg46; > + u32 ddrphy_reg47; > + u32 ddrphy_reg48; > + u32 ddrphy_reg49; > + u32 ddrphy_reg50; > + u32 ddrphy_reg51; > + u32 ddrphy_reg52; > + u32 ddrphy_reg53; > + u32 reserve14; > + u32 ddrphy_reg54; > + u32 ddrphy_reg55; > + u32 ddrphy_reg56; > + u32 ddrphy_reg57; > + u32 ddrphy_reg58; > + u32 ddrphy_reg59; > + u32 ddrphy_reg5a; > + u32 ddrphy_reg5b; > + u32 ddrphy_reg5c; > + u32 ddrphy_reg5d; > + u32 ddrphy_reg5e; > + u32 reserve15[28]; > + u32 ddrphy_reg5f; > + u32 reserve16[6]; > + u32 ddrphy_reg60; > + u32 ddrphy_reg61; > + u32 ddrphy_reg62; > +}; > +check_member(rk3036_ddr_phy, ddrphy_reg62, 0x03e8); > + > +struct rk3036_pctl_timing { > + u32 togcnt1u; > + u32 tinit; > + u32 trsth; > + u32 togcnt100n; > + u32 trefi; > + u32 tmrd; > + u32 trfc; > + u32 trp; > + u32 trtw; > + u32 tal; > + u32 tcl; > + u32 tcwl; > + u32 tras; > + u32 trc; > + u32 trcd; > + u32 trrd; > + u32 trtp; > + u32 twr; > + u32 twtr; > + u32 texsr; > + u32 txp; > + u32 txpdll; > + u32 tzqcs; > + u32 tzqcsi; > + u32 tdqs; > + u32 tcksre; > + u32 tcksrx; > + u32 tcke; > + u32 tmod; > + u32 trstl; > + u32 tzqcl; > + u32 tmrr; > + u32 tckesr; > + u32 tdpd; > +}; > + > +struct rk3036_phy_timing { > + u32 mr[4]; > + u32 bl; > + u32 cl_al; > +}; > + > +typedef union { > + u32 noc_timing; > + struct { > + u32 acttoact:6; > + u32 rdtomiss:6; > + u32 wrtomiss:6; > + u32 burstlen:3; > + u32 rdtowr:5; > + u32 wrtord:5; > + u32 bwratio:1; > + }; > +} rk3036_noc_timing; > + > +struct rk3036_ddr_timing { > + u32 freq; > + struct rk3036_pctl_timing pctl_timing; > + struct rk3036_phy_timing phy_timing; > + rk3036_noc_timing noc_timing; > +}; > + > +struct rk3036_service_sys { > + u32 id_coreid; > + u32 id_revisionid; > + u32 ddrconf; > + u32 ddrtiming; > + u32 ddrmode; > + u32 readlatency; > +}; > + > +struct rk3036_ddr_config { > + /* > + * 000: lpddr > + * 001: ddr > + * 010: ddr2 > + * 011: ddr3 > + * 100: lpddr2-s2 > + * 101: lpddr2-s4 > + * 110: lpddr3 > + */ > + u32 ddr_type; > + u32 rank; > + u32 cs0_row; > + u32 cs1_row; > + > + /* 2: 4bank, 3: 8bank */ > + u32 bank; > + u32 col; > + > + /* bw(0: 8bit, 1: 16bit, 2: 32bit) */ > + u32 bw; > +}; > + > +/* rk3036 sdram initial */ > +void sdram_init(void); > + > +/* get ddr die config, implement in specific board */ > +void get_ddr_config(struct rk3036_ddr_config *config); > + > +/* get ddr size on board */ > +size_t sdram_size(void); > +#endif > diff --git a/arch/arm/mach-rockchip/rk3036/Makefile b/arch/arm/mach-rockchip/rk3036/Makefile > index 5d14b95..6095777 100644 > --- a/arch/arm/mach-rockchip/rk3036/Makefile > +++ b/arch/arm/mach-rockchip/rk3036/Makefile > @@ -8,3 +8,5 @@ ifndef CONFIG_SPL_BUILD > obj-y += reset_rk3036.o > obj-y += syscon_rk3036.o > endif > + > +obj-y += sdram_rk3036.o > diff --git a/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c b/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c > new file mode 100644 > index 0000000..6fcb03e > --- /dev/null > +++ b/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c > @@ -0,0 +1,766 @@ > +/* > + * (C) Copyright 2015 Google, Inc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + Please add a comment that we cannot fit the code to access the device tree in SPL for this chip (due to SRAM size limits), so these are hard-coded here. > +#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 interge mode, 396M dpll setting > + * refdiv, fbdiv, postdiv1, postdiv2 > + */ > +const struct pll_div dpll_init_cfg = {1, 66, 4, 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) > + */ > +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) Should pass the pointer: struct rk3036_sdram_priv *priv Please fix throughout. > +{ > + 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 interger 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); Shouldn't this be: rk_setreg(..., 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT | > + 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT); > + rockchip_udelay(10); > + > + 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 | > + 0 << DDRPHY_PSRST_SHIFT | 0 << DDRPHY_SRST_SHIFT); Can it be: rk_clrreg(..., 0 << DDRPHY_PSRST_SHIFT | 0 << DDRPHY_SRST_SHIFT); Please check others also. > + rockchip_udelay(10); > + > + rk_clrsetreg(&priv.cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | > + 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT | > + 1 << DDRPHY_SRST_SHIFT, > + 0 << DDRCTRL_PSRST_SHIFT | 0 << DDRCTRL_SRST_SHIFT | > + 0 << DDRPHY_PSRST_SHIFT | 0 << DDRPHY_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 /* * If at low power... '> + * 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; Please use a pointer instead of copying the structure. 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); > + > + return; > +} > + > +static void sdram_all_config(struct rk3036_sdram_priv priv) > +{ > + u32 os_reg = 0; > + struct rk3036_ddr_config config = priv.ddr_config; > + > + 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 | > + (config.cs1_row - 13) << 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); sdram_all_config(&sdram_priv); Same with the others > + 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); > +} > -- > 1.9.1 > Regards, Simon