From: Jens Kuske <jensku...@gmail.com> The A64 DRAM controller is very similar to the H3 one, so the code can be reused with some small changes. [Andre: fixed up typo, merged in fixes from Jens]
Signed-off-by: Jens Kuske <jensku...@gmail.com> Signed-off-by: Andre Przywara <andre.przyw...@arm.com> --- arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 1 + arch/arm/include/asm/arch-sunxi/dram.h | 2 +- arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h | 10 +- arch/arm/mach-sunxi/Makefile | 1 + arch/arm/mach-sunxi/clock_sun6i.c | 2 +- arch/arm/mach-sunxi/dram_sun8i_h3.c | 139 +++++++++++++++++++----- 6 files changed, 123 insertions(+), 32 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index be9fcfd..3f87672 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -322,6 +322,7 @@ struct sunxi_ccm_reg { #define CCM_DRAMCLK_CFG_DIV0_MASK (0xf << 8) #define CCM_DRAMCLK_CFG_SRC_PLL5 (0x0 << 20) #define CCM_DRAMCLK_CFG_SRC_PLL6x2 (0x1 << 20) +#define CCM_DRAMCLK_CFG_SRC_PLL11 (0x1 << 20) /* A64 only */ #define CCM_DRAMCLK_CFG_SRC_MASK (0x3 << 20) #define CCM_DRAMCLK_CFG_UPD (0x1 << 16) #define CCM_DRAMCLK_CFG_RST (0x1 << 31) diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index e0be744..53e6d47 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,7 +24,7 @@ #include <asm/arch/dram_sun8i_a33.h> #elif defined(CONFIG_MACH_SUN8I_A83T) #include <asm/arch/dram_sun8i_a83t.h> -#elif defined(CONFIG_MACH_SUN8I_H3) +#elif defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I) #include <asm/arch/dram_sun8i_h3.h> #elif defined(CONFIG_MACH_SUN9I) #include <asm/arch/dram_sun9i.h> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 867fd12..b0e5d93 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h @@ -15,7 +15,8 @@ struct sunxi_mctl_com_reg { u32 cr; /* 0x00 control register */ - u8 res0[0xc]; /* 0x04 */ + u8 res0[0x8]; /* 0x04 */ + u32 tmr; /* 0x0c (A64 only) */ u32 mcr[16][2]; /* 0x10 */ u32 bwcr; /* 0x90 bandwidth control register */ u32 maer; /* 0x94 master enable register */ @@ -32,7 +33,9 @@ struct sunxi_mctl_com_reg { u32 swoffr; /* 0xc4 */ u8 res2[0x8]; /* 0xc8 */ u32 cccr; /* 0xd0 */ - u8 res3[0x72c]; /* 0xd4 */ + u8 res3[0x54]; /* 0xd4 */ + u32 mdfs_bwlr[3]; /* 0x128 (A64 only) */ + u8 res4[0x6cc]; /* 0x134 */ u32 protect; /* 0x800 */ }; @@ -81,7 +84,8 @@ struct sunxi_mctl_ctl_reg { u32 rfshtmg; /* 0x90 refresh timing */ u32 rfshctl1; /* 0x94 */ u32 pwrtmg; /* 0x98 */ - u8 res3[0x20]; /* 0x9c */ + u8 res3[0x1c]; /* 0x9c */ + u32 vtfcr; /* 0xb8 (A64 only) */ u32 dqsgmr; /* 0xbc */ u32 dtcr; /* 0xc0 */ u32 dtar[4]; /* 0xc4 */ diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index e73114e..7daba11 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -50,4 +50,5 @@ obj-$(CONFIG_MACH_SUN8I_A33) += dram_sun8i_a33.o obj-$(CONFIG_MACH_SUN8I_A83T) += dram_sun8i_a83t.o obj-$(CONFIG_MACH_SUN8I_H3) += dram_sun8i_h3.o obj-$(CONFIG_MACH_SUN9I) += dram_sun9i.o +obj-$(CONFIG_MACH_SUN50I) += dram_sun8i_h3.o endif diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c index 382fa94..4570060 100644 --- a/arch/arm/mach-sunxi/clock_sun6i.c +++ b/arch/arm/mach-sunxi/clock_sun6i.c @@ -218,7 +218,7 @@ done: } #endif -#ifdef CONFIG_MACH_SUN8I_A33 +#if defined(CONFIG_MACH_SUN8I_A33) || defined(CONFIG_MACH_SUN50I) void clock_set_pll11(unsigned int clk, bool sigma_delta_enable) { struct sunxi_ccm_reg * const ccm = diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c index 1647d76..2dc2071 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -32,30 +32,6 @@ static inline int ns_to_t(int nanoseconds) return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); } -static u32 bin_to_mgray(int val) -{ - static const u8 lookup_table[32] = { - 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, - 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, - 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d, - 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11, - }; - - return lookup_table[clamp(val, 0, 31)]; -} - -static int mgray_to_bin(u32 val) -{ - static const u8 lookup_table[32] = { - 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, - 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b, - 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b, - 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15, - }; - - return lookup_table[val & 0x1f]; -} - static void mctl_phy_init(u32 val) { struct sunxi_mctl_ctl_reg * const mctl_ctl = @@ -91,8 +67,9 @@ static void mctl_set_master_priority(void) struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; +#if defined(CONFIG_MACH_SUN8I_H3) /* enable bandwidth limit windows and set windows size 1us */ - writel(0x00010190, &mctl_com->bwcr); + writel((1 << 16) | (400 << 0), &mctl_com->bwcr); /* set cpu high priority */ writel(0x00000001, &mctl_com->mapr); @@ -121,6 +98,38 @@ static void mctl_set_master_priority(void) writel(0x04001800, &mctl_com->mcr[10][1]); writel(0x04000009, &mctl_com->mcr[11][0]); writel(0x00400120, &mctl_com->mcr[11][1]); +#elif defined(CONFIG_MACH_SUN50I) + /* enable bandwidth limit windows and set windows size 1us */ + writel(399, &mctl_com->tmr); + writel((1 << 16), &mctl_com->bwcr); + + writel(0x00a0000d, &mctl_com->mcr[0][0]); + writel(0x00500064, &mctl_com->mcr[0][1]); + writel(0x06000009, &mctl_com->mcr[1][0]); + writel(0x01000578, &mctl_com->mcr[1][1]); + writel(0x0200000d, &mctl_com->mcr[2][0]); + writel(0x00600100, &mctl_com->mcr[2][1]); + writel(0x01000009, &mctl_com->mcr[3][0]); + writel(0x00500064, &mctl_com->mcr[3][1]); + writel(0x07000009, &mctl_com->mcr[4][0]); + writel(0x01000640, &mctl_com->mcr[4][1]); + writel(0x01000009, &mctl_com->mcr[5][0]); + writel(0x00000080, &mctl_com->mcr[5][1]); + writel(0x01000009, &mctl_com->mcr[6][0]); + writel(0x00400080, &mctl_com->mcr[6][1]); + writel(0x0100000d, &mctl_com->mcr[7][0]); + writel(0x00400080, &mctl_com->mcr[7][1]); + writel(0x0100000d, &mctl_com->mcr[8][0]); + writel(0x00400080, &mctl_com->mcr[8][1]); + writel(0x04000009, &mctl_com->mcr[9][0]); + writel(0x00400100, &mctl_com->mcr[9][1]); + writel(0x20000209, &mctl_com->mcr[10][0]); + writel(0x08001800, &mctl_com->mcr[10][1]); + writel(0x05000009, &mctl_com->mcr[11][0]); + writel(0x00400090, &mctl_com->mcr[11][1]); + + writel(0x81000004, &mctl_com->mdfs_bwlr[2]); +#endif } static void mctl_set_timing_params(struct dram_para *para) @@ -204,7 +213,32 @@ static void mctl_set_timing_params(struct dram_para *para) writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg); } -static void mctl_zq_calibration(struct dram_para *para) +#ifdef CONFIG_MACH_SUN8I_H3 +static u32 bin_to_mgray(int val) +{ + static const u8 lookup_table[32] = { + 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, + 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, + 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d, + 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11, + }; + + return lookup_table[clamp(val, 0, 31)]; +} + +static int mgray_to_bin(u32 val) +{ + static const u8 lookup_table[32] = { + 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, + 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b, + 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b, + 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15, + }; + + return lookup_table[val & 0x1f]; +} + +static void mctl_h3_zq_calibration_quirk(struct dram_para *para) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; @@ -261,6 +295,7 @@ static void mctl_zq_calibration(struct dram_para *para) writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); } } +#endif static void mctl_set_cr(struct dram_para *para) { @@ -286,16 +321,27 @@ static void mctl_sys_init(struct dram_para *para) clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN); +#ifdef CONFIG_MACH_SUN50I + clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN); +#endif udelay(10); clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST); udelay(1000); +#ifdef CONFIG_MACH_SUN50I + clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false); + clrsetbits_le32(&ccm->dram_clk_cfg, + CCM_DRAMCLK_CFG_DIV_MASK | CCM_DRAMCLK_CFG_SRC_MASK, + CCM_DRAMCLK_CFG_DIV(1) | CCM_DRAMCLK_CFG_SRC_PLL11 | + CCM_DRAMCLK_CFG_UPD); +#else clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false); clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV_MASK | CCM_DRAMCLK_CFG_SRC_MASK, CCM_DRAMCLK_CFG_DIV(1) | CCM_DRAMCLK_CFG_SRC_PLL5 | CCM_DRAMCLK_CFG_UPD); +#endif mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0); setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); @@ -347,12 +393,18 @@ static int mctl_channel_init(struct dram_para *para) /* set DQS auto gating PD mode */ setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6); +#if defined(CONFIG_MACH_SUN8I_H3) /* dx ddr_clk & hdr_clk dynamic mode */ clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12)); /* dphy & aphy phase select 270 degree */ clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), (0x1 << 10) | (0x2 << 8)); +#elif defined(CONFIG_MACH_SUN50I) + /* dphy & aphy phase select ? */ + clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), + (0x0 << 10) | (0x3 << 8)); +#endif /* set half DQ */ if (para->bus_width != 32) { @@ -367,10 +419,17 @@ static int mctl_channel_init(struct dram_para *para) mctl_set_bit_delays(para); udelay(50); - mctl_zq_calibration(para); +#ifdef CONFIG_MACH_SUN8I_H3 + mctl_h3_zq_calibration_quirk(para); mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); +#else + clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ); + + mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | + PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); +#endif /* detect ranks and bus width */ if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) { @@ -408,7 +467,11 @@ static int mctl_channel_init(struct dram_para *para) udelay(10); /* set PGCR3, CKE polarity */ +#ifdef CONFIG_MACH_SUN50I + writel(0xc0aa0060, &mctl_ctl->pgcr[3]); +#else writel(0x00aa0060, &mctl_ctl->pgcr[3]); +#endif /* power down zq calibration module for power save */ setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN); @@ -452,6 +515,7 @@ unsigned long sunxi_dram_init(void) .row_bits = 15, .page_size = 4096, +#if defined(CONFIG_MACH_SUN8I_H3) .dx_read_delays = {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, @@ -464,6 +528,20 @@ unsigned long sunxi_dram_init(void) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +#elif defined(CONFIG_MACH_SUN50I) + .dx_read_delays = {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, + { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, + { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, + { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}, + .dx_write_delays = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, + { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, + { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}, + .ac_delays = { 5, 5, 13, 10, 2, 5, 3, 3, + 0, 3, 3, 3, 1, 0, 0, 0, + 3, 4, 0, 3, 4, 1, 4, 0, + 1, 1, 0, 1, 13, 5, 4 }, +#endif }; mctl_sys_init(¶); @@ -476,8 +554,15 @@ unsigned long sunxi_dram_init(void) writel(0x00000201, &mctl_ctl->odtmap); udelay(1); +#ifdef CONFIG_MACH_SUN8I_H3 /* odt delay */ writel(0x0c000400, &mctl_ctl->odtcfg); +#endif + +#ifdef CONFIG_MACH_SUN50I + setbits_le32(&mctl_ctl->vtfcr, (1 << 9)); + clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); +#endif /* clear credit value */ setbits_le32(&mctl_com->cccr, 1 << 31); -- 2.8.2 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot