diff options
Diffstat (limited to 'arch/arm/mach-sunxi/dram_sun8i_h3.c')
-rw-r--r-- | arch/arm/mach-sunxi/dram_sun8i_h3.c | 400 |
1 files changed, 289 insertions, 111 deletions
diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c index b08b8e6..9f7cc7f 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -13,15 +13,27 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/dram.h> +#include <asm/arch/cpu.h> #include <linux/kconfig.h> +/* + * The delay parameters below allow to allegedly specify delay times of some + * unknown unit for each individual bit trace in each of the four data bytes + * the 32-bit wide access consists of. Also three control signals can be + * adjusted individually. + */ +#define BITS_PER_BYTE 8 +#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE) +/* The eight data lines (DQn) plus DM, DQS and DQSN */ +#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) struct dram_para { - u32 read_delays; - u32 write_delays; u16 page_size; u8 bus_width; u8 dual_rank; u8 row_bits; + const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 ac_delays[31]; }; static inline int ns_to_t(int nanoseconds) @@ -31,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 = @@ -64,74 +52,144 @@ static void mctl_phy_init(u32 val) mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1); } -static void mctl_dq_delay(u32 read, u32 write) +static void mctl_set_bit_delays(struct dram_para *para) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; int i, j; - u32 val; - - for (i = 0; i < 4; i++) { - val = DATX_IOCR_WRITE_DELAY((write >> (i * 4)) & 0xf) | - DATX_IOCR_READ_DELAY(((read >> (i * 4)) & 0xf) * 2); - - for (j = DATX_IOCR_DQ(0); j <= DATX_IOCR_DM; j++) - writel(val, &mctl_ctl->datx[i].iocr[j]); - } clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26); - for (i = 0; i < 4; i++) { - val = DATX_IOCR_WRITE_DELAY((write >> (16 + i * 4)) & 0xf) | - DATX_IOCR_READ_DELAY((read >> (16 + i * 4)) & 0xf); + for (i = 0; i < NR_OF_BYTE_LANES; i++) + for (j = 0; j < LINES_PER_BYTE_LANE; j++) + writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) | + DXBDLR_READ_DELAY(para->dx_read_delays[i][j]), + &mctl_ctl->dx[i].bdlr[j]); - writel(val, &mctl_ctl->datx[i].iocr[DATX_IOCR_DQS]); - writel(val, &mctl_ctl->datx[i].iocr[DATX_IOCR_DQSN]); - } + for (i = 0; i < 31; i++) + writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]), + &mctl_ctl->acbdlr[i]); setbits_le32(&mctl_ctl->pgcr[0], 1 << 26); +} - udelay(1); +enum { + MBUS_PORT_CPU = 0, + MBUS_PORT_GPU = 1, + MBUS_PORT_UNUSED = 2, + MBUS_PORT_DMA = 3, + MBUS_PORT_VE = 4, + MBUS_PORT_CSI = 5, + MBUS_PORT_NAND = 6, + MBUS_PORT_SS = 7, + MBUS_PORT_TS = 8, + MBUS_PORT_DI = 9, + MBUS_PORT_DE = 10, + MBUS_PORT_DE_CFD = 11, +}; + +enum { + MBUS_QOS_LOWEST = 0, + MBUS_QOS_LOW, + MBUS_QOS_HIGH, + MBUS_QOS_HIGHEST +}; + +inline void mbus_configure_port(u8 port, + bool bwlimit, + bool priority, + u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */ + u8 waittime, /* 0 .. 0xf */ + u8 acs, /* 0 .. 0xff */ + u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */ + u16 bwl1, + u16 bwl2) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + + const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0) + | (priority ? (1 << 1) : 0) + | ((qos & 0x3) << 2) + | ((waittime & 0xf) << 4) + | ((acs & 0xff) << 8) + | (bwl0 << 16) ); + const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff); + + debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1); + writel(cfg0, &mctl_com->mcr[port][0]); + writel(cfg1, &mctl_com->mcr[port][1]); } -static void mctl_set_master_priority(void) +#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \ + mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \ + MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2) + +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); - writel(0x0200000d, &mctl_com->mcr[0][0]); - writel(0x00800100, &mctl_com->mcr[0][1]); - writel(0x06000009, &mctl_com->mcr[1][0]); - writel(0x01000400, &mctl_com->mcr[1][1]); - writel(0x0200000d, &mctl_com->mcr[2][0]); - writel(0x00600100, &mctl_com->mcr[2][1]); - writel(0x0100000d, &mctl_com->mcr[3][0]); - writel(0x00200080, &mctl_com->mcr[3][1]); - writel(0x07000009, &mctl_com->mcr[4][0]); - writel(0x01000640, &mctl_com->mcr[4][1]); - writel(0x0100000d, &mctl_com->mcr[5][0]); - writel(0x00200080, &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(0x2000030d, &mctl_com->mcr[10][0]); - writel(0x04001800, &mctl_com->mcr[10][1]); - writel(0x04000009, &mctl_com->mcr[11][0]); - writel(0x00400120, &mctl_com->mcr[11][1]); + MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128); + MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256); + MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96); + MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32); + MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256); + MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32); + 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, HIGHEST, 3, 8192, 6120, 1024); + 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; @@ -212,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; @@ -282,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; @@ -294,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); @@ -318,7 +414,12 @@ static void mctl_sys_init(struct dram_para *para) udelay(500); } -static int mctl_channel_init(struct dram_para *para) +/* These are more guessed based on some Allwinner code. */ +#define DX_GCR_ODT_DYNAMIC (0x0 << 4) +#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4) +#define DX_GCR_ODT_OFF (0x2 << 4) + +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; @@ -328,8 +429,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); @@ -344,10 +445,11 @@ static int mctl_channel_init(struct dram_para *para) /* set dramc odt */ for (i = 0; i < 4; i++) - clrsetbits_le32(&mctl_ctl->datx[i].gcr, (0x3 << 4) | + clrsetbits_le32(&mctl_ctl->dx[i].gcr, (0x3 << 4) | (0x1 << 1) | (0x3 << 2) | (0x3 << 12) | (0x3 << 14), - IS_ENABLED(CONFIG_DRAM_ODT_EN) ? 0x0 : 0x2); + IS_ENABLED(CONFIG_DRAM_ODT_EN) ? + DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF); /* AC PDR should always ON */ setbits_le32(&mctl_ctl->aciocr, 0x1 << 1); @@ -355,48 +457,58 @@ 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)); - - /* dphy & aphy phase select 270 degree */ - clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), - (0x1 << 10) | (0x2 << 8)); + 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)); + } 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) { - writel(0x0, &mctl_ctl->datx[2].gcr); - writel(0x0, &mctl_ctl->datx[3].gcr); + writel(0x0, &mctl_ctl->dx[2].gcr); + writel(0x0, &mctl_ctl->dx[3].gcr); } /* data training configuration */ clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, (para->dual_rank ? 0x3 : 0x1) << 24); + mctl_set_bit_delays(para); + udelay(50); - if (para->read_delays || para->write_delays) { - mctl_dq_delay(para->read_delays, para->write_delays); - udelay(50); - } + if (socid == SOCID_H3) { + mctl_h3_zq_calibration_quirk(para); - mctl_zq_calibration(para); + 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_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST | - PIR_DRAMINIT | PIR_QSGATE); + 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)) { /* only one rank */ - if (((readl(&mctl_ctl->datx[0].gsr[0]) >> 24) & 0x2) || - ((readl(&mctl_ctl->datx[1].gsr[0]) >> 24) & 0x2)) { + if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) || + ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)) { clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24); para->dual_rank = 0; } /* only half DQ width */ - if (((readl(&mctl_ctl->datx[2].gsr[0]) >> 24) & 0x1) || - ((readl(&mctl_ctl->datx[3].gsr[0]) >> 24) & 0x1)) { - writel(0x0, &mctl_ctl->datx[2].gcr); - writel(0x0, &mctl_ctl->datx[3].gcr); + if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) || + ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { + writel(0x0, &mctl_ctl->dx[2].gcr); + writel(0x0, &mctl_ctl->dx[3].gcr); para->bus_width = 16; } @@ -419,7 +531,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); @@ -450,6 +565,45 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) break; } +/* + * The actual values used here are taken from Allwinner provided boot0 + * binaries, though they are probably board specific, so would likely benefit + * from invidual tuning for each board. Apparently a lot of boards copy from + * some Allwinner reference design, so we go with those generic values for now + * in the hope that they are reasonable for most (all?) boards. + */ +#define 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 }, \ + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }} +#define SUN8I_H3_DX_WRITE_DELAYS \ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }} +#define SUN8I_H3_AC_DELAYS \ + { 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 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 = @@ -458,16 +612,34 @@ unsigned long sunxi_dram_init(void) (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; struct dram_para para = { - .read_delays = 0x00007979, /* dram_tpr12 */ - .write_delays = 0x6aaa0000, /* dram_tpr11 */ .dual_rank = 0, .bus_width = 32, .row_bits = 15, .page_size = 4096, - }; - mctl_sys_init(¶); - if (mctl_channel_init(¶)) +#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(socid, ¶); + if (mctl_channel_init(socid, ¶)) return 0; if (para.dual_rank) @@ -477,7 +649,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); @@ -486,6 +664,6 @@ unsigned long sunxi_dram_init(void) mctl_auto_detect_dram_size(¶); mctl_set_cr(¶); - return (1 << (para.row_bits + 3)) * para.page_size * + return (1UL << (para.row_bits + 3)) * para.page_size * (para.dual_rank ? 2 : 1); } |