19934aba4SIcenowy Zheng /*
29934aba4SIcenowy Zheng * sun8i H3 platform dram controller init
39934aba4SIcenowy Zheng *
49934aba4SIcenowy Zheng * (C) Copyright 2007-2015 Allwinner Technology Co.
59934aba4SIcenowy Zheng * Jerry Wang <wangflord@allwinnertech.com>
69934aba4SIcenowy Zheng * (C) Copyright 2015 Vishnu Patekar <vishnupatekar0510@gmail.com>
79934aba4SIcenowy Zheng * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
89934aba4SIcenowy Zheng * (C) Copyright 2015 Jens Kuske <jenskuske@gmail.com>
99934aba4SIcenowy Zheng *
109934aba4SIcenowy Zheng * SPDX-License-Identifier: GPL-2.0+
119934aba4SIcenowy Zheng */
129934aba4SIcenowy Zheng #include <common.h>
139934aba4SIcenowy Zheng #include <asm/io.h>
149934aba4SIcenowy Zheng #include <asm/arch/clock.h>
159934aba4SIcenowy Zheng #include <asm/arch/dram.h>
169934aba4SIcenowy Zheng #include <asm/arch/cpu.h>
179934aba4SIcenowy Zheng #include <linux/kconfig.h>
189934aba4SIcenowy Zheng
mctl_phy_init(u32 val)199934aba4SIcenowy Zheng static void mctl_phy_init(u32 val)
209934aba4SIcenowy Zheng {
219934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
229934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
239934aba4SIcenowy Zheng
249934aba4SIcenowy Zheng writel(val | PIR_INIT, &mctl_ctl->pir);
259934aba4SIcenowy Zheng mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
269934aba4SIcenowy Zheng }
279934aba4SIcenowy Zheng
mctl_set_bit_delays(struct dram_para * para)289934aba4SIcenowy Zheng static void mctl_set_bit_delays(struct dram_para *para)
299934aba4SIcenowy Zheng {
309934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
319934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
329934aba4SIcenowy Zheng int i, j;
339934aba4SIcenowy Zheng
349934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
359934aba4SIcenowy Zheng
369934aba4SIcenowy Zheng for (i = 0; i < NR_OF_BYTE_LANES; i++)
379934aba4SIcenowy Zheng for (j = 0; j < LINES_PER_BYTE_LANE; j++)
389934aba4SIcenowy Zheng writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
399934aba4SIcenowy Zheng DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
409934aba4SIcenowy Zheng &mctl_ctl->dx[i].bdlr[j]);
419934aba4SIcenowy Zheng
429934aba4SIcenowy Zheng for (i = 0; i < 31; i++)
439934aba4SIcenowy Zheng writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
449934aba4SIcenowy Zheng &mctl_ctl->acbdlr[i]);
459934aba4SIcenowy Zheng
469934aba4SIcenowy Zheng #ifdef CONFIG_MACH_SUN8I_R40
479934aba4SIcenowy Zheng /* DQSn, DMn, DQn output enable bit delay */
489934aba4SIcenowy Zheng for (i = 0; i < 4; i++)
499934aba4SIcenowy Zheng writel(0x6 << 24, &mctl_ctl->dx[i].sdlr);
509934aba4SIcenowy Zheng #endif
519934aba4SIcenowy Zheng
529934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
539934aba4SIcenowy Zheng }
549934aba4SIcenowy Zheng
559934aba4SIcenowy Zheng enum {
569934aba4SIcenowy Zheng MBUS_PORT_CPU = 0,
579934aba4SIcenowy Zheng MBUS_PORT_GPU = 1,
589934aba4SIcenowy Zheng MBUS_PORT_UNUSED = 2,
599934aba4SIcenowy Zheng MBUS_PORT_DMA = 3,
609934aba4SIcenowy Zheng MBUS_PORT_VE = 4,
619934aba4SIcenowy Zheng MBUS_PORT_CSI = 5,
629934aba4SIcenowy Zheng MBUS_PORT_NAND = 6,
639934aba4SIcenowy Zheng MBUS_PORT_SS = 7,
649934aba4SIcenowy Zheng MBUS_PORT_TS = 8,
659934aba4SIcenowy Zheng MBUS_PORT_DI = 9,
669934aba4SIcenowy Zheng MBUS_PORT_DE = 10,
679934aba4SIcenowy Zheng MBUS_PORT_DE_CFD = 11,
689934aba4SIcenowy Zheng MBUS_PORT_UNKNOWN1 = 12,
699934aba4SIcenowy Zheng MBUS_PORT_UNKNOWN2 = 13,
709934aba4SIcenowy Zheng MBUS_PORT_UNKNOWN3 = 14,
719934aba4SIcenowy Zheng };
729934aba4SIcenowy Zheng
739934aba4SIcenowy Zheng enum {
749934aba4SIcenowy Zheng MBUS_QOS_LOWEST = 0,
759934aba4SIcenowy Zheng MBUS_QOS_LOW,
769934aba4SIcenowy Zheng MBUS_QOS_HIGH,
779934aba4SIcenowy Zheng MBUS_QOS_HIGHEST
789934aba4SIcenowy Zheng };
799934aba4SIcenowy Zheng
mbus_configure_port(u8 port,bool bwlimit,bool priority,u8 qos,u8 waittime,u8 acs,u16 bwl0,u16 bwl1,u16 bwl2)809934aba4SIcenowy Zheng inline void mbus_configure_port(u8 port,
819934aba4SIcenowy Zheng bool bwlimit,
829934aba4SIcenowy Zheng bool priority,
839934aba4SIcenowy Zheng u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */
849934aba4SIcenowy Zheng u8 waittime, /* 0 .. 0xf */
859934aba4SIcenowy Zheng u8 acs, /* 0 .. 0xff */
869934aba4SIcenowy Zheng u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */
879934aba4SIcenowy Zheng u16 bwl1,
889934aba4SIcenowy Zheng u16 bwl2)
899934aba4SIcenowy Zheng {
909934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
919934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
929934aba4SIcenowy Zheng
939934aba4SIcenowy Zheng const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
949934aba4SIcenowy Zheng | (priority ? (1 << 1) : 0)
959934aba4SIcenowy Zheng | ((qos & 0x3) << 2)
969934aba4SIcenowy Zheng | ((waittime & 0xf) << 4)
979934aba4SIcenowy Zheng | ((acs & 0xff) << 8)
989934aba4SIcenowy Zheng | (bwl0 << 16) );
999934aba4SIcenowy Zheng const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
1009934aba4SIcenowy Zheng
1019934aba4SIcenowy Zheng debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
1029934aba4SIcenowy Zheng writel(cfg0, &mctl_com->mcr[port][0]);
1039934aba4SIcenowy Zheng writel(cfg1, &mctl_com->mcr[port][1]);
1049934aba4SIcenowy Zheng }
1059934aba4SIcenowy Zheng
1069934aba4SIcenowy Zheng #define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
1079934aba4SIcenowy Zheng mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
1089934aba4SIcenowy Zheng MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
1099934aba4SIcenowy Zheng
mctl_set_master_priority_h3(void)1109934aba4SIcenowy Zheng static void mctl_set_master_priority_h3(void)
1119934aba4SIcenowy Zheng {
1129934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
1139934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1149934aba4SIcenowy Zheng
1159934aba4SIcenowy Zheng /* enable bandwidth limit windows and set windows size 1us */
1169934aba4SIcenowy Zheng writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
1179934aba4SIcenowy Zheng
1189934aba4SIcenowy Zheng /* set cpu high priority */
1199934aba4SIcenowy Zheng writel(0x00000001, &mctl_com->mapr);
1209934aba4SIcenowy Zheng
1219934aba4SIcenowy Zheng MBUS_CONF( CPU, true, HIGHEST, 0, 512, 256, 128);
1229934aba4SIcenowy Zheng MBUS_CONF( GPU, true, HIGH, 0, 1536, 1024, 256);
1239934aba4SIcenowy Zheng MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
1249934aba4SIcenowy Zheng MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
1259934aba4SIcenowy Zheng MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
1269934aba4SIcenowy Zheng MBUS_CONF( CSI, true, HIGHEST, 0, 256, 128, 32);
1279934aba4SIcenowy Zheng MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
1289934aba4SIcenowy Zheng MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
1299934aba4SIcenowy Zheng MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
1309934aba4SIcenowy Zheng MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
1319934aba4SIcenowy Zheng MBUS_CONF( DE, true, HIGHEST, 3, 8192, 6120, 1024);
1329934aba4SIcenowy Zheng MBUS_CONF(DE_CFD, true, HIGH, 0, 1024, 288, 64);
1339934aba4SIcenowy Zheng }
1349934aba4SIcenowy Zheng
mctl_set_master_priority_a64(void)1359934aba4SIcenowy Zheng static void mctl_set_master_priority_a64(void)
1369934aba4SIcenowy Zheng {
1379934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
1389934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1399934aba4SIcenowy Zheng
1409934aba4SIcenowy Zheng /* enable bandwidth limit windows and set windows size 1us */
1419934aba4SIcenowy Zheng writel(399, &mctl_com->tmr);
1429934aba4SIcenowy Zheng writel((1 << 16), &mctl_com->bwcr);
1439934aba4SIcenowy Zheng
1449934aba4SIcenowy Zheng /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
1459934aba4SIcenowy Zheng * initialise it */
1469934aba4SIcenowy Zheng MBUS_CONF( CPU, true, HIGHEST, 0, 160, 100, 80);
1479934aba4SIcenowy Zheng MBUS_CONF( GPU, false, HIGH, 0, 1536, 1400, 256);
1489934aba4SIcenowy Zheng MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
1499934aba4SIcenowy Zheng MBUS_CONF( DMA, true, HIGH, 0, 256, 80, 100);
1509934aba4SIcenowy Zheng MBUS_CONF( VE, true, HIGH, 0, 1792, 1600, 256);
1519934aba4SIcenowy Zheng MBUS_CONF( CSI, true, HIGH, 0, 256, 128, 0);
1529934aba4SIcenowy Zheng MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
1539934aba4SIcenowy Zheng MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
1549934aba4SIcenowy Zheng MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
1559934aba4SIcenowy Zheng MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
1569934aba4SIcenowy Zheng MBUS_CONF( DE, true, HIGH, 2, 8192, 6144, 2048);
1579934aba4SIcenowy Zheng MBUS_CONF(DE_CFD, true, HIGH, 0, 1280, 144, 64);
1589934aba4SIcenowy Zheng
1599934aba4SIcenowy Zheng writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
1609934aba4SIcenowy Zheng }
1619934aba4SIcenowy Zheng
mctl_set_master_priority_h5(void)1629934aba4SIcenowy Zheng static void mctl_set_master_priority_h5(void)
1639934aba4SIcenowy Zheng {
1649934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
1659934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1669934aba4SIcenowy Zheng
1679934aba4SIcenowy Zheng /* enable bandwidth limit windows and set windows size 1us */
1689934aba4SIcenowy Zheng writel(399, &mctl_com->tmr);
1699934aba4SIcenowy Zheng writel((1 << 16), &mctl_com->bwcr);
1709934aba4SIcenowy Zheng
1719934aba4SIcenowy Zheng /* set cpu high priority */
1729934aba4SIcenowy Zheng writel(0x00000001, &mctl_com->mapr);
1739934aba4SIcenowy Zheng
1749934aba4SIcenowy Zheng /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
1759934aba4SIcenowy Zheng * they initialise it */
1769934aba4SIcenowy Zheng MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
1779934aba4SIcenowy Zheng MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
1789934aba4SIcenowy Zheng MBUS_CONF(UNUSED, true, HIGHEST, 0, 512, 256, 96);
1799934aba4SIcenowy Zheng MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
1809934aba4SIcenowy Zheng MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
1819934aba4SIcenowy Zheng MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
1829934aba4SIcenowy Zheng MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
1839934aba4SIcenowy Zheng MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
1849934aba4SIcenowy Zheng MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
1859934aba4SIcenowy Zheng MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
1869934aba4SIcenowy Zheng MBUS_CONF( DE, true, HIGHEST, 3, 3400, 2400, 1024);
1879934aba4SIcenowy Zheng MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200);
1889934aba4SIcenowy Zheng }
1899934aba4SIcenowy Zheng
mctl_set_master_priority_r40(void)1909934aba4SIcenowy Zheng static void mctl_set_master_priority_r40(void)
1919934aba4SIcenowy Zheng {
1929934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
1939934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
1949934aba4SIcenowy Zheng
1959934aba4SIcenowy Zheng /* enable bandwidth limit windows and set windows size 1us */
1969934aba4SIcenowy Zheng writel(399, &mctl_com->tmr);
1979934aba4SIcenowy Zheng writel((1 << 16), &mctl_com->bwcr);
1989934aba4SIcenowy Zheng
1999934aba4SIcenowy Zheng /* set cpu high priority */
2009934aba4SIcenowy Zheng writel(0x00000001, &mctl_com->mapr);
2019934aba4SIcenowy Zheng
2029934aba4SIcenowy Zheng /* Port 2 is reserved per Allwinner's linux-3.10 source, yet
2039934aba4SIcenowy Zheng * they initialise it */
2049934aba4SIcenowy Zheng MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150);
2059934aba4SIcenowy Zheng MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200);
2069934aba4SIcenowy Zheng MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96);
2079934aba4SIcenowy Zheng MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32);
2089934aba4SIcenowy Zheng MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000);
2099934aba4SIcenowy Zheng MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100);
2109934aba4SIcenowy Zheng MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64);
2119934aba4SIcenowy Zheng MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64);
2129934aba4SIcenowy Zheng MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64);
2139934aba4SIcenowy Zheng MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64);
2149934aba4SIcenowy Zheng
2159934aba4SIcenowy Zheng /*
2169934aba4SIcenowy Zheng * The port names are probably wrong, but no correct sources
2179934aba4SIcenowy Zheng * are available.
2189934aba4SIcenowy Zheng */
2199934aba4SIcenowy Zheng MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0);
2209934aba4SIcenowy Zheng MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0);
2219934aba4SIcenowy Zheng MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256);
2229934aba4SIcenowy Zheng MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024);
2239934aba4SIcenowy Zheng MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64);
2249934aba4SIcenowy Zheng }
2259934aba4SIcenowy Zheng
mctl_set_master_priority(uint16_t socid)2269934aba4SIcenowy Zheng static void mctl_set_master_priority(uint16_t socid)
2279934aba4SIcenowy Zheng {
2289934aba4SIcenowy Zheng switch (socid) {
2299934aba4SIcenowy Zheng case SOCID_H3:
2309934aba4SIcenowy Zheng mctl_set_master_priority_h3();
2319934aba4SIcenowy Zheng return;
2329934aba4SIcenowy Zheng case SOCID_A64:
2339934aba4SIcenowy Zheng mctl_set_master_priority_a64();
2349934aba4SIcenowy Zheng return;
2359934aba4SIcenowy Zheng case SOCID_H5:
2369934aba4SIcenowy Zheng mctl_set_master_priority_h5();
2379934aba4SIcenowy Zheng return;
2389934aba4SIcenowy Zheng case SOCID_R40:
2399934aba4SIcenowy Zheng mctl_set_master_priority_r40();
2409934aba4SIcenowy Zheng return;
2419934aba4SIcenowy Zheng }
2429934aba4SIcenowy Zheng }
2439934aba4SIcenowy Zheng
bin_to_mgray(int val)2449934aba4SIcenowy Zheng static u32 bin_to_mgray(int val)
2459934aba4SIcenowy Zheng {
2469934aba4SIcenowy Zheng static const u8 lookup_table[32] = {
2479934aba4SIcenowy Zheng 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
2489934aba4SIcenowy Zheng 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
2499934aba4SIcenowy Zheng 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
2509934aba4SIcenowy Zheng 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
2519934aba4SIcenowy Zheng };
2529934aba4SIcenowy Zheng
2539934aba4SIcenowy Zheng return lookup_table[clamp(val, 0, 31)];
2549934aba4SIcenowy Zheng }
2559934aba4SIcenowy Zheng
mgray_to_bin(u32 val)2569934aba4SIcenowy Zheng static int mgray_to_bin(u32 val)
2579934aba4SIcenowy Zheng {
2589934aba4SIcenowy Zheng static const u8 lookup_table[32] = {
2599934aba4SIcenowy Zheng 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
2609934aba4SIcenowy Zheng 0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
2619934aba4SIcenowy Zheng 0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
2629934aba4SIcenowy Zheng 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
2639934aba4SIcenowy Zheng };
2649934aba4SIcenowy Zheng
2659934aba4SIcenowy Zheng return lookup_table[val & 0x1f];
2669934aba4SIcenowy Zheng }
2679934aba4SIcenowy Zheng
mctl_h3_zq_calibration_quirk(struct dram_para * para)2689934aba4SIcenowy Zheng static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
2699934aba4SIcenowy Zheng {
2709934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
2719934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
27287098d70SIcenowy Zheng int zq_count;
27387098d70SIcenowy Zheng
27487098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_16BIT
27587098d70SIcenowy Zheng zq_count = 4;
27687098d70SIcenowy Zheng #else
27787098d70SIcenowy Zheng zq_count = 6;
27887098d70SIcenowy Zheng #endif
2799934aba4SIcenowy Zheng
2809934aba4SIcenowy Zheng if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 &&
2819934aba4SIcenowy Zheng (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) {
2829934aba4SIcenowy Zheng u32 reg_val;
2839934aba4SIcenowy Zheng
2849934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->zqcr, 0xffff,
2859934aba4SIcenowy Zheng CONFIG_DRAM_ZQ & 0xffff);
2869934aba4SIcenowy Zheng
2879934aba4SIcenowy Zheng writel(PIR_CLRSR, &mctl_ctl->pir);
2889934aba4SIcenowy Zheng mctl_phy_init(PIR_ZCAL);
2899934aba4SIcenowy Zheng
2909934aba4SIcenowy Zheng reg_val = readl(&mctl_ctl->zqdr[0]);
2919934aba4SIcenowy Zheng reg_val &= (0x1f << 16) | (0x1f << 0);
2929934aba4SIcenowy Zheng reg_val |= reg_val << 8;
2939934aba4SIcenowy Zheng writel(reg_val, &mctl_ctl->zqdr[0]);
2949934aba4SIcenowy Zheng
2959934aba4SIcenowy Zheng reg_val = readl(&mctl_ctl->zqdr[1]);
2969934aba4SIcenowy Zheng reg_val &= (0x1f << 16) | (0x1f << 0);
2979934aba4SIcenowy Zheng reg_val |= reg_val << 8;
2989934aba4SIcenowy Zheng writel(reg_val, &mctl_ctl->zqdr[1]);
2999934aba4SIcenowy Zheng writel(reg_val, &mctl_ctl->zqdr[2]);
3009934aba4SIcenowy Zheng } else {
3019934aba4SIcenowy Zheng int i;
3029934aba4SIcenowy Zheng u16 zq_val[6];
3039934aba4SIcenowy Zheng u8 val;
3049934aba4SIcenowy Zheng
3059934aba4SIcenowy Zheng writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
3069934aba4SIcenowy Zheng
30787098d70SIcenowy Zheng for (i = 0; i < zq_count; i++) {
3089934aba4SIcenowy Zheng u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
3099934aba4SIcenowy Zheng
3109934aba4SIcenowy Zheng writel((zq << 20) | (zq << 16) | (zq << 12) |
3119934aba4SIcenowy Zheng (zq << 8) | (zq << 4) | (zq << 0),
3129934aba4SIcenowy Zheng &mctl_ctl->zqcr);
3139934aba4SIcenowy Zheng
3149934aba4SIcenowy Zheng writel(PIR_CLRSR, &mctl_ctl->pir);
3159934aba4SIcenowy Zheng mctl_phy_init(PIR_ZCAL);
3169934aba4SIcenowy Zheng
3179934aba4SIcenowy Zheng zq_val[i] = readl(&mctl_ctl->zqdr[0]) & 0xff;
3189934aba4SIcenowy Zheng writel(REPEAT_BYTE(zq_val[i]), &mctl_ctl->zqdr[2]);
3199934aba4SIcenowy Zheng
3209934aba4SIcenowy Zheng writel(PIR_CLRSR, &mctl_ctl->pir);
3219934aba4SIcenowy Zheng mctl_phy_init(PIR_ZCAL);
3229934aba4SIcenowy Zheng
3239934aba4SIcenowy Zheng val = readl(&mctl_ctl->zqdr[0]) >> 24;
3249934aba4SIcenowy Zheng zq_val[i] |= bin_to_mgray(mgray_to_bin(val) - 1) << 8;
3259934aba4SIcenowy Zheng }
3269934aba4SIcenowy Zheng
3279934aba4SIcenowy Zheng writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]);
3289934aba4SIcenowy Zheng writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
32987098d70SIcenowy Zheng if (zq_count > 4)
33087098d70SIcenowy Zheng writel((zq_val[5] << 16) | zq_val[4],
33187098d70SIcenowy Zheng &mctl_ctl->zqdr[2]);
3329934aba4SIcenowy Zheng }
3339934aba4SIcenowy Zheng }
3349934aba4SIcenowy Zheng
mctl_set_cr(uint16_t socid,struct dram_para * para)3359934aba4SIcenowy Zheng static void mctl_set_cr(uint16_t socid, struct dram_para *para)
3369934aba4SIcenowy Zheng {
3379934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
3389934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
3399934aba4SIcenowy Zheng
340f6457ce5SIcenowy Zheng writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED |
341f6457ce5SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DDR3
342f6457ce5SIcenowy Zheng MCTL_CR_DDR3 | MCTL_CR_2T |
34367337e68SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DDR2
34467337e68SIcenowy Zheng MCTL_CR_DDR2 | MCTL_CR_2T |
345*72cc9870SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_LPDDR3
346*72cc9870SIcenowy Zheng MCTL_CR_LPDDR3 | MCTL_CR_1T |
347f6457ce5SIcenowy Zheng #else
348f6457ce5SIcenowy Zheng #error Unsupported DRAM type!
349f6457ce5SIcenowy Zheng #endif
35066b12526SIcenowy Zheng (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) |
351f43a0099SIcenowy Zheng MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) |
3529934aba4SIcenowy Zheng (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) |
3539934aba4SIcenowy Zheng MCTL_CR_PAGE_SIZE(para->page_size) |
3549934aba4SIcenowy Zheng MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
3559934aba4SIcenowy Zheng
3569934aba4SIcenowy Zheng if (socid == SOCID_R40) {
3579934aba4SIcenowy Zheng if (para->dual_rank)
3589934aba4SIcenowy Zheng panic("Dual rank memory not supported\n");
3599934aba4SIcenowy Zheng
3609934aba4SIcenowy Zheng /* Mux pin to A15 address line for single rank memory. */
3619934aba4SIcenowy Zheng setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
3629934aba4SIcenowy Zheng }
3639934aba4SIcenowy Zheng }
3649934aba4SIcenowy Zheng
mctl_sys_init(uint16_t socid,struct dram_para * para)3659934aba4SIcenowy Zheng static void mctl_sys_init(uint16_t socid, struct dram_para *para)
3669934aba4SIcenowy Zheng {
3679934aba4SIcenowy Zheng struct sunxi_ccm_reg * const ccm =
3689934aba4SIcenowy Zheng (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
3699934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
3709934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
3719934aba4SIcenowy Zheng
3729934aba4SIcenowy Zheng clrbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
3739934aba4SIcenowy Zheng clrbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
3749934aba4SIcenowy Zheng clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
3759934aba4SIcenowy Zheng clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
3769934aba4SIcenowy Zheng clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
3779934aba4SIcenowy Zheng if (socid == SOCID_A64 || socid == SOCID_R40)
3789934aba4SIcenowy Zheng clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
3799934aba4SIcenowy Zheng udelay(10);
3809934aba4SIcenowy Zheng
3819934aba4SIcenowy Zheng clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
3829934aba4SIcenowy Zheng udelay(1000);
3839934aba4SIcenowy Zheng
3849934aba4SIcenowy Zheng if (socid == SOCID_A64 || socid == SOCID_R40) {
3859934aba4SIcenowy Zheng clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
3869934aba4SIcenowy Zheng clrsetbits_le32(&ccm->dram_clk_cfg,
3879934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_DIV_MASK |
3889934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_SRC_MASK,
3899934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_DIV(1) |
3909934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_SRC_PLL11 |
3919934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_UPD);
3929934aba4SIcenowy Zheng } else if (socid == SOCID_H3 || socid == SOCID_H5) {
3939934aba4SIcenowy Zheng clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
3949934aba4SIcenowy Zheng clrsetbits_le32(&ccm->dram_clk_cfg,
3959934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_DIV_MASK |
3969934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_SRC_MASK,
3979934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_DIV(1) |
3989934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_SRC_PLL5 |
3999934aba4SIcenowy Zheng CCM_DRAMCLK_CFG_UPD);
4009934aba4SIcenowy Zheng }
4019934aba4SIcenowy Zheng mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
4029934aba4SIcenowy Zheng
4039934aba4SIcenowy Zheng setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
4049934aba4SIcenowy Zheng setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
4059934aba4SIcenowy Zheng setbits_le32(&ccm->mbus_reset, CCM_MBUS_RESET_RESET);
4069934aba4SIcenowy Zheng setbits_le32(&ccm->mbus0_clk_cfg, MBUS_CLK_GATE);
4079934aba4SIcenowy Zheng
4089934aba4SIcenowy Zheng setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
4099934aba4SIcenowy Zheng udelay(10);
4109934aba4SIcenowy Zheng
4119934aba4SIcenowy Zheng writel(socid == SOCID_H5 ? 0x8000 : 0xc00e, &mctl_ctl->clken);
4129934aba4SIcenowy Zheng udelay(500);
4139934aba4SIcenowy Zheng }
4149934aba4SIcenowy Zheng
4159934aba4SIcenowy Zheng /* These are more guessed based on some Allwinner code. */
4169934aba4SIcenowy Zheng #define DX_GCR_ODT_DYNAMIC (0x0 << 4)
4179934aba4SIcenowy Zheng #define DX_GCR_ODT_ALWAYS_ON (0x1 << 4)
4189934aba4SIcenowy Zheng #define DX_GCR_ODT_OFF (0x2 << 4)
4199934aba4SIcenowy Zheng
mctl_channel_init(uint16_t socid,struct dram_para * para)4209934aba4SIcenowy Zheng static int mctl_channel_init(uint16_t socid, struct dram_para *para)
4219934aba4SIcenowy Zheng {
4229934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
4239934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
4249934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
4259934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
4269934aba4SIcenowy Zheng
4279934aba4SIcenowy Zheng unsigned int i;
4289934aba4SIcenowy Zheng
4299934aba4SIcenowy Zheng mctl_set_cr(socid, para);
4309934aba4SIcenowy Zheng mctl_set_timing_params(socid, para);
4319934aba4SIcenowy Zheng mctl_set_master_priority(socid);
4329934aba4SIcenowy Zheng
4339934aba4SIcenowy Zheng /* setting VTC, default disable all VT */
4349934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
4359934aba4SIcenowy Zheng if (socid == SOCID_H5)
4369934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->pgcr[1], (1 << 24) | (1 << 26));
4379934aba4SIcenowy Zheng else
4389934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->pgcr[1], 1 << 24, 1 << 26);
4399934aba4SIcenowy Zheng
4409934aba4SIcenowy Zheng /* increase DFI_PHY_UPD clock */
4419934aba4SIcenowy Zheng writel(PROTECT_MAGIC, &mctl_com->protect);
4429934aba4SIcenowy Zheng udelay(100);
4439934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->upd2, 0xfff << 16, 0x50 << 16);
4449934aba4SIcenowy Zheng writel(0x0, &mctl_com->protect);
4459934aba4SIcenowy Zheng udelay(100);
4469934aba4SIcenowy Zheng
4479934aba4SIcenowy Zheng /* set dramc odt */
4489934aba4SIcenowy Zheng for (i = 0; i < 4; i++) {
4499934aba4SIcenowy Zheng u32 clearmask = (0x3 << 4) | (0x1 << 1) | (0x3 << 2) |
4509934aba4SIcenowy Zheng (0x3 << 12) | (0x3 << 14);
4519934aba4SIcenowy Zheng u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ?
4529934aba4SIcenowy Zheng DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF;
4539934aba4SIcenowy Zheng
4549934aba4SIcenowy Zheng if (socid == SOCID_H5) {
4559934aba4SIcenowy Zheng clearmask |= 0x2 << 8;
4569934aba4SIcenowy Zheng setmask |= 0x4 << 8;
4579934aba4SIcenowy Zheng }
4589934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask);
4599934aba4SIcenowy Zheng }
4609934aba4SIcenowy Zheng
4619934aba4SIcenowy Zheng /* AC PDR should always ON */
4629934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->aciocr, socid == SOCID_H5 ? (0x1 << 11) : 0,
4639934aba4SIcenowy Zheng 0x1 << 1);
4649934aba4SIcenowy Zheng
4659934aba4SIcenowy Zheng /* set DQS auto gating PD mode */
4669934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
4679934aba4SIcenowy Zheng
4689934aba4SIcenowy Zheng if (socid == SOCID_H3) {
4699934aba4SIcenowy Zheng /* dx ddr_clk & hdr_clk dynamic mode */
4709934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
4719934aba4SIcenowy Zheng
4729934aba4SIcenowy Zheng /* dphy & aphy phase select 270 degree */
4739934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4749934aba4SIcenowy Zheng (0x1 << 10) | (0x2 << 8));
4759934aba4SIcenowy Zheng } else if (socid == SOCID_A64 || socid == SOCID_H5) {
4769934aba4SIcenowy Zheng /* dphy & aphy phase select ? */
4779934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4789934aba4SIcenowy Zheng (0x0 << 10) | (0x3 << 8));
4799934aba4SIcenowy Zheng } else if (socid == SOCID_R40) {
4809934aba4SIcenowy Zheng /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */
4819934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
4829934aba4SIcenowy Zheng
4839934aba4SIcenowy Zheng /* dphy & aphy phase select ? */
4849934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
4859934aba4SIcenowy Zheng (0x0 << 10) | (0x3 << 8));
4869934aba4SIcenowy Zheng }
4879934aba4SIcenowy Zheng
4889934aba4SIcenowy Zheng /* set half DQ */
489f43a0099SIcenowy Zheng if (!para->bus_full_width) {
49087098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
4919934aba4SIcenowy Zheng writel(0x0, &mctl_ctl->dx[2].gcr);
4929934aba4SIcenowy Zheng writel(0x0, &mctl_ctl->dx[3].gcr);
49387098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
49487098d70SIcenowy Zheng writel(0x0, &mctl_ctl->dx[1].gcr);
49587098d70SIcenowy Zheng #else
49687098d70SIcenowy Zheng #error Unsupported DRAM bus width!
49787098d70SIcenowy Zheng #endif
4989934aba4SIcenowy Zheng }
4999934aba4SIcenowy Zheng
5009934aba4SIcenowy Zheng /* data training configuration */
5019934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
5029934aba4SIcenowy Zheng (para->dual_rank ? 0x3 : 0x1) << 24);
5039934aba4SIcenowy Zheng
5049934aba4SIcenowy Zheng mctl_set_bit_delays(para);
5059934aba4SIcenowy Zheng udelay(50);
5069934aba4SIcenowy Zheng
5079934aba4SIcenowy Zheng if (socid == SOCID_H3) {
5089934aba4SIcenowy Zheng mctl_h3_zq_calibration_quirk(para);
5099934aba4SIcenowy Zheng
5109934aba4SIcenowy Zheng mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5119934aba4SIcenowy Zheng PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
5129934aba4SIcenowy Zheng } else if (socid == SOCID_A64 || socid == SOCID_H5) {
5139934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
5149934aba4SIcenowy Zheng
5159934aba4SIcenowy Zheng mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5169934aba4SIcenowy Zheng PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
5179934aba4SIcenowy Zheng /* no PIR_QSGATE for H5 ???? */
5189934aba4SIcenowy Zheng } else if (socid == SOCID_R40) {
5199934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
5209934aba4SIcenowy Zheng
5219934aba4SIcenowy Zheng mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
5229934aba4SIcenowy Zheng PIR_DRAMRST | PIR_DRAMINIT);
5239934aba4SIcenowy Zheng }
5249934aba4SIcenowy Zheng
5259934aba4SIcenowy Zheng /* detect ranks and bus width */
5269934aba4SIcenowy Zheng if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
5279934aba4SIcenowy Zheng /* only one rank */
52887098d70SIcenowy Zheng if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
52987098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
53087098d70SIcenowy Zheng || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
53187098d70SIcenowy Zheng #endif
53287098d70SIcenowy Zheng ) {
5339934aba4SIcenowy Zheng clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
5349934aba4SIcenowy Zheng para->dual_rank = 0;
5359934aba4SIcenowy Zheng }
5369934aba4SIcenowy Zheng
5379934aba4SIcenowy Zheng /* only half DQ width */
53887098d70SIcenowy Zheng #if defined CONFIG_SUNXI_DRAM_DW_32BIT
5399934aba4SIcenowy Zheng if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) ||
5409934aba4SIcenowy Zheng ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) {
5419934aba4SIcenowy Zheng writel(0x0, &mctl_ctl->dx[2].gcr);
5429934aba4SIcenowy Zheng writel(0x0, &mctl_ctl->dx[3].gcr);
543f43a0099SIcenowy Zheng para->bus_full_width = 0;
5449934aba4SIcenowy Zheng }
54587098d70SIcenowy Zheng #elif defined CONFIG_SUNXI_DRAM_DW_16BIT
54687098d70SIcenowy Zheng if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
54787098d70SIcenowy Zheng writel(0x0, &mctl_ctl->dx[1].gcr);
54887098d70SIcenowy Zheng para->bus_full_width = 0;
54987098d70SIcenowy Zheng }
55087098d70SIcenowy Zheng #endif
5519934aba4SIcenowy Zheng
5529934aba4SIcenowy Zheng mctl_set_cr(socid, para);
5539934aba4SIcenowy Zheng udelay(20);
5549934aba4SIcenowy Zheng
5559934aba4SIcenowy Zheng /* re-train */
5569934aba4SIcenowy Zheng mctl_phy_init(PIR_QSGATE);
5579934aba4SIcenowy Zheng if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20))
5589934aba4SIcenowy Zheng return 1;
5599934aba4SIcenowy Zheng }
5609934aba4SIcenowy Zheng
5619934aba4SIcenowy Zheng /* check the dramc status */
5629934aba4SIcenowy Zheng mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1);
5639934aba4SIcenowy Zheng
5649934aba4SIcenowy Zheng /* liuke added for refresh debug */
5659934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
5669934aba4SIcenowy Zheng udelay(10);
5679934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31);
5689934aba4SIcenowy Zheng udelay(10);
5699934aba4SIcenowy Zheng
5709934aba4SIcenowy Zheng /* set PGCR3, CKE polarity */
5719934aba4SIcenowy Zheng if (socid == SOCID_H3)
5729934aba4SIcenowy Zheng writel(0x00aa0060, &mctl_ctl->pgcr[3]);
5739934aba4SIcenowy Zheng else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40)
5749934aba4SIcenowy Zheng writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
5759934aba4SIcenowy Zheng
5769934aba4SIcenowy Zheng /* power down zq calibration module for power save */
5779934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
5789934aba4SIcenowy Zheng
5799934aba4SIcenowy Zheng /* enable master access */
5809934aba4SIcenowy Zheng writel(0xffffffff, &mctl_com->maer);
5819934aba4SIcenowy Zheng
5829934aba4SIcenowy Zheng return 0;
5839934aba4SIcenowy Zheng }
5849934aba4SIcenowy Zheng
mctl_auto_detect_dram_size(uint16_t socid,struct dram_para * para)5859934aba4SIcenowy Zheng static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
5869934aba4SIcenowy Zheng {
5879934aba4SIcenowy Zheng /* detect row address bits */
5889934aba4SIcenowy Zheng para->page_size = 512;
5899934aba4SIcenowy Zheng para->row_bits = 16;
59066b12526SIcenowy Zheng para->bank_bits = 2;
5919934aba4SIcenowy Zheng mctl_set_cr(socid, para);
5929934aba4SIcenowy Zheng
5939934aba4SIcenowy Zheng for (para->row_bits = 11; para->row_bits < 16; para->row_bits++)
59466b12526SIcenowy Zheng if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size))
59566b12526SIcenowy Zheng break;
59666b12526SIcenowy Zheng
59766b12526SIcenowy Zheng /* detect bank address bits */
59866b12526SIcenowy Zheng para->bank_bits = 3;
59966b12526SIcenowy Zheng mctl_set_cr(socid, para);
60066b12526SIcenowy Zheng
60166b12526SIcenowy Zheng for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++)
60266b12526SIcenowy Zheng if (mctl_mem_matches((1 << para->bank_bits) * para->page_size))
6039934aba4SIcenowy Zheng break;
6049934aba4SIcenowy Zheng
6059934aba4SIcenowy Zheng /* detect page size */
6069934aba4SIcenowy Zheng para->page_size = 8192;
6079934aba4SIcenowy Zheng mctl_set_cr(socid, para);
6089934aba4SIcenowy Zheng
6099934aba4SIcenowy Zheng for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2)
6109934aba4SIcenowy Zheng if (mctl_mem_matches(para->page_size))
6119934aba4SIcenowy Zheng break;
6129934aba4SIcenowy Zheng }
6139934aba4SIcenowy Zheng
6149934aba4SIcenowy Zheng /*
6159934aba4SIcenowy Zheng * The actual values used here are taken from Allwinner provided boot0
6169934aba4SIcenowy Zheng * binaries, though they are probably board specific, so would likely benefit
6179934aba4SIcenowy Zheng * from invidual tuning for each board. Apparently a lot of boards copy from
6189934aba4SIcenowy Zheng * some Allwinner reference design, so we go with those generic values for now
6199934aba4SIcenowy Zheng * in the hope that they are reasonable for most (all?) boards.
6209934aba4SIcenowy Zheng */
6219934aba4SIcenowy Zheng #define SUN8I_H3_DX_READ_DELAYS \
6229934aba4SIcenowy Zheng {{ 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
6239934aba4SIcenowy Zheng { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
6249934aba4SIcenowy Zheng { 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0 }, \
6259934aba4SIcenowy Zheng { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }}
6269934aba4SIcenowy Zheng #define SUN8I_H3_DX_WRITE_DELAYS \
6279934aba4SIcenowy Zheng {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
6289934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
6299934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }, \
6309934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6 }}
6319934aba4SIcenowy Zheng #define SUN8I_H3_AC_DELAYS \
6329934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, \
6339934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0, 0, \
6349934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0, 0, \
6359934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0 }
6369934aba4SIcenowy Zheng
6379934aba4SIcenowy Zheng #define SUN8I_R40_DX_READ_DELAYS \
6389934aba4SIcenowy Zheng {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
6399934aba4SIcenowy Zheng { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
6409934aba4SIcenowy Zheng { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \
6419934aba4SIcenowy Zheng { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } }
6429934aba4SIcenowy Zheng #define SUN8I_R40_DX_WRITE_DELAYS \
6439934aba4SIcenowy Zheng {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
6449934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
6459934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \
6469934aba4SIcenowy Zheng { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } }
6479934aba4SIcenowy Zheng #define SUN8I_R40_AC_DELAYS \
6489934aba4SIcenowy Zheng { 0, 0, 3, 0, 0, 0, 0, 0, \
6499934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0, 0, \
6509934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0, 0, \
6519934aba4SIcenowy Zheng 0, 0, 0, 0, 0, 0, 0 }
6529934aba4SIcenowy Zheng
6539934aba4SIcenowy Zheng #define SUN50I_A64_DX_READ_DELAYS \
6549934aba4SIcenowy Zheng {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \
6559934aba4SIcenowy Zheng { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \
6569934aba4SIcenowy Zheng { 16, 17, 17, 16, 16, 16, 16, 16, 16, 0, 0 }, \
6579934aba4SIcenowy Zheng { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }}
6589934aba4SIcenowy Zheng #define SUN50I_A64_DX_WRITE_DELAYS \
6599934aba4SIcenowy Zheng {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15 }, \
6609934aba4SIcenowy Zheng { 0, 0, 0, 0, 1, 1, 1, 1, 0, 10, 10 }, \
6619934aba4SIcenowy Zheng { 1, 0, 1, 1, 1, 1, 1, 1, 0, 11, 11 }, \
6629934aba4SIcenowy Zheng { 1, 0, 0, 1, 1, 1, 1, 1, 0, 12, 12 }}
6639934aba4SIcenowy Zheng #define SUN50I_A64_AC_DELAYS \
6649934aba4SIcenowy Zheng { 5, 5, 13, 10, 2, 5, 3, 3, \
6659934aba4SIcenowy Zheng 0, 3, 3, 3, 1, 0, 0, 0, \
6669934aba4SIcenowy Zheng 3, 4, 0, 3, 4, 1, 4, 0, \
6679934aba4SIcenowy Zheng 1, 1, 0, 1, 13, 5, 4 }
6689934aba4SIcenowy Zheng
6699934aba4SIcenowy Zheng #define SUN8I_H5_DX_READ_DELAYS \
6709934aba4SIcenowy Zheng {{ 14, 15, 17, 17, 17, 17, 17, 18, 17, 3, 3 }, \
6719934aba4SIcenowy Zheng { 21, 21, 12, 22, 21, 21, 21, 21, 21, 3, 3 }, \
6729934aba4SIcenowy Zheng { 16, 19, 19, 17, 22, 22, 21, 22, 19, 3, 3 }, \
6739934aba4SIcenowy Zheng { 21, 21, 22, 22, 20, 21, 19, 19, 19, 3, 3 } }
6749934aba4SIcenowy Zheng #define SUN8I_H5_DX_WRITE_DELAYS \
6759934aba4SIcenowy Zheng {{ 1, 2, 3, 4, 3, 4, 4, 4, 6, 6, 6 }, \
6769934aba4SIcenowy Zheng { 6, 6, 6, 5, 5, 5, 5, 5, 6, 6, 6 }, \
6779934aba4SIcenowy Zheng { 0, 2, 4, 2, 6, 5, 5, 5, 6, 6, 6 }, \
6789934aba4SIcenowy Zheng { 3, 3, 3, 2, 2, 1, 1, 1, 4, 4, 4 } }
6799934aba4SIcenowy Zheng #define SUN8I_H5_AC_DELAYS \
6809934aba4SIcenowy Zheng { 0, 0, 5, 5, 0, 0, 0, 0, \
6819934aba4SIcenowy Zheng 0, 0, 0, 0, 3, 3, 3, 3, \
6829934aba4SIcenowy Zheng 3, 3, 3, 3, 3, 3, 3, 3, \
6839934aba4SIcenowy Zheng 3, 3, 3, 3, 2, 0, 0 }
6849934aba4SIcenowy Zheng
sunxi_dram_init(void)6859934aba4SIcenowy Zheng unsigned long sunxi_dram_init(void)
6869934aba4SIcenowy Zheng {
6879934aba4SIcenowy Zheng struct sunxi_mctl_com_reg * const mctl_com =
6889934aba4SIcenowy Zheng (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
6899934aba4SIcenowy Zheng struct sunxi_mctl_ctl_reg * const mctl_ctl =
6909934aba4SIcenowy Zheng (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
6919934aba4SIcenowy Zheng
6929934aba4SIcenowy Zheng struct dram_para para = {
693176868bcSIcenowy Zheng .dual_rank = 1,
694f43a0099SIcenowy Zheng .bus_full_width = 1,
6959934aba4SIcenowy Zheng .row_bits = 15,
69666b12526SIcenowy Zheng .bank_bits = 3,
6979934aba4SIcenowy Zheng .page_size = 4096,
6989934aba4SIcenowy Zheng
6999934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
7009934aba4SIcenowy Zheng .dx_read_delays = SUN8I_H3_DX_READ_DELAYS,
7019934aba4SIcenowy Zheng .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
7029934aba4SIcenowy Zheng .ac_delays = SUN8I_H3_AC_DELAYS,
7039934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
7049934aba4SIcenowy Zheng .dx_read_delays = SUN8I_R40_DX_READ_DELAYS,
7059934aba4SIcenowy Zheng .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS,
7069934aba4SIcenowy Zheng .ac_delays = SUN8I_R40_AC_DELAYS,
7079934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
7089934aba4SIcenowy Zheng .dx_read_delays = SUN50I_A64_DX_READ_DELAYS,
7099934aba4SIcenowy Zheng .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
7109934aba4SIcenowy Zheng .ac_delays = SUN50I_A64_AC_DELAYS,
7119934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
7129934aba4SIcenowy Zheng .dx_read_delays = SUN8I_H5_DX_READ_DELAYS,
7139934aba4SIcenowy Zheng .dx_write_delays = SUN8I_H5_DX_WRITE_DELAYS,
7149934aba4SIcenowy Zheng .ac_delays = SUN8I_H5_AC_DELAYS,
7159934aba4SIcenowy Zheng #endif
7169934aba4SIcenowy Zheng };
7179934aba4SIcenowy Zheng /*
7189934aba4SIcenowy Zheng * Let the compiler optimize alternatives away by passing this value into
7199934aba4SIcenowy Zheng * the static functions. This saves us #ifdefs, but still keeps the binary
7209934aba4SIcenowy Zheng * small.
7219934aba4SIcenowy Zheng */
7229934aba4SIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_H3)
7239934aba4SIcenowy Zheng uint16_t socid = SOCID_H3;
7249934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_R40)
7259934aba4SIcenowy Zheng uint16_t socid = SOCID_R40;
726176868bcSIcenowy Zheng /* Currently we cannot support R40 with dual rank memory */
727176868bcSIcenowy Zheng para.dual_rank = 0;
7283ec0698bSIcenowy Zheng #elif defined(CONFIG_MACH_SUN8I_V3S)
7293ec0698bSIcenowy Zheng /* TODO: set delays and mbus priority for V3s */
7303ec0698bSIcenowy Zheng uint16_t socid = SOCID_H3;
7319934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I)
7329934aba4SIcenowy Zheng uint16_t socid = SOCID_A64;
7339934aba4SIcenowy Zheng #elif defined(CONFIG_MACH_SUN50I_H5)
7349934aba4SIcenowy Zheng uint16_t socid = SOCID_H5;
7359934aba4SIcenowy Zheng #endif
7369934aba4SIcenowy Zheng
7379934aba4SIcenowy Zheng mctl_sys_init(socid, ¶);
7389934aba4SIcenowy Zheng if (mctl_channel_init(socid, ¶))
7399934aba4SIcenowy Zheng return 0;
7409934aba4SIcenowy Zheng
7419934aba4SIcenowy Zheng if (para.dual_rank)
7429934aba4SIcenowy Zheng writel(0x00000303, &mctl_ctl->odtmap);
7439934aba4SIcenowy Zheng else
7449934aba4SIcenowy Zheng writel(0x00000201, &mctl_ctl->odtmap);
7459934aba4SIcenowy Zheng udelay(1);
7469934aba4SIcenowy Zheng
7479934aba4SIcenowy Zheng /* odt delay */
7489934aba4SIcenowy Zheng if (socid == SOCID_H3)
7499934aba4SIcenowy Zheng writel(0x0c000400, &mctl_ctl->odtcfg);
7509934aba4SIcenowy Zheng
7519934aba4SIcenowy Zheng if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) {
7529934aba4SIcenowy Zheng /* VTF enable (tpr13[8] == 1) */
7539934aba4SIcenowy Zheng setbits_le32(&mctl_ctl->vtfcr,
7549934aba4SIcenowy Zheng (socid != SOCID_A64 ? 3 : 2) << 8);
7559934aba4SIcenowy Zheng /* DQ hold disable (tpr13[26] == 1) */
7569934aba4SIcenowy Zheng clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
7579934aba4SIcenowy Zheng }
7589934aba4SIcenowy Zheng
7599934aba4SIcenowy Zheng /* clear credit value */
7609934aba4SIcenowy Zheng setbits_le32(&mctl_com->cccr, 1 << 31);
7619934aba4SIcenowy Zheng udelay(10);
7629934aba4SIcenowy Zheng
7639934aba4SIcenowy Zheng mctl_auto_detect_dram_size(socid, ¶);
7649934aba4SIcenowy Zheng mctl_set_cr(socid, ¶);
7659934aba4SIcenowy Zheng
76666b12526SIcenowy Zheng return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
7679934aba4SIcenowy Zheng (para.dual_rank ? 2 : 1);
7689934aba4SIcenowy Zheng }
769