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