Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Originally checked out from: https://github.com/smaeul/u-boot/commits/d1-wip */
- /* Modified using: https://github.com/YuzukiHD/SyterKit/blob/main/src/drivers/chips/sun20iw1/sys-dram.c#L1066 */
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Allwinner D1/D1s/R528/T113-sx DRAM initialisation
- *
- * As usual there is no documentation for the memory controller or PHY IP
- * used here. The baseline of this code was lifted from awboot[1], which
- * seems to be based on some form of de-compilation of some original Allwinner
- * code bits (with a GPL2 license tag from the very beginning).
- * This version here is a reworked version, to match the U-Boot coding style
- * and style of the other Allwinner DRAM drivers.
- *
- * [1] https://github.com/szemzoa/awboot.git
- */
- #define CONFIG_DRAM_CLK 528
- #define CONFIG_DRAM_ZQ 0x007b7bf9
- #define readl rv_readl
- #define writel rv_writel
- #include <asm/io.h>
- #undef readl
- #undef writel
- #define readl(x) rv_readl((const volatile void __iomem *)(u64)(x))
- #define writel(v, x) rv_writel(v, (volatile void __iomem *)(u64)(x))
- #include <common.h>
- #ifdef CONFIG_RAM
- #include <dm.h>
- #include <ram.h>
- #endif
- #include <linux/delay.h>
- #include "dram_sun20i_d1.h"
- #ifndef SUNXI_SID_BASE
- #define SUNXI_SID_BASE 0x3006200
- #endif
- #ifndef SUNXI_CCM_BASE
- #define SUNXI_CCM_BASE 0x2001000
- #endif
- #ifdef debug
- #undef debug
- #endif
- #define debug(...) printf(__VA_ARGS__)
- static void sid_read_ldoB_cal(const dram_para_t *para)
- {
- uint32_t reg;
- reg = (readl(SUNXI_SID_BASE + 0x1c) & 0xff00) >> 8;
- if (reg == 0)
- return;
- switch (para->dram_type) {
- case SUNXI_DRAM_TYPE_DDR2:
- break;
- case SUNXI_DRAM_TYPE_DDR3:
- if (reg > 0x20)
- reg -= 0x16;
- break;
- default:
- reg = 0;
- break;
- }
- clrsetbits_le32(0x3000150, 0xff00, reg << 8);
- }
- static void dram_voltage_set(const dram_para_t *para)
- {
- int vol;
- switch (para->dram_type) {
- case SUNXI_DRAM_TYPE_DDR2:
- vol = 47;
- break;
- case SUNXI_DRAM_TYPE_DDR3:
- vol = 25;
- break;
- default:
- vol = 0;
- break;
- }
- clrsetbits_le32(0x3000150, 0x20ff00, vol << 8);
- udelay(1);
- sid_read_ldoB_cal(para);
- }
- static void dram_enable_all_master(void)
- {
- writel(~0, 0x3102020);
- writel(0xff, 0x3102024);
- writel(0xffff, 0x3102028);
- udelay(10);
- }
- static void dram_disable_all_master(void)
- {
- writel(1, 0x3102020);
- writel(0, 0x3102024);
- writel(0, 0x3102028);
- udelay(10);
- }
- static void eye_delay_compensation(const dram_para_t *para)
- {
- uint32_t delay;
- unsigned long ptr;
- // DATn0IOCR, n = 0...7
- delay = (para->dram_tpr11 & 0xf) << 9;
- delay |= (para->dram_tpr12 & 0xf) << 1;
- for (ptr = 0x3103310; ptr < 0x3103334; ptr += 4)
- setbits_le32(ptr, delay);
- // DATn1IOCR, n = 0...7
- delay = (para->dram_tpr11 & 0xf0) << 5;
- delay |= (para->dram_tpr12 & 0xf0) >> 3;
- for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4)
- setbits_le32(ptr, delay);
- // PGCR0: assert AC loopback FIFO reset
- clrbits_le32(0x3103100, 0x04000000);
- // ??
- delay = (para->dram_tpr11 & 0xf0000) >> 7;
- delay |= (para->dram_tpr12 & 0xf0000) >> 15;
- setbits_le32(0x3103334, delay);
- setbits_le32(0x3103338, delay);
- delay = (para->dram_tpr11 & 0xf00000) >> 11;
- delay |= (para->dram_tpr12 & 0xf00000) >> 19;
- setbits_le32(0x31033b4, delay);
- setbits_le32(0x31033b8, delay);
- setbits_le32(0x310333c, (para->dram_tpr11 & 0xf0000) << 9);
- setbits_le32(0x31033bc, (para->dram_tpr11 & 0xf00000) << 5);
- // PGCR0: release AC loopback FIFO reset
- setbits_le32(0x3103100, BIT(26));
- udelay(1);
- delay = (para->dram_tpr10 & 0xf0) << 4;
- for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4)
- setbits_le32(ptr, delay);
- for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4)
- setbits_le32(ptr, delay);
- setbits_le32(0x3103218, (para->dram_tpr10 & 0x0f) << 8);
- setbits_le32(0x310321c, (para->dram_tpr10 & 0x0f) << 8);
- setbits_le32(0x3103280, (para->dram_tpr10 & 0xf00) >> 4);
- }
- /*
- * Main purpose of the auto_set_timing routine seems to be to calculate all
- * timing settings for the specific type of sdram used. Read together with
- * an sdram datasheet for context on the various variables.
- */
- static void mctl_set_timing_params(const dram_para_t *para,
- const dram_config_t *config)
- {
- /* DRAM_TPR0 */
- u8 tccd = 2;
- u8 tfaw;
- u8 trrd;
- u8 trcd;
- u8 trc;
- /* DRAM_TPR1 */
- u8 txp;
- u8 twtr;
- u8 trtp = 4;
- u8 twr;
- u8 trp;
- u8 tras;
- /* DRAM_TPR2 */
- u16 trefi;
- u16 trfc;
- u8 tcksrx;
- u8 tckesr;
- u8 trd2wr;
- u8 twr2rd;
- u8 trasmax;
- u8 twtp;
- u8 tcke;
- u8 tmod;
- u8 tmrd;
- u8 tmrw;
- u8 tcl;
- u8 tcwl;
- u8 t_rdata_en;
- u8 wr_latency;
- u32 mr0;
- u32 mr1;
- u32 mr2;
- u32 mr3;
- u32 tdinit0;
- u32 tdinit1;
- u32 tdinit2;
- u32 tdinit3;
- switch (para->dram_type) {
- case SUNXI_DRAM_TYPE_DDR2:
- /* DRAM_TPR0 */
- tfaw = ns_to_t(50);
- trrd = ns_to_t(10);
- trcd = ns_to_t(20);
- trc = ns_to_t(65);
- /* DRAM_TPR1 */
- txp = 2;
- twtr = ns_to_t(8);
- twr = ns_to_t(15);
- trp = ns_to_t(15);
- tras = ns_to_t(45);
- /* DRAM_TRP2 */
- trfc = ns_to_t(328);
- trefi = ns_to_t(7800) / 32;
- trasmax = CONFIG_DRAM_CLK / 30;
- if (CONFIG_DRAM_CLK < 409) {
- t_rdata_en = 1;
- tcl = 3;
- mr0 = 0x06a3;
- } else {
- t_rdata_en = 2;
- tcl = 4;
- mr0 = 0x0e73;
- }
- tmrd = 2;
- twtp = twr + 5;
- tcksrx = 5;
- tckesr = 4;
- trd2wr = 4;
- tcke = 3;
- tmod = 12;
- wr_latency = 1;
- tmrw = 0;
- twr2rd = twtr + 5;
- tcwl = 0;
- mr1 = para->dram_mr1;
- mr2 = 0;
- mr3 = 0;
- tdinit0 = 200 * CONFIG_DRAM_CLK + 1;
- tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1;
- tdinit2 = 200 * CONFIG_DRAM_CLK + 1;
- tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
- break;
- case SUNXI_DRAM_TYPE_DDR3:
- trfc = ns_to_t(350);
- trefi = ns_to_t(7800) / 32 + 1; // XXX
- twtr = ns_to_t(8) + 2; // + 2 ? XXX
- /* Only used by trd2wr calculation, which gets discard below */
- // twr = max(ns_to_t(15), 2);
- trrd = max(ns_to_t(10), 2);
- txp = max(ns_to_t(10), 2);
- if (CONFIG_DRAM_CLK <= 800) {
- tfaw = ns_to_t(50);
- trcd = ns_to_t(15);
- trp = ns_to_t(15);
- trc = ns_to_t(53);
- tras = ns_to_t(38);
- mr0 = 0x1c70;
- mr2 = 0x18;
- tcl = 6;
- wr_latency = 2;
- tcwl = 4;
- t_rdata_en = 4;
- } else {
- tfaw = ns_to_t(35);
- trcd = ns_to_t(14);
- trp = ns_to_t(14);
- trc = ns_to_t(48);
- tras = ns_to_t(34);
- mr0 = 0x1e14;
- mr2 = 0x20;
- tcl = 7;
- wr_latency = 3;
- tcwl = 5;
- t_rdata_en = 5;
- }
- trasmax = CONFIG_DRAM_CLK / 30;
- twtp = tcwl + 2 + twtr; // WL+BL/2+tWTR
- /* Gets overwritten below */
- // trd2wr = tcwl + 2 + twr; // WL+BL/2+tWR
- twr2rd = tcwl + twtr; // WL+tWTR
- tdinit0 = 500 * CONFIG_DRAM_CLK + 1; // 500 us
- tdinit1 = 360 * CONFIG_DRAM_CLK / 1000 + 1; // 360 ns
- tdinit2 = 200 * CONFIG_DRAM_CLK + 1; // 200 us
- tdinit3 = 1 * CONFIG_DRAM_CLK + 1; // 1 us
- mr1 = para->dram_mr1;
- mr3 = 0;
- tcke = 3;
- tcksrx = 5;
- tckesr = 4;
- if (((config->dram_tpr13 & 0xc) == 0x04) || CONFIG_DRAM_CLK < 912)
- trd2wr = 5;
- else
- trd2wr = 6;
- tmod = 12;
- tmrd = 4;
- tmrw = 0;
- break;
- case SUNXI_DRAM_TYPE_LPDDR2:
- tfaw = max(ns_to_t(50), 4);
- trrd = max(ns_to_t(10), 1);
- trcd = max(ns_to_t(24), 2);
- trc = ns_to_t(70);
- txp = ns_to_t(8);
- if (txp < 2) {
- txp++;
- twtr = 2;
- } else {
- twtr = txp;
- }
- twr = max(ns_to_t(15), 2);
- trp = ns_to_t(17);
- tras = ns_to_t(42);
- trefi = ns_to_t(3900) / 32;
- trfc = ns_to_t(210);
- trasmax = CONFIG_DRAM_CLK / 60;
- mr3 = para->dram_mr3;
- twtp = twr + 5;
- mr2 = 6;
- mr1 = 5;
- tcksrx = 5;
- tckesr = 5;
- trd2wr = 10;
- tcke = 2;
- tmod = 5;
- tmrd = 5;
- tmrw = 3;
- tcl = 4;
- wr_latency = 1;
- t_rdata_en = 1;
- tdinit0 = 200 * CONFIG_DRAM_CLK + 1;
- tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1;
- tdinit2 = 11 * CONFIG_DRAM_CLK + 1;
- tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
- twr2rd = twtr + 5;
- tcwl = 2;
- mr1 = 195;
- mr0 = 0;
- break;
- case SUNXI_DRAM_TYPE_LPDDR3:
- tfaw = max(ns_to_t(50), 4);
- trrd = max(ns_to_t(10), 1);
- trcd = max(ns_to_t(24), 2);
- trc = ns_to_t(70);
- twtr = max(ns_to_t(8), 2);
- twr = max(ns_to_t(15), 2);
- trp = ns_to_t(17);
- tras = ns_to_t(42);
- trefi = ns_to_t(3900) / 32;
- trfc = ns_to_t(210);
- txp = twtr;
- trasmax = CONFIG_DRAM_CLK / 60;
- if (CONFIG_DRAM_CLK < 800) {
- tcwl = 4;
- wr_latency = 3;
- t_rdata_en = 6;
- mr2 = 12;
- } else {
- tcwl = 3;
- tcke = 6;
- wr_latency = 2;
- t_rdata_en = 5;
- mr2 = 10;
- }
- twtp = tcwl + 5;
- tcl = 7;
- mr3 = para->dram_mr3;
- tcksrx = 5;
- tckesr = 5;
- trd2wr = 13;
- tcke = 3;
- tmod = 12;
- tdinit0 = 400 * CONFIG_DRAM_CLK + 1;
- tdinit1 = 500 * CONFIG_DRAM_CLK / 1000 + 1;
- tdinit2 = 11 * CONFIG_DRAM_CLK + 1;
- tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
- tmrd = 5;
- tmrw = 5;
- twr2rd = tcwl + twtr + 5;
- mr1 = 195;
- mr0 = 0;
- break;
- default:
- trfc = 128;
- trp = 6;
- trefi = 98;
- txp = 10;
- twr = 8;
- twtr = 3;
- tras = 14;
- tfaw = 16;
- trc = 20;
- trcd = 6;
- trrd = 3;
- twr2rd = 8;
- tcksrx = 4;
- tckesr = 3;
- trd2wr = 4;
- trasmax = 27;
- twtp = 12;
- tcke = 2;
- tmod = 6;
- tmrd = 2;
- tmrw = 0;
- tcwl = 3;
- tcl = 3;
- wr_latency = 1;
- t_rdata_en = 1;
- mr3 = 0;
- mr2 = 0;
- mr1 = 0;
- mr0 = 0;
- tdinit3 = 0;
- tdinit2 = 0;
- tdinit1 = 0;
- tdinit0 = 0;
- break;
- }
- /* Set mode registers */
- writel(mr0, 0x3103030);
- writel(mr1, 0x3103034);
- writel(mr2, 0x3103038);
- writel(mr3, 0x310303c);
- /* TODO: dram_odt_en is either 0x0 or 0x1, so right shift looks weird */
- writel((para->dram_odt_en >> 4) & 0x3, 0x310302c);
- /* Set dram timing DRAMTMG0 - DRAMTMG5 */
- writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0),
- 0x3103058);
- writel((txp << 16) | (trtp << 8) | (trc << 0),
- 0x310305c);
- writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0),
- 0x3103060);
- writel((tmrw << 16) | (tmrd << 12) | (tmod << 0),
- 0x3103064);
- writel((trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0),
- 0x3103068);
- writel((tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0),
- 0x310306c);
- /* Set dual rank timing */
- clrsetbits_le32(0x3103078, 0xf000ffff,
- (CONFIG_DRAM_CLK < 800) ? 0xf0006610 : 0xf0007610);
- /* Set phy interface time PITMG0, PTR3, PTR4 */
- writel((0x2 << 24) | (t_rdata_en << 16) | BIT(8) | (wr_latency << 0),
- 0x3103080);
- writel(((tdinit0 << 0) | (tdinit1 << 20)), 0x3103050);
- writel(((tdinit2 << 0) | (tdinit3 << 20)), 0x3103054);
- /* Set refresh timing and mode */
- writel((trefi << 16) | (trfc << 0), 0x3103090);
- writel((trefi << 15) & 0x0fff0000, 0x3103094);
- }
- // Purpose of this routine seems to be to initialize the PLL driving
- // the MBUS and sdram.
- //
- static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para,
- const dram_config_t *config)
- {
- unsigned int val, clk, n;
- if (config->dram_tpr13 & BIT(6))
- clk = para->dram_tpr9;
- else
- clk = para->dram_clk;
- // set VCO clock divider
- n = (clk * 2) / 24;
- val = readl(SUNXI_CCM_BASE + 0x10);
- val &= ~0x0007ff03; // clear dividers
- val |= (n - 1) << 8; // set PLL division
- val |= BIT(31) | BIT(30); // enable PLL and LDO
- writel(val | BIT(29), SUNXI_CCM_BASE + 0x10);
- // wait for PLL to lock
- while ((readl(SUNXI_CCM_BASE + 0x10) & BIT(28)) == 0)
- ;
- udelay(20);
- // enable PLL output
- setbits_le32(SUNXI_CCM_BASE + 0x0, BIT(27));
- // turn clock gate on
- val = readl(SUNXI_CCM_BASE + 0x800);
- val &= ~0x03000303; // select DDR clk source, n=1, m=1
- val |= BIT(31); // turn clock on
- writel(val, SUNXI_CCM_BASE + 0x800);
- return n * 24;
- }
- /* Set up the PLL and clock gates for the DRAM controller and MBUS clocks. */
- static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
- {
- // assert MBUS reset
- clrbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
- // turn off sdram clock gate, assert sdram reset
- clrbits_le32(SUNXI_CCM_BASE + 0x80c, 0x10001);
- clrsetbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(30), BIT(27));
- udelay(10);
- // set ddr pll clock
- ccu_set_pll_ddr_clk(0, para, config);
- udelay(100);
- dram_disable_all_master();
- // release sdram reset
- setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(16));
- // release MBUS reset
- setbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
- setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(30));
- udelay(5);
- // turn on sdram clock gate
- setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(0));
- // turn dram clock gate on, trigger sdr clock update
- setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(27));
- udelay(5);
- // mCTL clock enable
- writel(0x8000, 0x310300c);
- udelay(10);
- }
- // The main purpose of this routine seems to be to copy an address configuration
- // from the dram_para1 and dram_para2 fields to the PHY configuration registers
- // (0x3102000, 0x3102004).
- //
- static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
- {
- uint32_t val, width;
- unsigned long ptr;
- int i;
- // purpose ??
- clrsetbits_le32(0x3102008, 0x3f00, 0x2000);
- // set SDRAM type and word width
- val = readl(0x3102000) & ~0x00fff000;
- val |= (para->dram_type & 0x7) << 16; // DRAM type
- val |= (~config->dram_para2 & 0x1) << 12; // DQ width
- val |= BIT(22); // ??
- if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
- para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
- val |= BIT(19); // type 6 and 7 must use 1T
- } else {
- if (config->dram_tpr13 & BIT(5))
- val |= BIT(19);
- }
- writel(val, 0x3102000);
- // init rank / bank / row for single/dual or two different ranks
- if ((config->dram_para2 & BIT(8)) &&
- ((config->dram_para2 & 0xf000) != 0x1000))
- width = 32;
- else
- width = 16;
- ptr = 0x3102000;
- for (i = 0; i < width; i += 16) {
- val = readl(ptr) & 0xfffff000;
- val |= (config->dram_para2 >> 12) & 0x3; // rank
- val |= ((config->dram_para1 >> (i + 12)) << 2) & 0x4; // bank - 2
- val |= (((config->dram_para1 >> (i + 4)) - 1) << 4) & 0xff; // row - 1
- // convert from page size to column addr width - 3
- switch ((config->dram_para1 >> i) & 0xf) {
- case 8: val |= 0xa00; break;
- case 4: val |= 0x900; break;
- case 2: val |= 0x800; break;
- case 1: val |= 0x700; break;
- default: val |= 0x600; break;
- }
- writel(val, ptr);
- ptr += 4;
- }
- // set ODTMAP based on number of ranks in use
- val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201;
- writel(val, 0x3103120);
- // set mctl reg 3c4 to zero when using half DQ
- if (config->dram_para2 & BIT(0))
- writel(0, 0x31033c4);
- // purpose ??
- if (para->dram_tpr4) {
- setbits_le32(0x3102000, (para->dram_tpr4 & 0x3) << 25);
- setbits_le32(0x3102004, (para->dram_tpr4 & 0x7fc) << 10);
- }
- }
- static const uint8_t ac_remapping_tables[][22] = {
- [0] = { 0 },
- [1] = { 1, 9, 3, 7, 8, 18, 4, 13, 5, 6, 10,
- 2, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 },
- [2] = { 4, 9, 3, 7, 8, 18, 1, 13, 2, 6, 10,
- 5, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 },
- [3] = { 1, 7, 8, 12, 10, 18, 4, 13, 5, 6, 3,
- 2, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 },
- [4] = { 4, 12, 10, 7, 8, 18, 1, 13, 2, 6, 3,
- 5, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 },
- [5] = { 13, 2, 7, 9, 12, 19, 5, 1, 6, 3, 4,
- 8, 10, 0, 0, 0, 21, 22, 18, 17, 11, 20 },
- [6] = { 3, 10, 7, 13, 9, 11, 1, 2, 4, 6, 8,
- 5, 12, 0, 0, 0, 20, 1, 0, 21, 22, 17 },
- [7] = { 3, 2, 4, 7, 9, 1, 17, 12, 18, 14, 13,
- 8, 15, 6, 10, 5, 19, 22, 16, 21, 20, 11 },
- };
- /*
- * This routine chooses one of several remapping tables for 22 lines.
- * It is unclear which lines are being remapped. It seems to pick
- * table cfg7 for the Nezha board.
- */
- static void mctl_phy_ac_remapping(const dram_para_t *para,
- const dram_config_t *config)
- {
- const uint8_t *cfg;
- uint32_t fuse, val;
- /*
- * It is unclear whether the LPDDRx types don't need any remapping,
- * or whether the original code just didn't provide tables.
- */
- if (para->dram_type != SUNXI_DRAM_TYPE_DDR2 &&
- para->dram_type != SUNXI_DRAM_TYPE_DDR3)
- return;
- fuse = (readl(SUNXI_SID_BASE + 0x28) & 0xf00) >> 8;
- debug("DDR efuse: 0x%x\n", fuse);
- if (para->dram_type == SUNXI_DRAM_TYPE_DDR2) {
- if (fuse == 15 || fuse == 10)
- return;
- cfg = ac_remapping_tables[6];
- } else {
- if (config->dram_tpr13 & 0xc0000) {
- cfg = ac_remapping_tables[7];
- } else {
- switch (fuse) {
- case 8: cfg = ac_remapping_tables[2]; break;
- case 9: cfg = ac_remapping_tables[3]; break;
- case 10: cfg = ac_remapping_tables[5]; break;
- case 11: cfg = ac_remapping_tables[4]; break;
- default:
- case 12: cfg = ac_remapping_tables[1]; break;
- case 13:
- case 14: cfg = ac_remapping_tables[0]; break;
- }
- }
- }
- val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
- (cfg[1] << 10) | (cfg[0] << 5);
- writel(val, 0x3102500);
- val = (cfg[10] << 25) | (cfg[9] << 20) | (cfg[8] << 15) |
- (cfg[ 7] << 10) | (cfg[6] << 5) | cfg[5];
- writel(val, 0x3102504);
- val = (cfg[15] << 20) | (cfg[14] << 15) | (cfg[13] << 10) |
- (cfg[12] << 5) | cfg[11];
- writel(val, 0x3102508);
- val = (cfg[21] << 25) | (cfg[20] << 20) | (cfg[19] << 15) |
- (cfg[18] << 10) | (cfg[17] << 5) | cfg[16];
- writel(val, 0x310250c);
- val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
- (cfg[1] << 10) | (cfg[0] << 5) | 1;
- writel(val, 0x3102500);
- }
- // Init the controller channel. The key part is placing commands in the main
- // command register (PIR, 0x3103000) and checking command status (PGSR0, 0x3103010).
- //
- static unsigned int mctl_channel_init(unsigned int ch_index,
- const dram_para_t *para,
- const dram_config_t *config)
- {
- unsigned int val, dqs_gating_mode;
- dqs_gating_mode = (config->dram_tpr13 & 0xc) >> 2;
- // set DDR clock to half of CPU clock
- clrsetbits_le32(0x310200c, 0xfff, (para->dram_clk / 2) - 1);
- // MRCTRL0 nibble 3 undocumented
- clrsetbits_le32(0x3103108, 0xf00, 0x300);
- if (para->dram_odt_en)
- val = 0;
- else
- val = BIT(5);
- // DX0GCR0
- if (para->dram_clk > 672)
- clrsetbits_le32(0x3103344, 0xf63e, val);
- else
- clrsetbits_le32(0x3103344, 0xf03e, val);
- // DX1GCR0
- if (para->dram_clk > 672) {
- setbits_le32(0x3103344, 0x400);
- clrsetbits_le32(0x31033c4, 0xf63e, val);
- } else {
- clrsetbits_le32(0x31033c4, 0xf03e, val);
- }
- // 0x3103208 undocumented
- setbits_le32(0x3103208, BIT(1));
- eye_delay_compensation(para);
- // set PLL SSCG ?
- val = readl(0x3103108);
- if (dqs_gating_mode == 1) {
- clrsetbits_le32(0x3103108, 0xc0, 0);
- clrbits_le32(0x31030bc, 0x107);
- } else if (dqs_gating_mode == 2) {
- clrsetbits_le32(0x3103108, 0xc0, 0x80);
- clrsetbits_le32(0x31030bc, 0x107,
- (((config->dram_tpr13 >> 16) & 0x1f) - 2) | 0x100);
- clrsetbits_le32(0x310311c, BIT(31), BIT(27));
- } else {
- clrbits_le32(0x3103108, 0x40);
- udelay(10);
- setbits_le32(0x3103108, 0xc0);
- }
- if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
- para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
- if (dqs_gating_mode == 1)
- clrsetbits_le32(0x310311c, 0x080000c0, 0x80000000);
- else
- clrsetbits_le32(0x310311c, 0x77000000, 0x22000000);
- }
- clrsetbits_le32(0x31030c0, 0x0fffffff,
- (config->dram_para2 & BIT(12)) ? 0x03000001 : 0x01000007);
- if (readl(0x70005d4) & BIT(16)) {
- clrbits_le32(0x7010250, 0x2);
- udelay(10);
- }
- // Set ZQ config
- clrsetbits_le32(0x3103140, 0x3ffffff,
- (para->dram_zq & 0x00ffffff) | BIT(25));
- // Initialise DRAM controller
- if (dqs_gating_mode == 1) {
- //writel(0x52, 0x3103000); // prep PHY reset + PLL init + z-cal
- writel(0x53, 0x3103000); // Go
- while ((readl(0x3103010) & 0x1) == 0) {
- } // wait for IDONE
- udelay(10);
- // 0x520 = prep DQS gating + DRAM init + d-cal
- if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
- writel(0x5a0, 0x3103000); // + DRAM reset
- else
- writel(0x520, 0x3103000);
- } else {
- if ((readl(0x70005d4) & (1 << 16)) == 0) {
- // prep DRAM init + PHY reset + d-cal + PLL init + z-cal
- if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
- writel(0x1f2, 0x3103000); // + DRAM reset
- else
- writel(0x172, 0x3103000);
- } else {
- // prep PHY reset + d-cal + z-cal
- writel(0x62, 0x3103000);
- }
- }
- setbits_le32(0x3103000, 0x1); // GO
- udelay(10);
- while ((readl(0x3103010) & 0x1) == 0) {
- } // wait for IDONE
- if (readl(0x70005d4) & BIT(16)) {
- clrsetbits_le32(0x310310c, 0x06000000, 0x04000000);
- udelay(10);
- setbits_le32(0x3103004, 0x1);
- while ((readl(0x3103018) & 0x7) != 0x3) {
- }
- clrbits_le32(0x7010250, 0x1);
- udelay(10);
- clrbits_le32(0x3103004, 0x1);
- while ((readl(0x3103018) & 0x7) != 0x1) {
- }
- udelay(15);
- if (dqs_gating_mode == 1) {
- clrbits_le32(0x3103108, 0xc0);
- clrsetbits_le32(0x310310c, 0x06000000, 0x02000000);
- udelay(1);
- writel(0x401, 0x3103000);
- while ((readl(0x3103010) & 0x1) == 0) {
- }
- }
- }
- // Check for training error
- if (readl(0x3103010) & BIT(20)) {
- printf("ZQ calibration error, check external 240 ohm resistor\n");
- return 0;
- }
- // STATR = Zynq STAT? Wait for status 'normal'?
- while ((readl(0x3103018) & 0x1) == 0) {
- }
- setbits_le32(0x310308c, BIT(31));
- udelay(10);
- clrbits_le32(0x310308c, BIT(31));
- udelay(10);
- setbits_le32(0x3102014, BIT(31));
- udelay(10);
- clrbits_le32(0x310310c, 0x06000000);
- if (dqs_gating_mode == 1)
- clrsetbits_le32(0x310311c, 0xc0, 0x40);
- return 1;
- }
- static unsigned int calculate_rank_size(uint32_t regval)
- {
- unsigned int bits;
- bits = (regval >> 8) & 0xf; /* page size - 3 */
- bits += (regval >> 4) & 0xf; /* row width - 1 */
- bits += (regval >> 2) & 0x3; /* bank count - 2 */
- bits -= 14; /* 1MB = 20 bits, minus above 6 = 14 */
- return 1U << bits;
- }
- /*
- * The below routine reads the dram config registers and extracts
- * the number of address bits in each rank available. It then calculates
- * total memory size in MB.
- */
- static unsigned int DRAMC_get_dram_size(void)
- {
- uint32_t val;
- unsigned int size;
- val = readl(0x3102000); /* MC_WORK_MODE0 */
- size = calculate_rank_size(val);
- if ((val & 0x3) == 0) /* single rank? */
- return size;
- val = readl(0x3102004); /* MC_WORK_MODE1 */
- if ((val & 0x3) == 0) /* two identical ranks? */
- return size * 2;
- /* add sizes of both ranks */
- return size + calculate_rank_size(val);
- }
- /*
- * The below routine reads the command status register to extract
- * DQ width and rank count. This follows the DQS training command in
- * channel_init. If error bit 22 is reset, we have two ranks and full DQ.
- * If there was an error, figure out whether it was half DQ, single rank,
- * or both. Set bit 12 and 0 in dram_para2 with the results.
- */
- static int dqs_gate_detect(dram_config_t *config)
- {
- uint32_t dx0, dx1;
- if ((readl(0x3103010) & BIT(22)) == 0) {
- config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
- printf("dual rank and full DQ\n");
- return 1;
- }
- dx0 = (readl(0x3103348) & 0x3000000) >> 24;
- if (dx0 == 0) {
- config->dram_para2 = (config->dram_para2 & ~0xf) | 0x1001;
- printf("dual rank and half DQ\n");
- return 1;
- }
- if (dx0 == 2) {
- dx1 = (readl(0x31033c8) & 0x3000000) >> 24;
- if (dx1 == 2) {
- config->dram_para2 = config->dram_para2 & ~0xf00f;
- printf("single rank and full DQ\n");
- } else {
- config->dram_para2 = (config->dram_para2 & ~0xf00f) | BIT(0);
- printf("single rank and half DQ\n");
- }
- return 1;
- }
- if ((config->dram_tpr13 & BIT(29)) == 0)
- return 0;
- printf("DX0 state: %d\n", dx0);
- printf("DX1 state: %d\n", dx1);
- return 0;
- }
- static int dramc_simple_wr_test(unsigned int mem_mb, int len)
- {
- unsigned int offs = (mem_mb / 2) << 18; // half of memory size
- unsigned int patt1 = 0x01234567;
- unsigned int patt2 = 0xfedcba98;
- unsigned int *addr, v1, v2, i;
- addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
- for (i = 0; i != len; i++, addr++) {
- writel(patt1 + i, (unsigned long)addr);
- writel(patt2 + i, (unsigned long)(addr + offs));
- }
- addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
- for (i = 0; i != len; i++) {
- v1 = readl((unsigned long)(addr + i));
- v2 = patt1 + i;
- if (v1 != v2) {
- printf("DRAM: simple test FAIL\n");
- printf("%x != %x at address %p\n", v1, v2, addr + i);
- return 1;
- }
- v1 = readl((unsigned long)(addr + offs + i));
- v2 = patt2 + i;
- if (v1 != v2) {
- printf("DRAM: simple test FAIL\n");
- printf("%x != %x at address %p\n", v1, v2, addr + offs + i);
- return 1;
- }
- }
- debug("DRAM: simple test OK\n");
- return 0;
- }
- // Set the Vref mode for the controller
- //
- static void mctl_vrefzq_init(const dram_para_t *para, const dram_config_t *config)
- {
- if (config->dram_tpr13 & BIT(17))
- return;
- clrsetbits_le32(0x3103110, 0x7f7f7f7f, para->dram_tpr5);
- // IOCVR1
- if ((config->dram_tpr13 & BIT(16)) == 0)
- clrsetbits_le32(0x3103114, 0x7f, para->dram_tpr6 & 0x7f);
- }
- // Perform an init of the controller. This is actually done 3 times. The first
- // time to establish the number of ranks and DQ width. The second time to
- // establish the actual ram size. The third time is final one, with the final
- // settings.
- //
- static int mctl_core_init(const dram_para_t *para, const dram_config_t *config)
- {
- mctl_sys_init(para, config);
- mctl_vrefzq_init(para, config);
- mctl_com_init(para, config);
- mctl_phy_ac_remapping(para, config);
- mctl_set_timing_params(para, config);
- return mctl_channel_init(0, para, config);
- }
- /*
- * This routine sizes a DRAM device by cycling through address lines and
- * figuring out if they are connected to a real address line, or if the
- * address is a mirror.
- * First the column and bank bit allocations are set to low values (2 and 9
- * address lines). Then a maximum allocation (16 lines) is set for rows and
- * this is tested.
- * Next the BA2 line is checked. This seems to be placed above the column,
- * BA0-1 and row addresses. Finally, the column address is allocated 13 lines
- * and these are tested. The results are placed in dram_para1 and dram_para2.
- */
- static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config) {
- uint32_t i = 0, j = 0, current_rank = 0;
- uint32_t rank_count = 1, addr_line = 0;
- uint32_t reg_val = 0, ret = 0, cnt = 0;
- unsigned long mc_work_mode;
- uint32_t rank1_addr = CFG_SYS_SDRAM_BASE;
- // init core
- if (mctl_core_init(para, config) == 0) {
- debug("DRAM initial error : 0!\n");
- return 0;
- }
- // Set rank_count to 2
- if ((((config->dram_para2 >> 12) & 0xf) == 0x1))
- rank_count = 2;
- for (current_rank = 0; current_rank < rank_count; current_rank++) {
- mc_work_mode = ((0x3102000 + 0x00) + 4 * current_rank);
- /* Set 16 Row 4Bank 512BPage for Rank 1 */
- if (current_rank == 1) {
- clrsetbits_le32((0x3102000 + 0x00), 0xf0c, 0x6f0);
- clrsetbits_le32((0x3102000 + 0x04), 0xf0c, 0x6f0);
- /* update Rank 1 addr */
- rank1_addr = CFG_SYS_SDRAM_BASE + (0x1 << 27);
- }
- /* write test pattern */
- for (i = 0; i < 64; i++) {
- writel((i % 2) ? (CFG_SYS_SDRAM_BASE + 4 * i) : (~(CFG_SYS_SDRAM_BASE + 4 * i)),
- CFG_SYS_SDRAM_BASE + 4 * i);
- }
- /* set row mode */
- clrsetbits_le32(mc_work_mode, 0xf0c, 0x6f0);
- udelay(2);
- for (i = 11; i < 17; i++) {
- ret = CFG_SYS_SDRAM_BASE + (1 << (i + 2 + 9)); /* row-bank-column */
- cnt = 0;
- for (j = 0; j < 64; j++) {
- reg_val = (j % 2) ? (rank1_addr + 4 * j) : (~(rank1_addr + 4 * j));
- if (reg_val == readl(ret + j * 4)) {
- cnt++;
- } else
- break;
- }
- if (cnt == 64) {
- break;
- }
- }
- if (i >= 16)
- i = 16;
- addr_line += i;
- debug("rank %u row = %u \n", current_rank, i);
- /* Store rows in para 1 */
- config->dram_para1 &= ~(0xffU << (16 * current_rank + 4));
- config->dram_para1 |= (i << (16 * current_rank + 4));
- /* Set bank mode for current rank */
- if (current_rank == 1) { /* Set bank mode for rank0 */
- clrsetbits_le32((0x3102000 + 0x00), 0xffc, 0x6a4);
- }
- /* Set bank mode for current rank */
- clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4);
- udelay(1);
- for (i = 0; i < 1; i++) {
- ret = CFG_SYS_SDRAM_BASE + (0x1U << (i + 2 + 9));
- cnt = 0;
- for (j = 0; j < 64; j++) {
- reg_val = (j % 2) ? (rank1_addr + 4 * j) : (~(rank1_addr + 4 * j));
- if (reg_val == readl(ret + j * 4)) {
- cnt++;
- } else
- break;
- }
- if (cnt == 64) {
- break;
- }
- }
- addr_line += i + 2;
- debug("rank %u bank = %u \n", current_rank, (4 + i * 4));
- /* Store bank in para 1 */
- config->dram_para1 &= ~(0xfU << (16 * current_rank + 12));
- config->dram_para1 |= (i << (16 * current_rank + 12));
- /* Set page mode for rank0 */
- if (current_rank == 1) {
- clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0);
- }
- /* Set page mode for current rank */
- clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0);
- udelay(2);
- /* Scan per address line, until address wraps (i.e. see shadow) */
- for (i = 9; i <= 13; i++) {
- ret = CFG_SYS_SDRAM_BASE + (0x1U << i);// column 40000000+(9~13)
- cnt = 0;
- for (j = 0; j < 64; j++) {
- reg_val = (j % 2) ? (CFG_SYS_SDRAM_BASE + 4 * j) : (~(CFG_SYS_SDRAM_BASE + 4 * j));
- if (reg_val == readl(ret + j * 4)) {
- cnt++;
- } else {
- break;
- }
- }
- if (cnt == 64) {
- break;
- }
- }
- if (i >= 13) {
- i = 13;
- }
- /* add page size */
- addr_line += i;
- if (i == 9) {
- i = 0;
- } else {
- i = (0x1U << (i - 10));
- }
- debug("rank %u page size = %u KB \n", current_rank, i);
- /* Store page in para 1 */
- config->dram_para1 &= ~(0xfU << (16 * current_rank));
- config->dram_para1 |= (i << (16 * current_rank));
- }
- /* check dual rank config */
- if (rank_count == 2) {
- config->dram_para2 &= 0xfffff0ff;
- if ((config->dram_para1 & 0xffff) == (config->dram_para1 >> 16)) {
- debug("rank1 config same as rank0\n");
- } else {
- config->dram_para2 |= 0x1 << 8;
- debug("rank1 config different from rank0\n");
- }
- }
- return 1;
- }
- /*
- * This routine sets up parameters with dqs_gating_mode equal to 1 and two
- * ranks enabled. It then configures the core and tests for 1 or 2 ranks and
- * full or half DQ width. It then resets the parameters to the original values.
- * dram_para2 is updated with the rank and width findings.
- */
- static int auto_scan_dram_rank_width(const dram_para_t *para,
- dram_config_t *config)
- {
- unsigned int s1 = config->dram_tpr13;
- unsigned int s2 = config->dram_para1;
- config->dram_para1 = 0x00b000b0;
- config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
- /* set DQS probe mode */
- config->dram_tpr13 = (config->dram_tpr13 & ~0x8) | BIT(2) | BIT(0);
- mctl_core_init(para, config);
- if (readl(0x3103010) & BIT(20)) {
- printf("ERROR: read 0x3103010 failed\n");
- return 0;
- }
- if (dqs_gate_detect(config) == 0) {
- printf("ERROR: dqs_gate_detect failed\n");
- return 0;
- }
- config->dram_tpr13 = s1;
- config->dram_para1 = s2;
- return 1;
- }
- /*
- * This routine determines the SDRAM topology. It first establishes the number
- * of ranks and the DQ width. Then it scans the SDRAM address lines to establish
- * the size of each rank. It then updates dram_tpr13 to reflect that the sizes
- * are now known: a re-init will not repeat the autoscan.
- */
- static int auto_scan_dram_config(const dram_para_t *para,
- dram_config_t *config)
- {
- if (((config->dram_tpr13 & BIT(14)) == 0) &&
- (auto_scan_dram_rank_width(para, config) == 0)) {
- printf("ERROR: auto scan dram rank & width failed\n");
- return 0;
- }
- if (((config->dram_tpr13 & BIT(0)) == 0) &&
- (auto_scan_dram_size(para, config) == 0)) {
- printf("ERROR: auto scan dram size failed\n");
- return 0;
- }
- if ((config->dram_tpr13 & BIT(15)) == 0)
- config->dram_tpr13 |= BIT(14) | BIT(13) | BIT(1) | BIT(0);
- return 1;
- }
- static int init_DRAM(int type, const dram_para_t *para)
- {
- dram_config_t config = {
- .dram_para1 = 0x000000d2, // was 0x000010d2
- .dram_para2 = 0,
- .dram_tpr13 = CONFIG_DRAM_SUNXI_TPR13,
- };
- u32 rc, mem_size_mb;
- debug("DRAM BOOT DRIVE INFO: %s\n", "V0.24");
- debug("DRAM CLK = %d MHz\n", para->dram_clk);
- debug("DRAM Type = %d (2:DDR2,3:DDR3)\n", para->dram_type);
- if ((para->dram_odt_en & 0x1) == 0)
- debug("DRAMC read ODT off\n");
- else
- debug("DRAMC ZQ value: 0x%x\n", para->dram_zq);
- /* Test ZQ status */
- if (config.dram_tpr13 & BIT(16)) {
- debug("DRAM only have internal ZQ\n");
- setbits_le32(0x3000160, BIT(8));
- writel(0, 0x3000168);
- udelay(10);
- } else {
- clrbits_le32(0x3000160, 0x3);
- writel(config.dram_tpr13 & BIT(16), 0x7010254);
- udelay(10);
- clrsetbits_le32(0x3000160, 0x108, BIT(1));
- udelay(10);
- setbits_le32(0x3000160, BIT(0));
- udelay(20);
- debug("ZQ value = 0x%x\n", readl(0x300016c));
- }
- dram_voltage_set(para);
- /* Set SDRAM controller auto config */
- if ((config.dram_tpr13 & BIT(0)) == 0) {
- if (auto_scan_dram_config(para, &config) == 0) {
- printf("auto_scan_dram_config() FAILED\n");
- return 0;
- }
- }
- /* report ODT */
- rc = para->dram_mr1;
- if ((rc & 0x44) == 0)
- debug("DRAM ODT off\n");
- else
- debug("DRAM ODT value: 0x%x\n", rc);
- /* Init core, final run */
- if (mctl_core_init(para, &config) == 0) {
- printf("DRAM initialisation error: 1\n");
- return 0;
- }
- /* Get SDRAM size */
- /* TODO: who ever puts a negative number in the top half? */
- rc = config.dram_para2;
- if (rc & BIT(31)) {
- rc = (rc >> 16) & ~BIT(15);
- } else {
- rc = DRAMC_get_dram_size();
- debug("DRAM: size = %dMB\n", rc);
- config.dram_para2 = (config.dram_para2 & 0xffffU) | rc << 16;
- }
- mem_size_mb = rc;
- /* Purpose ?? */
- if (config.dram_tpr13 & BIT(30)) {
- rc = para->dram_tpr8;
- if (rc == 0)
- rc = 0x10000200;
- writel(rc, 0x31030a0);
- writel(0x40a, 0x310309c);
- setbits_le32(0x3103004, BIT(0));
- debug("Enable Auto SR\n");
- } else {
- clrbits_le32(0x31030a0, 0xffff);
- clrbits_le32(0x3103004, 0x1);
- }
- /* Purpose ?? */
- if (config.dram_tpr13 & BIT(9)) {
- clrsetbits_le32(0x3103100, 0xf000, 0x5000);
- } else {
- if (para->dram_type != SUNXI_DRAM_TYPE_LPDDR2)
- clrbits_le32(0x3103100, 0xf000);
- }
- setbits_le32(0x3103140, BIT(31));
- /* CHECK: is that really writing to a different register? */
- if (config.dram_tpr13 & BIT(8))
- writel(readl(0x3103140) | 0x300, 0x31030b8);
- if (config.dram_tpr13 & BIT(16))
- clrbits_le32(0x3103108, BIT(13));
- else
- setbits_le32(0x3103108, BIT(13));
- /* Purpose ?? */
- if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR3)
- clrsetbits_le32(0x310307c, 0xf0000, 0x1000);
- dram_enable_all_master();
- if (config.dram_tpr13 & BIT(28)) {
- if ((readl(0x70005d4) & BIT(16)) ||
- dramc_simple_wr_test(mem_size_mb, 4096))
- return 0;
- }
- return mem_size_mb;
- }
- static const dram_para_t para = {
- .dram_clk = CONFIG_DRAM_CLK,
- .dram_type = CONFIG_SUNXI_DRAM_TYPE,
- .dram_zq = CONFIG_DRAM_ZQ,
- .dram_odt_en = CONFIG_DRAM_SUNXI_ODT_EN,
- .dram_mr0 = 0xe73, // was 0x1c70
- .dram_mr1 = 0x02, // was 0x42
- .dram_mr2 = 0, // was 0x18
- .dram_mr3 = 0,
- .dram_tpr0 = CONFIG_DRAM_SUNXI_TPR0, // was 0x004a2195
- .dram_tpr1 = 0x0131A10C, // was 0x02423190
- .dram_tpr2 = 0x00057041, // was 0x0008b061
- .dram_tpr3 = 0xb4787896, // unused
- .dram_tpr4 = 0,
- .dram_tpr5 = 0x48484848,
- .dram_tpr6 = 0x00000048,
- .dram_tpr7 = 0x1621121e, // unused
- .dram_tpr8 = 0,
- .dram_tpr9 = 0, // clock?
- .dram_tpr10 = 0,
- .dram_tpr11 = CONFIG_DRAM_SUNXI_TPR11,
- .dram_tpr12 = CONFIG_DRAM_SUNXI_TPR12,
- };
- unsigned long sunxi_dram_init(void)
- {
- return init_DRAM(0, ¶) * 1024UL * 1024;
- };
- #ifdef CONFIG_RAM /* using the driver model */
- struct sunxi_ram_priv {
- size_t size;
- };
- static int sunxi_ram_probe(struct udevice *dev)
- {
- struct sunxi_ram_priv *priv = dev_get_priv(dev);
- unsigned long dram_size;
- debug("%s: %s: probing\n", __func__, dev->name);
- dram_size = sunxi_dram_init();
- if (!dram_size) {
- printf("DRAM init failed\n");
- return -ENODEV;
- }
- priv->size = dram_size;
- return 0;
- }
- static int sunxi_ram_get_info(struct udevice *dev, struct ram_info *info)
- {
- struct sunxi_ram_priv *priv = dev_get_priv(dev);
- debug("%s: %s: getting info\n", __func__, dev->name);
- info->base = CFG_SYS_SDRAM_BASE;
- info->size = priv->size;
- return 0;
- }
- static struct ram_ops sunxi_ram_ops = {
- .get_info = sunxi_ram_get_info,
- };
- static const struct udevice_id sunxi_ram_ids[] = {
- { .compatible = "allwinner,sun20i-d1-mbus" },
- { }
- };
- U_BOOT_DRIVER(sunxi_ram) = {
- .name = "sunxi_ram",
- .id = UCLASS_RAM,
- .of_match = sunxi_ram_ids,
- .ops = &sunxi_ram_ops,
- .probe = sunxi_ram_probe,
- .priv_auto = sizeof(struct sunxi_ram_priv),
- };
- #endif /* CONFIG_RAM (using driver model) */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement