From 1bc464be1fc559a3f6dc1334297245d5b27b9b57 Mon Sep 17 00:00:00 2001 From: Jens Kuske Date: Mon, 2 Jan 2017 11:48:42 +0000 Subject: [PATCH] sunxi: A64: use H3 DRAM initialization code for A64 as well The A64 DRAM controller is very similar to the H3 one, so the code can be reused with some small changes. This refactoring does not change the code size for the existing H3 part. [Andre: rework from #ifdefs to using socid parameters in static functions, minor fixes, merging in fixes from Jens] Signed-off-by: Jens Kuske Signed-off-by: Andre Przywara Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 1 + arch/arm/include/asm/arch-sunxi/cpu.h | 3 + arch/arm/include/asm/arch-sunxi/dram.h | 2 +- .../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 | 207 +++++++++++++----- 7 files changed, 172 insertions(+), 54 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index be9fcfda0e..3f87672c62 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/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index 73583ed445..6f96a9715a 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -13,4 +13,7 @@ #include #endif +#define SOCID_A64 0x1689 +#define SOCID_H3 0x1680 + #endif /* _SUNXI_CPU_H */ diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index e0be744dba..53e6d471d2 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,7 +24,7 @@ #include #elif defined(CONFIG_MACH_SUN8I_A83T) #include -#elif defined(CONFIG_MACH_SUN8I_H3) +#elif defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I) #include #elif defined(CONFIG_MACH_SUN9I) #include 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 346538c3a1..25d07d9863 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 (unused on H3) */ 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 (unused on H3) */ + 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 (unused on H3) */ 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 e73114ee64..7daba1169c 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 8e39bbef82..d123b3acb2 100644 --- a/arch/arm/mach-sunxi/clock_sun6i.c +++ b/arch/arm/mach-sunxi/clock_sun6i.c @@ -217,7 +217,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 4396754766..fe9cf9a181 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* @@ -42,30 +43,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 = @@ -148,13 +125,13 @@ inline void mbus_configure_port(u8 port, mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \ MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2) -static void mctl_set_master_priority(void) +static void mctl_set_master_priority_h3(void) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; /* 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); @@ -173,7 +150,46 @@ static void mctl_set_master_priority(void) MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64); } -static void mctl_set_timing_params(struct dram_para *para) +static void mctl_set_master_priority_a64(void) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + + /* enable bandwidth limit windows and set windows size 1us */ + writel(399, &mctl_com->tmr); + writel((1 << 16), &mctl_com->bwcr); + + /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they + * initialise it */ + MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80); + MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256); + MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96); + MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100); + MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256); + MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0); + MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); + MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); + MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); + MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); + MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048); + MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64); + + writel(0x81000004, &mctl_com->mdfs_bwlr[2]); +} + +static void mctl_set_master_priority(uint16_t socid) +{ + switch (socid) { + case SOCID_H3: + mctl_set_master_priority_h3(); + return; + case SOCID_A64: + mctl_set_master_priority_a64(); + return; + } +} + +static void mctl_set_timing_params(uint16_t socid, struct dram_para *para) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; @@ -254,7 +270,31 @@ 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) +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; @@ -324,7 +364,7 @@ static void mctl_set_cr(struct dram_para *para) MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); } -static void mctl_sys_init(struct dram_para *para) +static void mctl_sys_init(uint16_t socid, struct dram_para *para) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; @@ -336,16 +376,30 @@ 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); + if (socid == SOCID_A64) + clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN); udelay(10); clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST); udelay(1000); - 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); + if (socid == SOCID_A64) { + 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 if (socid == SOCID_H3) { + 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); + } mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0); setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); @@ -360,7 +414,7 @@ static void mctl_sys_init(struct dram_para *para) udelay(500); } -static int mctl_channel_init(struct dram_para *para) +static int mctl_channel_init(uint16_t socid, struct dram_para *para) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; @@ -370,8 +424,8 @@ static int mctl_channel_init(struct dram_para *para) unsigned int i; mctl_set_cr(para); - mctl_set_timing_params(para); - mctl_set_master_priority(); + mctl_set_timing_params(socid, para); + mctl_set_master_priority(socid); /* setting VTC, default disable all VT */ clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f); @@ -397,12 +451,18 @@ static int mctl_channel_init(struct dram_para *para) /* set DQS auto gating PD mode */ setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6); - /* dx ddr_clk & hdr_clk dynamic mode */ - clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12)); + if (socid == SOCID_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)); + /* dphy & aphy phase select 270 degree */ + clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), + (0x1 << 10) | (0x2 << 8)); + } else if (socid == SOCID_A64) { + /* dphy & aphy phase select ? */ + clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), + (0x0 << 10) | (0x3 << 8)); + } /* set half DQ */ if (para->bus_width != 32) { @@ -417,10 +477,17 @@ static int mctl_channel_init(struct dram_para *para) mctl_set_bit_delays(para); udelay(50); - mctl_zq_calibration(para); + if (socid == SOCID_H3) { + mctl_h3_zq_calibration_quirk(para); - mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST | - PIR_DRAMINIT | PIR_QSGATE); + mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | + PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); + } else if (socid == SOCID_A64) { + 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); + } /* detect ranks and bus width */ if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) { @@ -458,7 +525,10 @@ static int mctl_channel_init(struct dram_para *para) udelay(10); /* set PGCR3, CKE polarity */ - writel(0x00aa0060, &mctl_ctl->pgcr[3]); + if (socid == SOCID_H3) + writel(0x00aa0060, &mctl_ctl->pgcr[3]); + else if (socid == SOCID_A64) + writel(0xc0aa0060, &mctl_ctl->pgcr[3]); /* power down zq calibration module for power save */ setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN); @@ -512,6 +582,22 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0 } +#define SUN50I_A64_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 }} +#define SUN50I_A64_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 }} +#define SUN50I_A64_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 } + unsigned long sunxi_dram_init(void) { struct sunxi_mctl_com_reg * const mctl_com = @@ -524,13 +610,30 @@ unsigned long sunxi_dram_init(void) .bus_width = 32, .row_bits = 15, .page_size = 4096, + +#if defined(CONFIG_MACH_SUN8I_H3) .dx_read_delays = SUN8I_H3_DX_READ_DELAYS, .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS, .ac_delays = SUN8I_H3_AC_DELAYS, +#elif defined(CONFIG_MACH_SUN50I) + .dx_read_delays = SUN50I_A64_DX_READ_DELAYS, + .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS, + .ac_delays = SUN50I_A64_AC_DELAYS, +#endif }; +/* + * Let the compiler optimize alternatives away by passing this value into + * the static functions. This saves us #ifdefs, but still keeps the binary + * small. + */ +#if defined(CONFIG_MACH_SUN8I_H3) + uint16_t socid = SOCID_H3; +#elif defined(CONFIG_MACH_SUN50I) + uint16_t socid = SOCID_A64; +#endif - mctl_sys_init(¶); - if (mctl_channel_init(¶)) + mctl_sys_init(socid, ¶); + if (mctl_channel_init(socid, ¶)) return 0; if (para.dual_rank) @@ -540,7 +643,13 @@ unsigned long sunxi_dram_init(void) udelay(1); /* odt delay */ - writel(0x0c000400, &mctl_ctl->odtcfg); + if (socid == SOCID_H3) + writel(0x0c000400, &mctl_ctl->odtcfg); + + if (socid == SOCID_A64) { + setbits_le32(&mctl_ctl->vtfcr, 2 << 8); + clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); + } /* clear credit value */ setbits_le32(&mctl_com->cccr, 1 << 31);