
Hi Simon,
On 07/11/15 07:58, Simon Glass wrote:
Hi Lin,
On 6 November 2015 at 01:53, Lin Huang hl@rock-chips.com wrote:
add rk3036 sdram driver so we can set up sdram in SPL
Signed-off-by: Lin Huang hl@rock-chips.com
Changes in v1: None Changes in v2: None Changes in v3: fix some code style error
arch/arm/include/asm/arch-rockchip/sdram_rk3036.h | 336 ++++++++++ arch/arm/mach-rockchip/rk3036/Makefile | 2 + arch/arm/mach-rockchip/rk3036/sdram_rk3036.c | 729 ++++++++++++++++++++++ 3 files changed, 1067 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_rk3036.h create mode 100644 arch/arm/mach-rockchip/rk3036/sdram_rk3036.c
Just a few nits.
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..76c8b5b --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/sdram_rk3036.h @@ -0,0 +1,336 @@ +/*
- (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 <common.h>
+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;
+};
+void sdram_init(void); +void get_ddr_config(struct rk3036_ddr_config *config); +size_t sdram_size(void);
Can you add function comments for these?
Ok, will be done in next version
+#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..0327f18 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3036/sdram_rk3036.c @@ -0,0 +1,729 @@ +/*
- (C) Copyright 2015 Google, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/arch/cru_rk3036.h> +#include <asm/arch/grf_rk3036.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sdram_rk3036.h> +#include <asm/arch/timer.h> +#include <asm/arch/uart.h> +#include <asm/io.h> +#include <asm/types.h> +#include <common.h>
common.h should go first then <asm/...> then <asm/arch/...>
Got it, thank you
+#define CRU_BASE 0x20000000 +static struct rk3036_cru * const cru = (void *)CRU_BASE;
+#define GRF_BASE 0x20008000 +static struct rk3036_grf * const grf = (void *)GRF_BASE;
+#define DDR_PHY_BASE 0x2000a000 +static struct rk3036_ddr_phy * const ddr_phy = (void *)DDR_PHY_BASE;
+#define DDR_PCTL_BASE 0x20004000 +static struct rk3036_ddr_pctl * const pctl = (void *)DDR_PCTL_BASE;
+#define CPU_AXI_BUS_BASE 0x10128000 +static struct rk3036_service_sys * const axi_bus = (void *)CPU_AXI_BUS_BASE;
Can you just make these local variables?
Okay, will be done next version.
+/* use interge mode, 396M dpll setting
- refdiv, fbdiv, postdiv1, postdiv2
- */
+static const struct pll_div dpll_init_cfg = {1, 66, 4, 1};
+/* 396Mhz ddr timing */ +struct rk3036_ddr_timing ddr_timing = {0x18c,
const?
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};
+/* ddr die config */ +static struct rk3036_ddr_config ddr_config;
Why is this static? Can it just be a local variable in the function?
+/*
- [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
() around that. Also can you remove extra space after #define?
Got it.
+#define PHY_RON_DISABLE 0 +#define PHY_RON_309OHM 1 +#define PHY_RON_155OHM 2 +#define PHY_RON_103OHM 3 +#define PHY_RON_63OHM 5 +#define PHY_RON_45OHM 7 +#define PHY_RON_77OHM 8 +#define PHY_RON_62OHM 9 +#define PHY_RON_52OHM 0xa +#define PHY_RON_44OHM 0xb +#define PHY_RON_39OHM 0xc +#define PHY_RON_34OHM 0xd +#define PHY_RON_31OHM 0xe +#define PHY_RON_28OHM 0xf
+#define PHY_RTT_DISABLE 0 +#define PHY_RTT_861OHM 1 +#define PHY_RTT_431OHM 2 +#define PHY_RTT_287OHM 3 +#define PHY_RTT_216OHM 4 +#define PHY_RTT_172OHM 5 +#define PHY_RTT_145OHM 6 +#define PHY_RTT_124OHM 7 +#define PHY_RTT_215OHM 8 +#define PHY_RTT_144OHM 0xa +#define PHY_RTT_123OHM 0xb +#define PHY_RTT_108OHM 0xc +#define PHY_RTT_96OHM 0xd +#define PHY_RTT_86OHM 0xe +#define PHY_RTT_78OHM 0xf
How about using enum for these?
Okay, will be done next version
+#define PHY_DRV_ODT_SET(n) ((n << 4) | n)
+#define DDR3_DLL_RESET (1 << 8)
+/* 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(void) +{
struct rk3036_pll *pll = &cru->pll[1];
/* pll enter slow-mode */
rk_clrsetreg(&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(&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(void) +{
rk_clrsetreg(&cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT,
1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
rockchip_udelay(10);
rk_clrsetreg(&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);
rockchip_udelay(10);
rk_clrsetreg(&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(unsigned int freq) +{
if (freq < ddr_timing.freq) {
writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS |
LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a);
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);
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(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);
Is this the same as the ddrphy_reg19 line above?
Oh, yes, you are right, will move together next version
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);
}
/* 45 degree delay */
writel((2 & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) <<
2 should be in an enum
Okay
LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8);
writel((2 & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) <<
RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11);
+}
+static void send_command(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(void) +{
send_command(3, DESELECT_CMD, 0);
rockchip_udelay(1);
send_command(3, PREA_CMD, 0);
send_command(3, MRS_CMD, (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(3, MRS_CMD, (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(3, MRS_CMD, (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
(ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) <<
CMD_ADDR_SHIFT);
send_command(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);
The order is strange here - 2, 3, 1, 0. Then you do a RESET.
Is it possible to put this in a for() loop?
send_command(3, ZQCL_CMD, 0);
+}
+static void data_training(void) +{
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(10);
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);
send_command(3, REF_CMD, 0);
send_command(3, REF_CMD, 0);
send_command(3, REF_CMD, 0);
writel(value, &pctl->trefi);
+}
+static void move_to_config_state(void) +{
unsigned int state;
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,
/*
- If at ...
Also please try to wrap the comments to the full width (e.g. 75-78 chars).
Okay , thank you
* and then enter the config
* so fallthrough.
*/
case ACCESS:
/* fallthrough */
case INIT_MEM:
writel(CFG_STATE, &pctl->sctl);
while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
;
break;
Drop blank line
Got it.
case CONFIG:
return;
default:
break;
}
}
+}
+static void move_to_access_state(void) +{
unsigned int state;
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(void) +{
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), &grf->soc_con2);
setbits_le32(&pctl->scfg, HW_LOW_POWER_EN);
+}
+static void phy_cfg(void) +{
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(void) +{
char noc_config;
int i = 0;
move_to_config_state();
/* 2bit in BIT1, 2 */
if (ddr_config.rank == 2) {
noc_config = (ddr_config.cs0_row - 13) << 4 |
ddr_config.bank << 1 |
1 << 3 | (ddr_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 = (ddr_config.cs0_row - 13) << 4 | ddr_config.bank << 1 |
(ddr_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 | (ddr_config.cs0_row - 13) << 4 |
2 << 1 | (ddr_config.col - 10);
if (noc_config == ddr_cfg_2_rbc[11]) {
i = 11;
goto finish;
}
/* bank: 2bit in BIT6,7 */
noc_config = (ddr_config.bank << 6) | (ddr_config.cs0_row - 13) << 4 |
(ddr_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();
return;
+}
+static void sdram_all_config(void) +{
u32 os_reg = 0;
os_reg = ddr_config.ddr_type << DDR_TYPE_SHIFT |
0 << DDR_CHN_CNT_SHIFT |
(ddr_config.rank - 1) << DDR_RANK_CNT_SHIFT |
(ddr_config.col - 1) << DDR_COL_SHIFT |
(ddr_config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT |
(ddr_config.cs0_row - 13) << DDR_CS0_ROW_SHIFT |
(ddr_config.cs1_row - 13) << DDR_CS1_ROW_SHIFT |
1 << DDR_BW_SHIFT | ddr_config.bw << DDR_DIE_BW_SHIFT;
writel(os_reg, &grf->os_reg[1]);
+}
+size_t sdram_size(void) +{
u32 size, os_reg, cs0_row, cs1_row, col, bank, rank;
os_reg = readl(&grf->os_reg[1]);
print_hex(os_reg);
Do you want this? What is the purpose?
Oh, careless, sorry.
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;
+}
+__weak void get_ddr_config(struct rk3036_ddr_config *config) +{ +}
+void sdram_init(void) +{
get_ddr_config(&ddr_config);
sdram_all_config();
rkdclk_init();
phy_pctrl_reset();
phy_dll_bypass_set(ddr_timing.freq);
pctl_cfg();
phy_cfg();
writel(POWER_UP_START, &pctl->powctl);
while (!(readl(&pctl->powstat) & POWER_UP_DONE))
;
memory_init();
move_to_config_state();
data_training();
move_to_access_state();
dram_cfg_rbc();
This looks good and very clear, thank you.
Thank you for your review, i will rework it.
+}
1.9.1
Regards, Simon