[U-Boot] [PATCH v5 16/21] rockchip: add rk3036 sdram driver
Ben Chan
benchan at chromium.org
Thu Nov 12 09:35:26 CET 2015
On Tue, Nov 10, 2015 at 2:24 AM, Lin Huang <hl at rock-chips.com> wrote:
> add rk3036 sdram driver so we can set up sdram in SPL
>
> Signed-off-by: Lin Huang <hl at rock-chips.com>
> ---
> 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
>
> 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 <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;
> +};
> +
> +/* 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 <common.h>
> +#include <asm/io.h>
> +#include <asm/types.h>
> +#include <asm/arch/cru_rk3036.h>
> +#include <asm/arch/grf_rk3036.h>
> +#include <asm/arch/hardware.h>
> +#include <asm/arch/sdram_rk3036.h>
> +#include <asm/arch/timer.h>
> +#include <asm/arch/uart.h>
> +
> +#define CRU_BASE 0x20000000
> +#define GRF_BASE 0x20008000
> +#define DDR_PHY_BASE 0x2000a000
nit: for consistency, space after #define
> +#define DDR_PCTL_BASE 0x20004000
nit: for consistency, space after #define
> +#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
typo: interge -> integer
396M -> 396MHz?
> + * 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)
> + */
should probably mark ddr_cfg_2_rbc as a constant.
> +char ddr_cfg_2_rbc[] = {
> + ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 1),
> + ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 0),
> + ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 0),
> + ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 0),
> + ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 1),
> + ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 1),
> + ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 1),
> + ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 0),
> + ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 1),
> + ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 0),
> + ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 1),
> + ((1 << 6) | (2 << 4) | (0 << 3) | (2 << 1) | 0),
> + ((3 << 6) | (2 << 4) | (0 << 3) | (0 << 1) | 1),
> + ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 0),
> +};
> +
> +/* DDRPHY REG */
> +enum {
> + /* DDRPHY_REG1 */
> + SOFT_RESET_MASK = 3,
> + SOFT_RESET_SHIFT = 2,
> +
> + /* DDRPHY_REG2 */
> + MEMORY_SELECT_DDR3 = 0 << 6,
> + DQS_SQU_CAL_NORMAL_MODE = 0 << 1,
> + DQS_SQU_CAL_START = 1 << 0,
> + DQS_SQU_NO_CAL = 0 << 0,
> +
> + /* DDRPHY_REG2A */
> + CMD_DLL_BYPASS = 1 << 4,
> + CMD_DLL_BYPASS_DISABLE = 0 << 4,
> + HIGH_8BIT_DLL_BYPASS = 1 << 3,
> + HIGH_8BIT_DLL_BYPASS_DISABLE = 0 << 3,
> + LOW_8BIT_DLL_BYPASS = 1 << 2,
> + LOW_8BIT_DLL_BYPASS_DISABLE = 0 << 2,
> +
> + /* DDRPHY_REG19 */
> + CMD_FEEDBACK_ENABLE = 1 << 5,
> + CMD_SLAVE_DLL_INVERSE_MODE = 1 << 4,
> + CMD_SLAVE_DLL_NO_INVERSE_MODE = 0 << 4,
> + CMD_SLAVE_DLL_ENALBE = 1 << 3,
> + CMD_TX_SLAVE_DLL_DELAY_MASK = 7,
> + CMD_TX_SLAVE_DLL_DELAY_SHIFT = 0,
> +
> + /* DDRPHY_REG6 */
> + LEFT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4,
> + LEFT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4,
> + LEFT_CHN_TX_DQ_DLL_ENABLE = 1 << 3,
> + LEFT_CHN_TX_DQ_DLL_DELAY_MASK = 7,
> + LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0,
> +
> + /* DDRPHY_REG8 */
> + LEFT_CHN_RX_DQS_DELAY_TAP_MASK = 3,
> + LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0,
> +
> + /* DDRPHY_REG9 */
> + RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4,
> + RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4,
> + RIGHT_CHN_TX_DQ_DLL_ENABLE = 1 << 3,
> + RIGHT_CHN_TX_DQ_DLL_DELAY_MASK = 7,
> + RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0,
> +
> + /* DDRPHY_REG11 */
> + RIGHT_CHN_RX_DQS_DELAY_TAP_MASK = 3,
> + RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0,
> +
> + /* DDRPHY_REG62 */
> + CAL_DONE_MASK = 3,
> + HIGH_8BIT_CAL_DONE = 1 << 1,
> + LOW_8BIT_CAL_DONE = 1 << 0,
> +};
> +
> +/* PTCL */
> +enum {
> + /* PCTL_DFISTCFG0 */
> + DFI_INIT_START = 1 << 0,
> + DFI_DATA_BYTE_DISABLE_EN = 1 << 2,
> +
> + /* PCTL_DFISTCFG1 */
> + DFI_DRAM_CLK_SR_EN = 1 << 0,
> + DFI_DRAM_CLK_DPD_EN = 1 << 1,
> +
> + /* PCTL_DFISTCFG2 */
> + DFI_PARITY_INTR_EN = 1 << 0,
> + DFI_PARITY_EN = 1 << 1,
> +
> + /* PCTL_DFILPCFG0 */
> + TLP_RESP_TIME_SHIFT = 16,
> + LP_SR_EN = 1 << 8,
> + LP_PD_EN = 1 << 0,
> +
> + /* PCTL_DFIODTCFG */
> + RANK0_ODT_WRITE_SEL = 1 << 3,
> + RANK1_ODT_WRITE_SEL = 1 << 11,
> +
> + /* PCTL_DFIODTCFG1 */
> + ODT_LEN_BL8_W_SHIFT = 16,
> +
> + /* PCTL_MCFG */
> + TFAW_CFG_MASK = 3,
> + TFAW_CFG_SHIFT = 18,
> + PD_EXIT_SLOW_MODE = 0 << 17,
> + PD_ACTIVE_POWER_DOWN = 1 << 16,
> + PD_IDLE_MASK = 0xff,
> + PD_IDLE_SHIFT = 8,
> + MEM_BL4 = 0 << 0,
> + MEM_BL8 = 1 << 0,
> +
> + /* PCTL_MCFG1 */
> + HW_EXIT_IDLE_EN_MASK = 1,
> + HW_EXIT_IDLE_EN_SHIFT = 31,
> + SR_IDLE_MASK = 0x1ff,
> + SR_IDLE_SHIFT = 0,
> +
> + /* PCTL_SCFG */
> + HW_LOW_POWER_EN = 1 << 0,
> +
> + /* PCTL_POWCTL */
> + POWER_UP_START = 1 << 0,
> +
> + /* PCTL_POWSTAT */
> + POWER_UP_DONE = 1 << 0,
> +
> + /* PCTL_MCMD */
> + START_CMD = 1 << 31,
> + BANK_ADDR_MASK = 7,
> + BANK_ADDR_SHIFT = 17,
> + CMD_ADDR_MASK = 0x1fff,
> + CMD_ADDR_SHIFT = 4,
> + DESELECT_CMD = 0,
> + PREA_CMD,
> + REF_CMD,
> + MRS_CMD,
> + ZQCS_CMD,
> + ZQCL_CMD,
> + RSTL_CMD,
> + MRR_CMD = 8,
> +
> + /* PCTL_STAT */
> + INIT_MEM = 0,
> + CONFIG,
> + CONFIG_REQ,
> + ACCESS,
> + ACCESS_REQ,
> + LOW_POWER,
> + LOW_POWER_ENTRY_REQ,
> + LOW_POWER_EXIT_REQ,
> + PCTL_STAT_MASK = 7,
> +
> + /* PCTL_SCTL */
> + INIT_STATE = 0,
> + CFG_STATE = 1,
> + GO_STATE = 2,
> + SLEEP_STATE = 3,
> + WAKEUP_STATE = 4,
> +};
> +
> +/* GRF_SOC_CON2 */
> +#define MSCH4_MAINDDR3 (1 << 7)
> +#define PHY_DRV_ODT_SET(n) ((n << 4) | n)
> +#define DDR3_DLL_RESET (1 << 8)
> +
> +/* CK pull up/down driver strength control */
> +enum {
> + PHY_RON_DISABLE = 0,
> + PHY_RON_309OHM = 1,
> + PHY_RON_155OHM,
> + PHY_RON_103OHM = 3,
> + PHY_RON_63OHM = 5,
> + PHY_RON_45OHM = 7,
> + PHY_RON_77OHM,
> + PHY_RON_62OHM,
> + PHY_RON_52OHM,
> + PHY_RON_44OHM,
> + PHY_RON_39OHM,
> + PHY_RON_34OHM,
> + PHY_RON_31OHM,
> + PHY_RON_28OHM,
> +};
> +
> +/* DQ pull up/down control */
> +enum {
> + PHY_RTT_DISABLE = 0,
> + PHY_RTT_861OHM = 1,
> + PHY_RTT_431OHM,
> + PHY_RTT_287OHM,
> + PHY_RTT_216OHM,
> + PHY_RTT_172OHM,
> + PHY_RTT_145OHM,
> + PHY_RTT_124OHM,
> + PHY_RTT_215OHM,
> + PHY_RTT_144OHM = 0xa,
> + PHY_RTT_123OHM,
> + PHY_RTT_108OHM,
> + PHY_RTT_96OHM,
> + PHY_RTT_86OHM,
> + PHY_RTT_78OHM,
> +};
> +
> +/* DQS squelch DLL delay */
> +enum {
> + DQS_DLL_NO_DELAY = 0,
> + DQS_DLL_22P5_DELAY,
> + DQS_DLL_45_DELAY,
> + DQS_DLL_67P5_DELAY,
> + DQS_DLL_90_DELAY,
> + DQS_DLL_112P5_DELAY,
> + DQS_DLL_135_DELAY,
> + DQS_DLL_157P5_DELAY,
> +};
> +
> +/* GRF_OS_REG1 */
> +enum {
> + /*
> + * 000: lpddr
> + * 001: ddr
> + * 010: ddr2
> + * 011: ddr3
> + * 100: lpddr2-s2
> + * 101: lpddr2-s4
> + * 110: lpddr3
> + */
> + DDR_TYPE_MASK = 7,
> + DDR_TYPE_SHIFT = 13,
> +
> + /* 0: 1 chn, 1: 2 chn */
> + DDR_CHN_CNT_SHIFT = 12,
> +
> + /* 0: 1 rank, 1: 2 rank */
> + DDR_RANK_CNT_MASK = 1,
> + DDR_RANK_CNT_SHIFT = 11,
> +
> + /*
> + * 00: 9col
> + * 01: 10col
> + * 10: 11col
> + * 11: 12col
> + */
> + DDR_COL_MASK = 3,
> + DDR_COL_SHIFT = 9,
> +
> + /* 0: 8 bank, 1: 4 bank*/
> + DDR_BANK_MASK = 1,
> + DDR_BANK_SHIFT = 8,
> +
> + /*
> + * 00: 13 row
> + * 01: 14 row
> + * 10: 15 row
> + * 11: 16 row
> + */
> + DDR_CS0_ROW_MASK = 3,
> + DDR_CS0_ROW_SHIFT = 6,
> + DDR_CS1_ROW_MASK = 3,
> + DDR_CS1_ROW_SHIFT = 4,
> +
> + /*
> + * 00: 32 bit
> + * 01: 16 bit
> + * 10: 8 bit
> + * rk3036 only support 16bit
> + */
> + DDR_BW_MASK = 3,
> + DDR_BW_SHIFT = 2,
> + DDR_DIE_BW_MASK = 3,
> + DDR_DIE_BW_SHIFT = 0,
> +};
> +
> +static void rkdclk_init(struct rk3036_sdram_priv priv)
> +{
> + struct rk3036_pll *pll = &priv.cru->pll[1];
> +
> + /* pll enter slow-mode */
> + rk_clrsetreg(&priv.cru->cru_mode_con,
> + DPLL_MODE_MASK << DPLL_MODE_SHIFT,
> + DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
> +
> + /* use interger mode */
typo: interger -> integer
> + rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
> +
> + rk_clrsetreg(&pll->con0,
> + PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK,
> + (dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) |
> + dpll_init_cfg.fbdiv);
> + rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
> + PLL_REFDIV_MASK << PLL_REFDIV_SHIFT,
> + (dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT |
> + dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT));
> +
> + /* waiting for pll lock */
> + while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
> + rockchip_udelay(1);
> +
> + /* PLL enter normal-mode */
> + rk_clrsetreg(&priv.cru->cru_mode_con,
> + DPLL_MODE_MASK << DPLL_MODE_SHIFT,
> + DPLL_MODE_NORM << DPLL_MODE_SHIFT);
> +}
> +
> +static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
> +{
> + int i;
> +
> + for (i = 0; i < n / sizeof(u32); i++) {
> + writel(*src, dest);
> + src++;
> + dest++;
> + }
> +}
> +
> +void phy_pctrl_reset(struct rk3036_sdram_priv priv)
> +{
> + struct rk3036_ddr_phy *ddr_phy = priv.phy;
> +
> + rk_clrsetreg(&priv.cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
> + 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT |
> + 1 << DDRPHY_SRST_SHIFT,
> + 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
> + 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
> + rockchip_udelay(10);
> +
> + rk_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);
> + 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
> + * enter the config, so fallthrough
> + */
> + case ACCESS:
> + /* fallthrough */
> + case INIT_MEM:
> + writel(CFG_STATE, &pctl->sctl);
> + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
> + ;
> + break;
> + case CONFIG:
> + return;
> + default:
> + break;
> + }
> + }
> +}
> +
> +static void move_to_access_state(struct rk3036_sdram_priv priv)
> +{
> + unsigned int state;
> + struct rk3036_ddr_pctl *pctl = priv.pctl;
> +
> + while (1) {
> + state = readl(&pctl->stat) & PCTL_STAT_MASK;
> + switch (state) {
> + case LOW_POWER:
> + writel(WAKEUP_STATE, &pctl->sctl);
> + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
> + ;
> + break;
> + case INIT_MEM:
> + writel(CFG_STATE, &pctl->sctl);
> + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
> + ;
> + /* fallthrough */
> + case CONFIG:
> + writel(GO_STATE, &pctl->sctl);
> + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
> + ;
> + break;
> + case ACCESS:
> + return;
> + default:
> + break;
> + }
> + }
> +}
> +
> +static void pctl_cfg(struct rk3036_sdram_priv priv)
> +{
> + struct rk3036_ddr_pctl *pctl = priv.pctl;
> + u32 burst_len;
> + u32 reg;
> +
> + writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0);
> + writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1);
> + writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2);
> + writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN,
> + &pctl->dfilpcfg0);
> +
> + writel(1, &pctl->dfitphyupdtype0);
> + writel(0x0d, &pctl->dfitphyrdlat);
> +
> + /* cs0 and cs1 write odt enable */
> + writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
> + &pctl->dfiodtcfg);
> +
> + /* odt write length */
> + writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1);
> +
> + /* phyupd and ctrlupd disabled */
> + writel(0, &pctl->dfiupdcfg);
> +
> + if ((ddr_timing.noc_timing.burstlen << 1) == 4)
> + burst_len = MEM_BL4;
> + else
> + burst_len = MEM_BL8;
> +
> + copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u,
> + sizeof(struct rk3036_pctl_timing));
> + reg = readl(&pctl->tcl);
> + writel(reg - 3, &pctl->dfitrddataen);
> + reg = readl(&pctl->tcwl);
> + writel(reg - 1, &pctl->dfitphywrlat);
> +
> + writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT |
> + PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN |
> + (0 & PD_IDLE_MASK) << PD_IDLE_SHIFT,
> + &pctl->mcfg);
> +
> + writel(RK_SETBITS(MSCH4_MAINDDR3), &priv.grf->soc_con2);
> + setbits_le32(&pctl->scfg, HW_LOW_POWER_EN);
> +}
> +
> +static void phy_cfg(struct rk3036_sdram_priv priv)
> +{
> + struct rk3036_ddr_phy *ddr_phy = priv.phy;
> + struct rk3036_service_sys *axi_bus = priv.axi_bus;
> +
> + writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming);
> + writel(0x3f, &axi_bus->readlatency);
> +
> + writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE,
> + &ddr_phy->ddrphy_reg2);
> +
> + clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl);
> + writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a);
> + writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16);
> + writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22);
> + writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25);
> + writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26);
> + writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27);
> + writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28);
> +}
> +
> +void dram_cfg_rbc(struct rk3036_sdram_priv priv)
> +{
> + char noc_config;
> + int i = 0;
> + struct rk3036_ddr_config config = priv.ddr_config;
> + struct rk3036_service_sys *axi_bus = priv.axi_bus;
> +
> + move_to_config_state(priv);
> +
> + /* 2bit in BIT1, 2 */
> + if (config.rank == 2) {
> + noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
> + 1 << 3 | (config.col - 10);
> + if (noc_config == ddr_cfg_2_rbc[9]) {
> + i = 9;
> + goto finish;
> + } else if (noc_config == ddr_cfg_2_rbc[10]) {
> + i = 10;
> + goto finish;
> + }
> + }
> +
> + noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
> + (config.col - 10);
> +
> + for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) {
> + if (noc_config == ddr_cfg_2_rbc[i])
> + goto finish;
> + }
> +
> + /* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */
> + noc_config = 1 << 6 | (config.cs0_row - 13) << 4 |
> + 2 << 1 | (config.col - 10);
> + if (noc_config == ddr_cfg_2_rbc[11]) {
> + i = 11;
> + goto finish;
> + }
> +
> + /* bank: 2bit in BIT6,7 */
> + noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 |
> + (config.col - 10);
> +
> + if (noc_config == ddr_cfg_2_rbc[0])
> + i = 0;
> + else if (noc_config == ddr_cfg_2_rbc[12])
> + i = 12;
> + else if (noc_config == ddr_cfg_2_rbc[13])
> + i = 13;
> +finish:
> + writel(i, &axi_bus->ddrconf);
> + move_to_access_state(priv);
> +
> + return;
nit: this return seems unnecessary
> +}
> +
> +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);
> + 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
>
More information about the U-Boot
mailing list