summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mainboard/google/veyron/Makefile.inc1
-rw-r--r--src/mainboard/google/veyron/romstage.c2
-rw-r--r--src/mainboard/google/veyron/sdram_configs.c75
-rw-r--r--src/mainboard/google/veyron/sdram_inf/sdram-ddr3-hynix-2GB.inc77
-rw-r--r--src/mainboard/google/veyron/sdram_inf/sdram-lpddr3-samsung-2GB.inc78
-rw-r--r--src/mainboard/google/veyron/sdram_inf/sdram-unused.inc3
-rw-r--r--src/soc/rockchip/rk3288/Makefile.inc2
-rwxr-xr-xsrc/soc/rockchip/rk3288/clock.c77
-rwxr-xr-xsrc/soc/rockchip/rk3288/clock.h5
-rw-r--r--src/soc/rockchip/rk3288/cpu.h2
-rwxr-xr-xsrc/soc/rockchip/rk3288/grf.h40
-rw-r--r--src/soc/rockchip/rk3288/sdram.c1046
-rw-r--r--src/soc/rockchip/rk3288/sdram.h104
13 files changed, 1498 insertions, 14 deletions
diff --git a/src/mainboard/google/veyron/Makefile.inc b/src/mainboard/google/veyron/Makefile.inc
index 50a6ba039b..f249cf95af 100644
--- a/src/mainboard/google/veyron/Makefile.inc
+++ b/src/mainboard/google/veyron/Makefile.inc
@@ -18,6 +18,7 @@
##
romstage-y += romstage.c
+romstage-y += sdram_configs.c
ramstage-y += mainboard.c
ramstage-y += chromeos.c
diff --git a/src/mainboard/google/veyron/romstage.c b/src/mainboard/google/veyron/romstage.c
index 5b26f48e3c..5831fde095 100644
--- a/src/mainboard/google/veyron/romstage.c
+++ b/src/mainboard/google/veyron/romstage.c
@@ -27,6 +27,7 @@
#include <timestamp.h>
#include <arch/cache.h>
#include <arch/exception.h>
+#include <soc/rockchip/rk3288/sdram.h>
void main(void)
{
@@ -36,6 +37,7 @@ void main(void)
u32 dram_start = (CONFIG_SYS_SDRAM_BASE >> 20);
u32 dram_size = CONFIG_DRAM_SIZE_MB;
u32 dram_end = dram_start + dram_size;
+ sdram_init(get_sdram_config());
mmu_init();
/* Device memory below DRAM is uncached. */
mmu_config_range(0, dram_start, DCACHE_OFF);
diff --git a/src/mainboard/google/veyron/sdram_configs.c b/src/mainboard/google/veyron/sdram_configs.c
new file mode 100644
index 0000000000..b3600fbfff
--- /dev/null
+++ b/src/mainboard/google/veyron/sdram_configs.c
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <arch/io.h>
+#include <string.h>
+#include <types.h>
+#include <console/console.h>
+#include <soc/rockchip/rk3288/sdram.h>
+#include <soc/rockchip/rk3288/gpio.h>
+
+static struct rk3288_sdram_params sdram_configs[] = {
+#include "sdram_inf/sdram-lpddr3-samsung-2GB.inc" /* ram_code = 0000 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0001 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0010 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0011 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0100 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0101 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0110 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 0111 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1000 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1001 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1010 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1011 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1100 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1101 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1110 */
+#include "sdram_inf/sdram-unused.inc" /* ram_code = 1111 */
+};
+
+#define GPIO_RAMCODE0 (gpio_t){.port = 8, .bank = GPIO_A, .idx = 0}
+#define GPIO_RAMCODE1 (gpio_t){.port = 8, .bank = GPIO_A, .idx = 1}
+#define GPIO_RAMCODE2 (gpio_t){.port = 8, .bank = GPIO_A, .idx = 2}
+#define GPIO_RAMCODE3 (gpio_t){.port = 8, .bank = GPIO_A, .idx = 3}
+
+u32 sdram_get_ram_code(void)
+{
+ u32 code = 0;
+
+ gpio_input(GPIO_RAMCODE0);
+ gpio_input(GPIO_RAMCODE1);
+ gpio_input(GPIO_RAMCODE2);
+ gpio_input(GPIO_RAMCODE3);
+
+ code = gpio_get_in_value(GPIO_RAMCODE3) << 3
+ | gpio_get_in_value(GPIO_RAMCODE2) << 2
+ | gpio_get_in_value(GPIO_RAMCODE1) << 1
+ | gpio_get_in_value(GPIO_RAMCODE0) << 0;
+
+ return code;
+}
+
+const struct rk3288_sdram_params *get_sdram_config()
+{
+ u32 ramcode = sdram_get_ram_code();
+
+ if (ramcode >= ARRAY_SIZE(sdram_configs)
+ || sdram_configs[ramcode].dramtype == UNUSED)
+ die("Invalid RAMCODE.");
+ return &sdram_configs[ramcode];
+}
diff --git a/src/mainboard/google/veyron/sdram_inf/sdram-ddr3-hynix-2GB.inc b/src/mainboard/google/veyron/sdram_inf/sdram-ddr3-hynix-2GB.inc
new file mode 100644
index 0000000000..409a7cad35
--- /dev/null
+++ b/src/mainboard/google/veyron/sdram_inf/sdram-ddr3-hynix-2GB.inc
@@ -0,0 +1,77 @@
+{
+ {
+ {
+ .rank = 0x1,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF
+ },
+ {
+ .rank = 0x1,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF
+ }
+ },
+ {
+ .togcnt1u = 0x215,
+ .tinit = 0xC8,
+ .trsth = 0x1F4,
+ .togcnt100n = 0x35,
+ .trefi = 0x4E,
+ .tmrd = 0x4,
+ .trfc = 0xBB,
+ .trp = 0x8,
+ .trtw = 0x4,
+ .tal = 0x0,
+ .tcl = 0x8,
+ .tcwl = 0x6,
+ .tras = 0x14,
+ .trc = 0x1D,
+ .trcd = 0x8,
+ .trrd = 0x6,
+ .trtp = 0x4,
+ .twr = 0x8,
+ .twtr = 0x4,
+ .texsr = 0x200,
+ .txp = 0x4,
+ .txpdll = 0xD,
+ .tzqcs = 0x40,
+ .tzqcsi = 0x0,
+ .tdqs = 0x1,
+ .tcksre = 0x6,
+ .tcksrx = 0x6,
+ .tcke = 0x4,
+ .tmod = 0xC,
+ .trstl = 0x36,
+ .tzqcl = 0x100,
+ .tmrr = 0x0,
+ .tckesr = 0x5,
+ .tdpd = 0x0
+ },
+ {
+ .dtpr0 = 0x3AD48890,
+ .dtpr1 = 0xBB08D8,
+ .dtpr2 = 0x1002B600,
+ .mr[0] = 0x840,
+ .mr[1] = 0x40,
+ .mr[2] = 0x8,
+ .mr[3] = 0x0
+ },
+ .noc_timing = 0x2891E41D,
+ .noc_activate = 0x5B6,
+ .ddrconfig = 3,
+ .ddr_freq = 533000000,
+ .dramtype = DDR3,
+ .num_channels = 2,
+ .stride = 9,
+ .odt = 1
+},
diff --git a/src/mainboard/google/veyron/sdram_inf/sdram-lpddr3-samsung-2GB.inc b/src/mainboard/google/veyron/sdram_inf/sdram-lpddr3-samsung-2GB.inc
new file mode 100644
index 0000000000..315e542c39
--- /dev/null
+++ b/src/mainboard/google/veyron/sdram_inf/sdram-lpddr3-samsung-2GB.inc
@@ -0,0 +1,78 @@
+{
+ /* two Samsung K4E8E304ED-EGCE000 chips */
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x2,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xE,
+ .cs1_row = 0xE
+ },
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x2,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xE,
+ .cs1_row = 0xE
+ }
+ },
+ {
+ .togcnt1u = 0x215,
+ .tinit = 0xC8,
+ .trsth = 0x0,
+ .togcnt100n = 0x35,
+ .trefi = 0x26,
+ .tmrd = 0x2,
+ .trfc = 0x70,
+ .trp = 0x2000D,
+ .trtw = 0x6,
+ .tal = 0x0,
+ .tcl = 0x8,
+ .tcwl = 0x4,
+ .tras = 0x17,
+ .trc = 0x24,
+ .trcd = 0xD,
+ .trrd = 0x6,
+ .trtp = 0x4,
+ .twr = 0x8,
+ .twtr = 0x4,
+ .texsr = 0x76,
+ .txp = 0x4,
+ .txpdll = 0x0,
+ .tzqcs = 0x30,
+ .tzqcsi = 0x0,
+ .tdqs = 0x1,
+ .tcksre = 0x2,
+ .tcksrx = 0x2,
+ .tcke = 0x4,
+ .tmod = 0x0,
+ .trstl = 0x0,
+ .tzqcl = 0xC0,
+ .tmrr = 0x4,
+ .tckesr = 0x8,
+ .tdpd = 0x1F4
+ },
+ {
+ .dtpr0 = 0x48D7DD93,
+ .dtpr1 = 0x187008D8,
+ .dtpr2 = 0x121076,
+ .mr[0] = 0x0,
+ .mr[1] = 0xC3,
+ .mr[2] = 0x6,
+ .mr[3] = 0x1
+ },
+ .noc_timing = 0x20D266A4,
+ .noc_activate = 0x5B6,
+ .ddrconfig = 2,
+ .ddr_freq = 533000000,
+ .dramtype = LPDDR3,
+ .num_channels = 2,
+ .stride = 9,
+ .odt = 1
+},
diff --git a/src/mainboard/google/veyron/sdram_inf/sdram-unused.inc b/src/mainboard/google/veyron/sdram_inf/sdram-unused.inc
new file mode 100644
index 0000000000..06498f7f14
--- /dev/null
+++ b/src/mainboard/google/veyron/sdram_inf/sdram-unused.inc
@@ -0,0 +1,3 @@
+{
+ .dramtype= UNUSED
+}, \ No newline at end of file
diff --git a/src/soc/rockchip/rk3288/Makefile.inc b/src/soc/rockchip/rk3288/Makefile.inc
index 4818cafb11..446aa7842d 100644
--- a/src/soc/rockchip/rk3288/Makefile.inc
+++ b/src/soc/rockchip/rk3288/Makefile.inc
@@ -39,7 +39,7 @@ romstage-y += clock.c
romstage-y += gpio.c
romstage-y += spi.c
romstage-y += media.c
-
+romstage-y += sdram.c
ramstage-y += cbmem.c
ramstage-y += timer.c
diff --git a/src/soc/rockchip/rk3288/clock.c b/src/soc/rockchip/rk3288/clock.c
index 757d180387..b194b4c10e 100755
--- a/src/soc/rockchip/rk3288/clock.c
+++ b/src/soc/rockchip/rk3288/clock.c
@@ -70,11 +70,10 @@ static struct rk3288_cru_reg * const cru_ptr = (void *)CRU_BASE;
(_nr * _no) == hz,\
#hz "Hz cannot be hit with PLL divisors in " __FILE__);
-/* apll = 816MHz, gpll = 594MHz, cpll = 384MHz, dpll = 300MHz */
+/* apll = 816MHz, gpll = 594MHz, cpll = 384MHz */
static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 2);
static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 4);
static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 4);
-static const struct pll_div dpll_init_cfg = PLL_DIVISORS(DPLL_HZ, 1, 4);
/*******************PLL CON0 BITS***************************/
#define PLL_OD_MSK (0x0F)
@@ -191,23 +190,21 @@ void rkclk_init(void)
/* pll enter slow-mode */
writel(RK_CLRSETBITS(APLL_MODE_MSK, APLL_MODE_SLOW)
| RK_CLRSETBITS(GPLL_MODE_MSK, GPLL_MODE_SLOW)
- | RK_CLRSETBITS(CPLL_MODE_MSK, CPLL_MODE_SLOW)
- | RK_CLRSETBITS(DPLL_MODE_MSK, DPLL_MODE_SLOW),
+ | RK_CLRSETBITS(CPLL_MODE_MSK, CPLL_MODE_SLOW),
&cru_ptr->cru_mode_con);
/* init pll */
rkclk_set_pll(&cru_ptr->cru_apll_con[0], &apll_init_cfg);
rkclk_set_pll(&cru_ptr->cru_gpll_con[0], &gpll_init_cfg);
rkclk_set_pll(&cru_ptr->cru_cpll_con[0], &cpll_init_cfg);
- rkclk_set_pll(&cru_ptr->cru_dpll_con[0], &dpll_init_cfg);
/* waiting for pll lock */
while (1) {
if ((readl(&rk3288_grf->soc_status[1])
& (SOCSTS_APLL_LOCK | SOCSTS_CPLL_LOCK
- | SOCSTS_DPLL_LOCK | SOCSTS_GPLL_LOCK))
+ | SOCSTS_GPLL_LOCK))
== (SOCSTS_APLL_LOCK | SOCSTS_CPLL_LOCK
- | SOCSTS_GPLL_LOCK | SOCSTS_DPLL_LOCK))
+ | SOCSTS_GPLL_LOCK))
break;
udelay(1);
}
@@ -248,12 +245,74 @@ void rkclk_init(void)
/* PLL enter normal-mode */
writel(RK_CLRSETBITS(APLL_MODE_MSK, APLL_MODE_NORM)
| RK_CLRSETBITS(GPLL_MODE_MSK, GPLL_MODE_NORM)
- | RK_CLRSETBITS(CPLL_MODE_MSK, CPLL_MODE_NORM)
- | RK_CLRSETBITS(DPLL_MODE_MSK, DPLL_MODE_NORM),
+ | RK_CLRSETBITS(CPLL_MODE_MSK, CPLL_MODE_NORM),
&cru_ptr->cru_mode_con);
}
+void rkclk_configure_ddr(unsigned int hz)
+{
+ struct pll_div dpll_cfg;
+
+ if (hz <= 150000000) {
+ dpll_cfg.nr = 3;
+ dpll_cfg.no = 8;
+ } else if (hz <= 540000000) {
+ dpll_cfg.nr = 6;
+ dpll_cfg.no = 4;
+ } else {
+ dpll_cfg.nr = 1;
+ dpll_cfg.no = 1;
+ }
+
+ dpll_cfg.nf = (hz / 1000 * dpll_cfg.nr * dpll_cfg.no) / 24000;
+ assert(dpll_cfg.nf < 4096
+ && hz == dpll_cfg.nf * 24000 / (dpll_cfg.nr * dpll_cfg.no)
+ * 1000);
+ /* pll enter slow-mode */
+ writel(RK_CLRSETBITS(DPLL_MODE_MSK, DPLL_MODE_SLOW),
+ &cru_ptr->cru_mode_con);
+
+ rkclk_set_pll(&cru_ptr->cru_dpll_con[0], &dpll_cfg);
+
+ /* waiting for pll lock */
+ while (1) {
+ if (readl(&rk3288_grf->soc_status[1]) & SOCSTS_DPLL_LOCK)
+ break;
+ udelay(1);
+ }
+
+ /* PLL enter normal-mode */
+ writel(RK_CLRSETBITS(DPLL_MODE_MSK, DPLL_MODE_NORM),
+ &cru_ptr->cru_mode_con);
+}
+
+void rkclk_ddr_reset(u32 ch, u32 ctl, u32 phy)
+{
+ u32 phy_ctl_srstn_shift = 4 + 5 * ch;
+ u32 ctl_psrstn_shift = 3 + 5 * ch;
+ u32 ctl_srstn_shift = 2 + 5 * ch;
+ u32 phy_psrstn_shift = 1 + 5 * ch;
+ u32 phy_srstn_shift = 5 * ch;
+
+ writel(RK_CLRSETBITS(1 << phy_ctl_srstn_shift,
+ phy << phy_ctl_srstn_shift)
+ | RK_CLRSETBITS(1 << ctl_psrstn_shift, ctl << ctl_psrstn_shift)
+ | RK_CLRSETBITS(1 << ctl_srstn_shift, ctl << ctl_srstn_shift)
+ | RK_CLRSETBITS(1 << phy_psrstn_shift, phy << phy_psrstn_shift)
+ | RK_CLRSETBITS(1 << phy_srstn_shift, phy << phy_srstn_shift),
+ &cru_ptr->cru_softrst_con[10]);
+}
+
+void rkclk_ddr_phy_ctl_reset(u32 ch, u32 n)
+{
+ u32 phy_ctl_srstn_shift = 4 + 5 * ch;
+
+ writel(RK_CLRSETBITS(1 << phy_ctl_srstn_shift,
+ n << phy_ctl_srstn_shift),
+ &cru_ptr->cru_softrst_con[10]);
+}
+
void rkclk_configure_spi(unsigned int bus, unsigned int hz)
{
int src_clk_div = GPLL_HZ / hz;
diff --git a/src/soc/rockchip/rk3288/clock.h b/src/soc/rockchip/rk3288/clock.h
index e7732199ac..d04dfeb29c 100755
--- a/src/soc/rockchip/rk3288/clock.h
+++ b/src/soc/rockchip/rk3288/clock.h
@@ -25,10 +25,11 @@
#define APLL_HZ 816000000
#define GPLL_HZ 594000000
#define CPLL_HZ 384000000
-#define DPLL_HZ 300000000
void rkclk_init(void);
void rkclk_configure_spi(unsigned int bus, unsigned int hz);
+void rkclk_ddr_reset(u32 ch, u32 ctl, u32 phy);
+void rkclk_ddr_phy_ctl_reset(u32 ch, u32 n);
+void rkclk_configure_ddr(unsigned int hz);
#endif /* __SOC_ROCKCHIP_RK3288_CLOCK_H__ */
-
diff --git a/src/soc/rockchip/rk3288/cpu.h b/src/soc/rockchip/rk3288/cpu.h
index c42bbe8752..9bcfe3e1e9 100644
--- a/src/soc/rockchip/rk3288/cpu.h
+++ b/src/soc/rockchip/rk3288/cpu.h
@@ -20,6 +20,8 @@
#ifndef __SOC_ROCKCHIP_RK3288_CPU_H__
#define __SOC_ROCKCHIP_RK3288_CPU_H__
+#include <arch/io.h>
+
#define RK_CLRSETBITS(clr, set) ((((clr) | (set)) << 16) | set)
#define RK_SETBITS(set) RK_CLRSETBITS(0, set)
#define RK_CLRBITS(clr) RK_CLRSETBITS(clr, 0)
diff --git a/src/soc/rockchip/rk3288/grf.h b/src/soc/rockchip/rk3288/grf.h
index 547a4c7ee9..b035bb9dd3 100755
--- a/src/soc/rockchip/rk3288/grf.h
+++ b/src/soc/rockchip/rk3288/grf.h
@@ -25,9 +25,10 @@
#include "cpu.h"
struct rk3288_grf_gpio_lh {
- u32 gpiol;
- u32 gpioh;
+ u32 l;
+ u32 h;
};
+check_member(rk3288_grf_gpio_lh, h, 0x4);
struct rk3288_grf_regs {
u32 reserved[3];
@@ -155,6 +156,41 @@ struct rk3288_grf_regs {
};
check_member(rk3288_grf_regs, soc_con16, 0x3a8);
+struct rk3288_sgrf_regs {
+ u32 soc_con0;
+ u32 soc_con1;
+ u32 soc_con2;
+ u32 soc_con3;
+ u32 soc_con4;
+ u32 soc_con5;
+ u32 reserved1[(0x20-0x18)/4];
+ u32 busdmac_con[2];
+ u32 reserved2[(0x40-0x28)/4];
+ u32 cpu_con[3];
+ u32 reserved3[(0x50-0x4c)/4];
+ u32 soc_con6;
+ u32 soc_con7;
+ u32 soc_con8;
+ u32 soc_con9;
+ u32 soc_con10;
+ u32 soc_con11;
+ u32 soc_con12;
+ u32 soc_con13;
+ u32 soc_con14;
+ u32 soc_con15;
+ u32 soc_con16;
+ u32 soc_con17;
+ u32 soc_con18;
+ u32 soc_con19;
+ u32 soc_con20;
+ u32 soc_con21;
+ u32 reserved4[(0x100-0x90)/4];
+ u32 soc_status[2];
+ u32 reserved5[(0x120-0x108)/4];
+ u32 fast_boot_addr;
+};
+check_member(rk3288_sgrf_regs, fast_boot_addr, 0x0120);
+
static struct rk3288_grf_regs * const rk3288_grf = (void *)GRF_BASE;
static struct rk3288_sgrf_regs * const rk3288_sgrf = (void *)GRF_SECURE_BASE;
diff --git a/src/soc/rockchip/rk3288/sdram.c b/src/soc/rockchip/rk3288/sdram.c
new file mode 100644
index 0000000000..4f8b268398
--- /dev/null
+++ b/src/soc/rockchip/rk3288/sdram.c
@@ -0,0 +1,1046 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Rockchip Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <arch/io.h>
+#include <string.h>
+#include <types.h>
+#include <console/console.h>
+#include <delay.h>
+#include "addressmap.h"
+#include "clock.h"
+#include "sdram.h"
+#include "grf.h"
+#include "cpu.h"
+#include "pmu.h"
+
+struct rk3288_ddr_pctl_regs {
+ u32 scfg;
+ u32 sctl;
+ u32 stat;
+ u32 intrstat;
+ u32 reserved0[12];
+ u32 mcmd;
+ u32 powctl;
+ u32 powstat;
+ u32 cmdtstat;
+ u32 tstaten;
+ u32 reserved1[3];
+ u32 mrrcfg0;
+ u32 mrrstat0;
+ u32 mrrstat1;
+ u32 reserved2[4];
+ u32 mcfg1;
+ u32 mcfg;
+ u32 ppcfg;
+ u32 mstat;
+ u32 lpddr2zqcfg;
+ u32 reserved3;
+ u32 dtupdes;
+ u32 dtuna;
+ u32 dtune;
+ u32 dtuprd0;
+ u32 dtuprd1;
+ u32 dtuprd2;
+ u32 dtuprd3;
+ u32 dtuawdt;
+ u32 reserved4[3];
+ u32 togcnt1u;
+ u32 tinit;
+ u32 trsth;
+ u32 togcnt100n;
+ u32 trefi;
+ u32 tmrd;
+ u32 trfc;
+ u32 trp;
+ u32 trtw;
+ u32 tal;
+ u32 tcl;
+ u32 tcwl;
+ u32 tras;
+ u32 trc;
+ u32 trcd;
+ u32 trrd;
+ u32 trtp;
+ u32 twr;
+ u32 twtr;
+ u32 texsr;
+ u32 txp;
+ u32 txpdll;
+ u32 tzqcs;
+ u32 tzqcsi;
+ u32 tdqs;
+ u32 tcksre;
+ u32 tcksrx;
+ u32 tcke;
+ u32 tmod;
+ u32 trstl;
+ u32 tzqcl;
+ u32 tmrr;
+ u32 tckesr;
+ u32 tdpd;
+ u32 reserved5[14];
+ u32 ecccfg;
+ u32 ecctst;
+ u32 eccclr;
+ u32 ecclog;
+ u32 reserved6[28];
+ u32 dtuwactl;
+ u32 dturactl;
+ u32 dtucfg;
+ u32 dtuectl;
+ u32 dtuwd0;
+ u32 dtuwd1;
+ u32 dtuwd2;
+ u32 dtuwd3;
+ u32 dtuwdm;
+ u32 dturd0;
+ u32 dturd1;
+ u32 dturd2;
+ u32 dturd3;
+ u32 dtulfsrwd;
+ u32 dtulfsrrd;
+ u32 dtueaf;
+ u32 dfitctrldelay;
+ u32 dfiodtcfg;
+ u32 dfiodtcfg1;
+ u32 dfiodtrankmap;
+ u32 dfitphywrdata;
+ u32 dfitphywrlat;
+ u32 reserved7[2];
+ u32 dfitrddataen;
+ u32 dfitphyrdlat;
+ u32 reserved8[2];
+ u32 dfitphyupdtype0;
+ u32 dfitphyupdtype1;
+ u32 dfitphyupdtype2;
+ u32 dfitphyupdtype3;
+ u32 dfitctrlupdmin;
+ u32 dfitctrlupdmax;
+ u32 dfitctrlupddly;
+ u32 reserved9;
+ u32 dfiupdcfg;
+ u32 dfitrefmski;
+ u32 dfitctrlupdi;
+ u32 reserved10[4];
+ u32 dfitrcfg0;
+ u32 dfitrstat0;
+ u32 dfitrwrlvlen;
+ u32 dfitrrdlvlen;
+ u32 dfitrrdlvlgateen;
+ u32 dfiststat0;
+ u32 dfistcfg0;
+ u32 dfistcfg1;
+ u32 reserved11;
+ u32 dfitdramclken;
+ u32 dfitdramclkdis;
+ u32 dfistcfg2;
+ u32 dfistparclr;
+ u32 dfistparlog;
+ u32 reserved12[3];
+ u32 dfilpcfg0;
+ u32 reserved13[3];
+ u32 dfitrwrlvlresp0;
+ u32 dfitrwrlvlresp1;
+ u32 dfitrwrlvlresp2;
+ u32 dfitrrdlvlresp0;
+ u32 dfitrrdlvlresp1;
+ u32 dfitrrdlvlresp2;
+ u32 dfitrwrlvldelay0;
+ u32 dfitrwrlvldelay1;
+ u32 dfitrwrlvldelay2;
+ u32 dfitrrdlvldelay0;
+ u32 dfitrrdlvldelay1;
+ u32 dfitrrdlvldelay2;
+ u32 dfitrrdlvlgatedelay0;
+ u32 dfitrrdlvlgatedelay1;
+ u32 dfitrrdlvlgatedelay2;
+ u32 dfitrcmd;
+ u32 reserved14[46];
+ u32 ipvr;
+ u32 iptr;
+};
+check_member(rk3288_ddr_pctl_regs, iptr, 0x03fc);
+
+struct rk3288_ddr_publ_datx {
+ u32 dxgcr;
+ u32 dxgsr[2];
+ u32 dxdllcr;
+ u32 dxdqtr;
+ u32 dxdqstr;
+ u32 reserved[10];
+};
+
+struct rk3288_ddr_publ_regs {
+ u32 ridr;
+ u32 pir;
+ u32 pgcr;
+ u32 pgsr;
+ u32 dllgcr;
+ u32 acdllcr;
+ u32 ptr[3];
+ u32 aciocr;
+ u32 dxccr;
+ u32 dsgcr;
+ u32 dcr;
+ u32 dtpr[3];
+ u32 mr[4];
+ u32 odtcr;
+ u32 dtar;
+ u32 dtdr[2];
+ u32 reserved1[24];
+ u32 dcuar;
+ u32 dcudr;
+ u32 dcurr;
+ u32 dculr;
+ u32 dcugcr;
+ u32 dcutpr;
+ u32 dcusr[2];
+ u32 reserved2[8];
+ u32 bist[17];
+ u32 reserved3[15];
+ u32 zq0cr[2];
+ u32 zq0sr[2];
+ u32 zq1cr[2];
+ u32 zq1sr[2];
+ u32 zq2cr[2];
+ u32 zq2sr[2];
+ u32 zq3cr[2];
+ u32 zq3sr[2];
+ struct rk3288_ddr_publ_datx datx8[4];
+};
+check_member(rk3288_ddr_publ_regs, datx8[3].dxdqstr, 0x0294);
+
+struct rk3288_msch_regs {
+ u32 coreid;
+ u32 revisionid;
+ u32 ddrconf;
+ u32 ddrtiming;
+ u32 ddrmode;
+ u32 readlatency;
+ u32 reserved1[8];
+ u32 activate;
+ u32 devtodev;
+};
+check_member(rk3288_msch_regs, devtodev, 0x003c);
+
+static struct rk3288_ddr_pctl_regs * const rk3288_ddr_pctl[2] = {
+ (void *)DDR_PCTL0_BASE, (void *)DDR_PCTL1_BASE};
+static struct rk3288_ddr_publ_regs * const rk3288_ddr_publ[2] = {
+ (void *)DDR_PUBL0_BASE, (void *)DDR_PUBL1_BASE};
+static struct rk3288_msch_regs * const rk3288_msch[2] = {
+ (void *)SERVICE_BUS_BASE, (void *)SERVICE_BUS_BASE + 0x80};
+
+/* PCT_DFISTCFG0 */
+#define DFI_INIT_START (1 << 0)
+
+/* PCT_DFISTCFG1 */
+#define DFI_DRAM_CLK_SR_EN (1 << 0)
+#define DFI_DRAM_CLK_DPD_EN (1 << 1)
+
+/* PCT_DFISTCFG2 */
+#define DFI_PARITY_INTR_EN (1 << 0)
+#define DFI_PARITY_EN (1 << 1)
+
+/* PCT_DFILPCFG0 */
+#define TLP_RESP_TIME(n) (n << 16)
+#define LP_SR_EN (1 << 8)
+#define LP_PD_EN (1 << 0)
+
+/* PCT_DFITCTRLDELAY */
+#define TCTRL_DELAY_TIME(n) (n << 0)
+
+/* PCT_DFITPHYWRDATA */
+#define TPHY_WRDATA_TIME(n) (n << 0)
+
+/* PCT_DFITPHYRDLAT */
+#define TPHY_RDLAT_TIME(n) (n << 0)
+
+/* PCT_DFITDRAMCLKDIS */
+#define TDRAM_CLK_DIS_TIME(n) (n << 0)
+
+/* PCT_DFITDRAMCLKEN */
+#define TDRAM_CLK_EN_TIME(n) (n << 0)
+
+/* PCTL_DFIODTCFG */
+#define RANK0_ODT_WRITE_SEL (1 << 3)
+#define RANK1_ODT_WRITE_SEL (1 << 11)
+
+/* PCTL_DFIODTCFG1 */
+#define ODT_LEN_BL8_W(n) (n<<16)
+
+/* PUBL_ACDLLCR */
+#define ACDLLCR_DLLDIS (1 << 31)
+#define ACDLLCR_DLLSRST (1 << 30)
+
+/* PUBL_DXDLLCR */
+#define DXDLLCR_DLLDIS (1 << 31)
+#define DXDLLCR_DLLSRST (1 << 30)
+
+/* PUBL_DLLGCR */
+#define DLLGCR_SBIAS (1 << 30)
+
+/* PUBL_DXGCR */
+#define DQSRTT (1 << 9)
+#define DQRTT (1 << 10)
+
+/* PIR */
+#define PIR_INIT (1 << 0)
+#define PIR_DLLSRST (1 << 1)
+#define PIR_DLLLOCK (1 << 2)
+#define PIR_ZCAL (1 << 3)
+#define PIR_ITMSRST (1 << 4)
+#define PIR_DRAMRST (1 << 5)
+#define PIR_DRAMINIT (1 << 6)
+#define PIR_QSTRN (1 << 7)
+#define PIR_RVTRN (1 << 8)
+#define PIR_ICPC (1 << 16)
+#define PIR_DLLBYP (1 << 17)
+#define PIR_CTLDINIT (1 << 18)
+#define PIR_CLRSR (1 << 28)
+#define PIR_LOCKBYP (1 << 29)
+#define PIR_ZCALBYP (1 << 30)
+#define PIR_INITBYP (1u << 31)
+
+/* PGCR */
+#define PGCR_DFTLMT(n) ((n) << 3)
+#define PGCR_DFTCMP(n) ((n) << 2)
+#define PGCR_DQSCFG(n) ((n) << 1)
+#define PGCR_ITMDMD(n) ((n) << 0)
+
+/* PGSR */
+#define PGSR_IDONE (1 << 0)
+#define PGSR_DLDONE (1 << 1)
+#define PGSR_ZCDONE (1 << 2)
+#define PGSR_DIDONE (1 << 3)
+#define PGSR_DTDONE (1 << 4)
+#define PGSR_DTERR (1 << 5)
+#define PGSR_DTIERR (1 << 6)
+#define PGSR_DFTERR (1 << 7)
+#define PGSR_RVERR (1 << 8)
+#define PGSR_RVEIRR (1 << 9)
+
+/* PTR0 */
+#define PRT_ITMSRST(n) ((n) << 18)
+#define PRT_DLLLOCK(n) ((n) << 6)
+#define PRT_DLLSRST(n) ((n) << 0)
+
+/* PTR1 */
+#define PRT_DINIT1(n) ((n) << 19)
+#define PRT_DINIT0(n) ((n) << 0)
+
+/* PTR2 */
+#define PRT_DINIT3(n) ((n) << 17)
+#define PRT_DINIT2(n) ((n) << 0)
+
+/* DCR */
+#define DDRMD_LPDDR 0
+#define DDRMD_DDR 1
+#define DDRMD_DDR2 2
+#define DDRMD_DDR3 3
+#define DDRMD_LPDDR2_LPDDR3 4
+#define DDRMD_MSK (7 << 0)
+#define DDRMD_CFG(n) ((n) << 0)
+#define PDQ_MSK (7 << 4)
+#define PDQ_CFG(n) ((n) << 4)
+
+/* DXCCR */
+#define DQSNRES_MSK (0x0f << 8)
+#define DQSNRES_CFG(n) ((n) << 8)
+#define DQSRES_MSK (0x0f << 4)
+#define DQSRES_CFG(n) ((n) << 4)
+
+/* DTPR */
+#define TDQSCKMAX_VAL(n) (((n) >> 27) & 7)
+#define TDQSCK_VAL(n) (((n) >> 24) & 7)
+
+/* DSGCR */
+#define DQSGX_MSK (0x07 << 5)
+#define DQSGX_CFG(n) ((n) << 5)
+#define DQSGE_MSK (0x07 << 8)
+#define DQSGE_CFG(n) ((n) << 8)
+
+/* SCTL */
+#define INIT_STATE (0)
+#define CFG_STATE (1)
+#define GO_STATE (2)
+#define SLEEP_STATE (3)
+#define WAKEUP_STATE (4)
+
+/* STAT */
+#define LP_TRIG_VAL(n) (((n) >> 4) & 7)
+#define PCTL_STAT_MSK (7)
+#define INIT_MEM (0)
+#define CONFIG (1)
+#define CONFIG_REQ (2)
+#define ACCESS (3)
+#define ACCESS_REQ (4)
+#define LOW_POWER (5)
+#define LOW_POWER_ENTRY_REQ (6)
+#define LOW_POWER_EXIT_REQ (7)
+
+/* ZQCR*/
+#define PD_OUTPUT(n) ((n) << 0)
+#define PU_OUTPUT(n) ((n) << 5)
+#define PD_ONDIE(n) ((n) << 10)
+#define PU_ONDIE(n) ((n) << 15)
+#define ZDEN(n) ((n) << 28)
+
+/* DDLGCR */
+#define SBIAS_BYPASS (1 << 23)
+
+/* MCFG */
+#define MDDR_LPDDR2_CLK_STOP_IDLE(n) ((n) << 24)
+#define PD_IDLE(n) ((n) << 8)
+#define MDDR_EN (2 << 22)
+#define LPDDR2_EN (3 << 22)
+#define DDR2_EN (0 << 5)
+#define DDR3_EN (1 << 5)
+#define LPDDR2_S2 (0 << 6)
+#define LPDDR2_S4 (1 << 6)
+#define MDDR_LPDDR2_BL_2 (0 << 20)
+#define MDDR_LPDDR2_BL_4 (1 << 20)
+#define MDDR_LPDDR2_BL_8 (2 << 20)
+#define MDDR_LPDDR2_BL_16 (3 << 20)
+#define DDR2_DDR3_BL_4 (0)
+#define DDR2_DDR3_BL_8 (1)
+#define TFAW_CFG(n) (((n)-4) << 18)
+#define PD_EXIT_SLOW (0 << 17)
+#define PD_EXIT_FAST (1 << 17)
+#define PD_TYPE(n) ((n) << 16)
+#define BURSTLENGTH_CFG(n) (((n) >> 1) << 20)
+
+/* POWCTL */
+#define POWER_UP_START (1 << 0)
+
+/* POWSTAT */
+#define POWER_UP_DONE (1 << 0)
+
+/* MCMD */
+#define DESELECT_CMD (0)
+#define PREA_CMD (1)
+#define REF_CMD (2)
+#define MRS_CMD (3)
+#define ZQCS_CMD (4)
+#define ZQCL_CMD (5)
+#define RSTL_CMD (6)
+#define MRR_CMD (8)
+#define DPDE_CMD (9)
+
+#define LPDDR2_MA(n) (((n) & 0xff) << 4)
+
+#define START_CMD (1u << 31)
+
+/* DEVTODEV */
+#define BUSWRTORD(n) ((n) << 4)
+#define BUSRDTOWR(n) ((n) << 2)
+#define BUSRDTORD(n) ((n) << 0)
+
+/* GRF_SOC_CON0 */
+#define MSCH_MAINDDR3(ch, n) (((n) << (3 + (ch))) \
+ | ((1 << (3 + (ch))) << 16))
+
+/* GRF_SOC_CON2 */
+#define PUBL_LPDDR3_EN(ch, n) RK_CLRSETBITS(1 << (10 + (3 * (ch))), \
+ (n) << (10 + (3 * (ch))))
+#define PCTL_LPDDR3_ODT_EN(ch, n) RK_CLRSETBITS(1 << (9 + (3 * (ch))), \
+ (n) << (9 + (3 * (ch))))
+#define PCTL_BST_DISABLE(ch, n) RK_CLRSETBITS(1 << (8 + (3 * (ch))), \
+ (n) << (8 + (3 * (ch))))
+
+/* mr1 for ddr3 */
+#define DDR3_DLL_ENABLE (0)
+#define DDR3_DLL_DISABLE (1)
+
+/*
+ * sys_reg bitfield struct
+ * [31] row_3_4_ch1
+ * [30] row_3_4_ch0
+ * [29:28] chinfo
+ * [27] rank_ch1
+ * [26:25] col_ch1
+ * [24] bk_ch1
+ * [23:22] cs0_row_ch1
+ * [21:20] cs1_row_ch1
+ * [19:18] bw_ch1
+ * [17:16] dbw_ch1;
+ * [15:13] ddrtype
+ * [12] channelnum
+ * [11] rank_ch0
+ * [10:9] col_ch0
+ * [8] bk_ch0
+ * [7:6] cs0_row_ch0
+ * [5:4] cs1_row_ch0
+ * [3:2] bw_ch0
+ * [1:0] dbw_ch0
+*/
+#define SYS_REG_DDRTYPE(n) ((n) << 13)
+#define SYS_REG_NUM_CH(n) (((n) - 1) << 12)
+#define SYS_REG_ROW_3_4(n, ch) ((n) << (30 + (ch)))
+#define SYS_REG_CHINFO(ch) (1 << (28 + (ch)))
+#define SYS_REG_RANK(n, ch) (((n) - 1) << (11 + ((ch) * 16)))
+#define SYS_REG_COL(n, ch) (((n) - 9) << (9 + ((ch) * 16)))
+#define SYS_REG_BK(n, ch) (((n) == 3 ? 0 : 1) \
+ << (8 + ((ch) * 16)))
+#define SYS_REG_CS0_ROW(n, ch) (((n) - 13) << (6 + ((ch) * 16)))
+#define SYS_REG_CS1_ROW(n, ch) (((n) - 13) << (4 + ((ch) * 16)))
+#define SYS_REG_BW(n, ch) ((2 >> (n)) << (2 + ((ch) * 16)))
+#define SYS_REG_DBW(n, ch) ((2 >> (n)) << (0 + ((ch) * 16)))
+
+static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
+{
+ int i;
+ for (i = 0; i < n / sizeof(u32); i++) {
+ writel(*src, dest);
+ src++;
+ dest++;
+ }
+}
+
+static void phy_pctrl_reset(struct rk3288_ddr_publ_regs *ddr_publ_regs,
+ u32 channel)
+{
+ int i;
+ rkclk_ddr_reset(channel, 1, 1);
+ udelay(1);
+ clrbits_le32(&ddr_publ_regs->acdllcr, ACDLLCR_DLLSRST);
+ for (i = 0; i < 4; i++)
+ clrbits_le32(&ddr_publ_regs->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
+
+ udelay(10);
+ setbits_le32(&ddr_publ_regs->acdllcr, ACDLLCR_DLLSRST);
+ for (i = 0; i < 4; i++)
+ setbits_le32(&ddr_publ_regs->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
+
+ udelay(10);
+ rkclk_ddr_reset(channel, 1, 0);
+ udelay(10);
+ rkclk_ddr_reset(channel, 0, 0);
+ udelay(1);
+}
+
+static void phy_dll_bypass_set(struct rk3288_ddr_publ_regs *ddr_publ_regs,
+ u32 freq)
+{
+ int i;
+ if (freq <= 250000000) {
+ if (freq <= 150000000)
+ clrbits_le32(&ddr_publ_regs->dllgcr, SBIAS_BYPASS);
+ else
+ setbits_le32(&ddr_publ_regs->dllgcr, SBIAS_BYPASS);
+ setbits_le32(&ddr_publ_regs->acdllcr, ACDLLCR_DLLDIS);
+ for (i = 0; i < 4; i++)
+ setbits_le32(&ddr_publ_regs->datx8[i].dxdllcr,
+ DXDLLCR_DLLDIS);
+
+ setbits_le32(&ddr_publ_regs->pir, PIR_DLLBYP);
+ } else {
+ clrbits_le32(&ddr_publ_regs->dllgcr, SBIAS_BYPASS);
+ clrbits_le32(&ddr_publ_regs->acdllcr, ACDLLCR_DLLDIS);
+ for (i = 0; i < 4; i++)
+ clrbits_le32(&ddr_publ_regs->datx8[i].dxdllcr,
+ DXDLLCR_DLLDIS);
+
+ clrbits_le32(&ddr_publ_regs->pir, PIR_DLLBYP);
+ }
+}
+
+static void dfi_cfg(struct rk3288_ddr_pctl_regs *ddr_pctl_regs, u32 dramtype)
+{
+ writel(DFI_INIT_START, &ddr_pctl_regs->dfistcfg0);
+ writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN,
+ &ddr_pctl_regs->dfistcfg1);
+ writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &ddr_pctl_regs->dfistcfg2);
+ writel(TLP_RESP_TIME(7) | LP_SR_EN | LP_PD_EN,
+ &ddr_pctl_regs->dfilpcfg0);
+
+ writel(TCTRL_DELAY_TIME(2), &ddr_pctl_regs->dfitctrldelay);
+ writel(TPHY_WRDATA_TIME(1), &ddr_pctl_regs->dfitphywrdata);
+ writel(TPHY_RDLAT_TIME(0xf), &ddr_pctl_regs->dfitphyrdlat);
+ writel(TDRAM_CLK_DIS_TIME(2), &ddr_pctl_regs->dfitdramclkdis);
+ writel(TDRAM_CLK_EN_TIME(2), &ddr_pctl_regs->dfitdramclken);
+ writel(0x1, &ddr_pctl_regs->dfitphyupdtype0);
+
+ /* cs0 and cs1 write odt enable */
+ writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
+ &ddr_pctl_regs->dfiodtcfg);
+ /* odt write length */
+ writel(ODT_LEN_BL8_W(7), &ddr_pctl_regs->dfiodtcfg1);
+ /* phyupd and ctrlupd disabled */
+ writel(0, &ddr_pctl_regs->dfiupdcfg);
+}
+
+static void pctl_cfg(u32 channel,
+ const struct rk3288_sdram_params *sdram_params)
+{
+ unsigned int burstlen;
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs = rk3288_ddr_pctl[channel];
+ burstlen = (sdram_params->noc_timing >> 18) & 0x7;
+ copy_to_reg(&ddr_pctl_regs->togcnt1u,
+ &(sdram_params->pctl_timing.togcnt1u),
+ sizeof(sdram_params->pctl_timing));
+ switch (sdram_params->dramtype) {
+ case LPDDR3:
+ writel(sdram_params->pctl_timing.tcl - 1,
+ &ddr_pctl_regs->dfitrddataen);
+ writel(sdram_params->pctl_timing.tcwl,
+ &ddr_pctl_regs->dfitphywrlat);
+ writel(LPDDR2_S4 | MDDR_LPDDR2_CLK_STOP_IDLE(0) | LPDDR2_EN
+ | BURSTLENGTH_CFG(burstlen) | TFAW_CFG(6) | PD_EXIT_FAST
+ | PD_TYPE(1) | PD_IDLE(0), &ddr_pctl_regs->mcfg);
+ writel(MSCH_MAINDDR3(channel, 0), &rk3288_grf->soc_con0);
+
+ writel(PUBL_LPDDR3_EN(channel, 1)
+ | PCTL_BST_DISABLE(channel, 1)
+ | PCTL_LPDDR3_ODT_EN(channel, 1),
+ &rk3288_grf->soc_con2);
+
+ break;
+ case DDR3:
+ if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE)
+ writel(sdram_params->pctl_timing.tcl - 3,
+ &ddr_pctl_regs->dfitrddataen);
+ else
+ writel(sdram_params->pctl_timing.tcl - 2,
+ &ddr_pctl_regs->dfitrddataen);
+ writel(sdram_params->pctl_timing.tcwl - 1,
+ &ddr_pctl_regs->dfitphywrlat);
+ writel(MDDR_LPDDR2_CLK_STOP_IDLE(0) | DDR3_EN
+ | DDR2_DDR3_BL_8 | TFAW_CFG(5) | PD_EXIT_SLOW
+ | PD_TYPE(1) | PD_IDLE(0), &ddr_pctl_regs->mcfg);
+ writel(MSCH_MAINDDR3(channel, 1), &rk3288_grf->soc_con0);
+
+ writel(PUBL_LPDDR3_EN(channel, 0)
+ | PCTL_BST_DISABLE(channel, 0)
+ | PCTL_LPDDR3_ODT_EN(channel, 0),
+ &rk3288_grf->soc_con2);
+
+ break;
+ }
+
+ setbits_le32(&ddr_pctl_regs->scfg, 1);
+}
+
+static void phy_cfg(u32 channel, const struct rk3288_sdram_params *sdram_params)
+{
+ u32 i;
+ struct rk3288_ddr_publ_regs *ddr_publ_regs = rk3288_ddr_publ[channel];
+ struct rk3288_msch_regs *msch_regs = rk3288_msch[channel];
+
+ /* DDR PHY Timing */
+ copy_to_reg(&ddr_publ_regs->dtpr[0],
+ &(sdram_params->phy_timing.dtpr0),
+ sizeof(sdram_params->phy_timing));
+ writel(sdram_params->noc_timing, &msch_regs->ddrtiming);
+ writel(0x3f, &msch_regs->readlatency);
+ writel(sdram_params->noc_activate, &msch_regs->activate);
+ writel(BUSWRTORD(2) | BUSRDTOWR(2) | BUSRDTORD(1),
+ &msch_regs->devtodev);
+ writel(PRT_ITMSRST(8) | PRT_DLLLOCK(2750) | PRT_DLLSRST(27),
+ &ddr_publ_regs->ptr[0]);
+ /* tDINIT1=400ns (533MHz), tDINIT0=500us (533MHz) */
+ writel(PRT_DINIT1(213) | PRT_DINIT0(266525), &ddr_publ_regs->ptr[1]);
+ /* tDINIT3=1us (533MHz), tDINIT2=200us (533MHz) */
+ writel(PRT_DINIT3(534) | PRT_DINIT2(106610), &ddr_publ_regs->ptr[2]);
+
+ switch (sdram_params->dramtype) {
+ case LPDDR3:
+ clrsetbits_le32(&ddr_publ_regs->pgcr, 0x1F, PGCR_DFTLMT(0)
+ | PGCR_DFTCMP(0) | PGCR_DQSCFG(1) | PGCR_ITMDMD(0));
+ /* DDRMODE select LPDDR3 */
+ clrsetbits_le32(&ddr_publ_regs->dcr, DDRMD_MSK,
+ DDRMD_CFG(DDRMD_LPDDR2_LPDDR3));
+ clrsetbits_le32(&ddr_publ_regs->dxccr, DQSNRES_MSK | DQSRES_MSK,
+ DQSRES_CFG(4) | DQSNRES_CFG(0xc));
+ i = TDQSCKMAX_VAL(readl(&ddr_publ_regs->dtpr[1]))
+ - TDQSCK_VAL(readl(&ddr_publ_regs->dtpr[1]));
+ clrsetbits_le32(&ddr_publ_regs->dsgcr, DQSGE_MSK | DQSGX_MSK,
+ DQSGE_CFG(i) | DQSGX_CFG(i));
+ break;
+ case DDR3:
+ clrbits_le32(&ddr_publ_regs->pgcr, 0x1f);
+ clrsetbits_le32(&ddr_publ_regs->dcr, DDRMD_MSK,
+ DDRMD_CFG(DDRMD_DDR3));
+ break;
+ }
+ if (sdram_params->odt) {
+ /*dynamic RTT enable */
+ for (i = 0; i < 4; i++)
+ setbits_le32(&ddr_publ_regs->datx8[i].dxgcr,
+ DQSRTT | DQRTT);
+ } else {
+ /*dynamic RTT disable */
+ for (i = 0; i < 4; i++)
+ clrbits_le32(&ddr_publ_regs->datx8[i].dxgcr,
+ DQSRTT | DQRTT);
+
+ }
+}
+
+static void phy_init(struct rk3288_ddr_publ_regs *ddr_publ_regs)
+{
+ setbits_le32(&ddr_publ_regs->pir, PIR_INIT | PIR_DLLSRST
+ | PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR);
+ udelay(1);
+ while ((readl(&ddr_publ_regs->pgsr) &
+ (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) !=
+ (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE))
+ ;
+}
+
+static void send_command(struct rk3288_ddr_pctl_regs *ddr_pctl_regs, u32 rank,
+ u32 cmd, u32 arg)
+{
+ writel((START_CMD | (rank << 20) | arg | cmd), &ddr_pctl_regs->mcmd);
+ udelay(1);
+ while (readl(&ddr_pctl_regs->mcmd) & START_CMD)
+ ;
+}
+
+static void memory_init(struct rk3288_ddr_publ_regs *ddr_publ_regs,
+ u32 dramtype)
+{
+ setbits_le32(&ddr_publ_regs->pir,
+ (PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP
+ | PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC
+ | (dramtype == DDR3 ? PIR_DRAMRST : 0)));
+ udelay(1);
+ while ((readl(&ddr_publ_regs->pgsr) & (PGSR_IDONE | PGSR_DLDONE))
+ != (PGSR_IDONE | PGSR_DLDONE))
+ ;
+}
+
+static void move_to_config_state(struct rk3288_ddr_publ_regs *ddr_publ_regs,
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs)
+{
+ unsigned int state;
+
+ while (1) {
+ state = readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK;
+
+ switch (state) {
+ case LOW_POWER:
+ writel(WAKEUP_STATE, &ddr_pctl_regs->sctl);
+ while ((readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK)
+ != ACCESS)
+ ;
+ /* wait DLL lock */
+ while ((readl(&ddr_publ_regs->pgsr) & PGSR_DLDONE)
+ != PGSR_DLDONE)
+ ;
+ /* if at low power state,need wakeup first,
+ * and then enter the config
+ * so here no break.
+ */
+ case ACCESS:
+ case INIT_MEM:
+ writel(CFG_STATE, &ddr_pctl_regs->sctl);
+ while ((readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK)
+ != CONFIG)
+ ;
+ break;
+ case CONFIG:
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+static void set_bandwidth_ratio(u32 channel, u32 n)
+{
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs = rk3288_ddr_pctl[channel];
+ struct rk3288_ddr_publ_regs *ddr_publ_regs = rk3288_ddr_publ[channel];
+ struct rk3288_msch_regs *msch_regs = rk3288_msch[channel];
+
+ if (n == 1) {
+ setbits_le32(&ddr_pctl_regs->ppcfg, 1);
+ writel(RK_SETBITS(1 << (8 + channel)),
+ &rk3288_grf->soc_con0);
+ setbits_le32(&msch_regs->ddrtiming, 1 << 31);
+ /* Data Byte disable*/
+ clrbits_le32(&ddr_publ_regs->datx8[2].dxgcr, 1);
+ clrbits_le32(&ddr_publ_regs->datx8[3].dxgcr, 1);
+ /*disable DLL */
+ setbits_le32(&ddr_publ_regs->datx8[2].dxdllcr,
+ DXDLLCR_DLLDIS);
+ setbits_le32(&ddr_publ_regs->datx8[3].dxdllcr,
+ DXDLLCR_DLLDIS);
+ } else {
+ clrbits_le32(&ddr_pctl_regs->ppcfg, 1);
+ writel(RK_CLRBITS(1 << (8 + channel)),
+ &rk3288_grf->soc_con0);
+ clrbits_le32(&msch_regs->ddrtiming, 1 << 31);
+ /* Data Byte enable*/
+ setbits_le32(&ddr_publ_regs->datx8[2].dxgcr, 1);
+ setbits_le32(&ddr_publ_regs->datx8[3].dxgcr, 1);
+
+ /*enable DLL */
+ clrbits_le32(&ddr_publ_regs->datx8[2].dxdllcr,
+ DXDLLCR_DLLDIS);
+ clrbits_le32(&ddr_publ_regs->datx8[3].dxdllcr,
+ DXDLLCR_DLLDIS);
+ /* reset DLL */
+ clrbits_le32(&ddr_publ_regs->datx8[2].dxdllcr,
+ DXDLLCR_DLLSRST);
+ clrbits_le32(&ddr_publ_regs->datx8[3].dxdllcr,
+ DXDLLCR_DLLSRST);
+ udelay(10);
+ setbits_le32(&ddr_publ_regs->datx8[2].dxdllcr,
+ DXDLLCR_DLLSRST);
+ setbits_le32(&ddr_publ_regs->datx8[3].dxdllcr,
+ DXDLLCR_DLLSRST);
+ }
+ setbits_le32(&ddr_pctl_regs->dfistcfg0, 1 << 2);
+
+}
+
+static int data_training(u32 channel,
+ const struct rk3288_sdram_params *sdram_params)
+{
+ unsigned int j;
+ int ret = 0;
+ u32 rank;
+ int i;
+ u32 step[2] = { PIR_QSTRN, PIR_RVTRN };
+ struct rk3288_ddr_publ_regs *ddr_publ_regs = rk3288_ddr_publ[channel];
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs = rk3288_ddr_pctl[channel];
+
+ /* disable auto refresh */
+ writel(0, &ddr_pctl_regs->trefi);
+
+ if (sdram_params->dramtype != LPDDR3)
+ setbits_le32(&ddr_publ_regs->pgcr, PGCR_DQSCFG(1));
+ rank = sdram_params->ch[channel].rank | 1;
+ for (j = 0; j < ARRAY_SIZE(step); j++) {
+ /*
+ * trigger QSTRN and RVTRN
+ * clear DTDONE status
+ */
+ setbits_le32(&ddr_publ_regs->pir, PIR_CLRSR);
+
+ /* trigger DTT */
+ setbits_le32(&ddr_publ_regs->pir,
+ PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP |
+ PIR_CLRSR);
+ udelay(1);
+ /* wait echo byte DTDONE */
+ while ((readl(&ddr_publ_regs->datx8[0].dxgsr[0]) & rank)
+ != rank)
+ ;
+ while ((readl(&ddr_publ_regs->datx8[1].dxgsr[0]) & rank)
+ != rank)
+ ;
+ if (!(readl(&ddr_pctl_regs->ppcfg) & 1)) {
+ while ((readl(&ddr_publ_regs->datx8[2].dxgsr[0])
+ & rank) != rank)
+ ;
+ while ((readl(&ddr_publ_regs->datx8[3].dxgsr[0])
+ & rank) != rank)
+ ;
+ }
+ if (readl(&ddr_publ_regs->pgsr) &
+ (PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) {
+ ret = -1;
+ break;
+ }
+ }
+ /* send some auto refresh to complement the lost while DTT */
+ for (i = 0; i < (rank > 1 ? 4 : 2); i++)
+ send_command(ddr_pctl_regs, rank, REF_CMD, 0);
+
+ if (sdram_params->dramtype != LPDDR3)
+ clrbits_le32(&ddr_publ_regs->pgcr, PGCR_DQSCFG(1));
+
+ /* resume auto refresh */
+ writel(sdram_params->pctl_timing.trefi, &ddr_pctl_regs->trefi);
+
+ return ret;
+}
+
+static void move_to_access_state(u32 chnum)
+{
+ struct rk3288_ddr_publ_regs *ddr_publ_regs = rk3288_ddr_publ[chnum];
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs = rk3288_ddr_pctl[chnum];
+
+ unsigned int state;
+
+ while (1) {
+ state = readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK;
+
+ switch (state) {
+ case LOW_POWER:
+ if (LP_TRIG_VAL(readl(&ddr_pctl_regs->stat)) == 1)
+ return;
+
+ writel(WAKEUP_STATE, &ddr_pctl_regs->sctl);
+ while ((readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK)
+ != ACCESS)
+ ;
+ /* wait DLL lock */
+ while ((readl(&ddr_publ_regs->pgsr) & PGSR_DLDONE)
+ != PGSR_DLDONE)
+ ;
+ break;
+ case INIT_MEM:
+ writel(CFG_STATE, &ddr_pctl_regs->sctl);
+ while ((readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK)
+ != CONFIG)
+ ;
+ case CONFIG:
+ writel(GO_STATE, &ddr_pctl_regs->sctl);
+ while ((readl(&ddr_pctl_regs->stat) & PCTL_STAT_MSK)
+ == CONFIG)
+ ;
+ break;
+ case ACCESS:
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+static void dram_cfg_rbc(u32 chnum,
+ const struct rk3288_sdram_params *sdram_params)
+{
+ struct rk3288_ddr_publ_regs *ddr_publ_regs = rk3288_ddr_publ[chnum];
+ struct rk3288_msch_regs *msch_regs = rk3288_msch[chnum];
+
+ if (sdram_params->ch[chnum].bk == 3)
+ clrsetbits_le32(&ddr_publ_regs->dcr, PDQ_MSK, PDQ_CFG(1));
+ else
+ clrbits_le32(&ddr_publ_regs->dcr, PDQ_MSK);
+
+ writel(sdram_params->ddrconfig, &msch_regs->ddrconf);
+}
+
+static void dram_all_config(const struct rk3288_sdram_params *sdram_params)
+{
+ u32 sys_reg = 0;
+ unsigned int channel;
+
+ sys_reg |= SYS_REG_DDRTYPE(sdram_params->dramtype);
+ sys_reg |= SYS_REG_NUM_CH(sdram_params->num_channels);
+ for (channel = 0; channel < sdram_params->num_channels; channel++) {
+ const struct rk3288_sdram_channel *info =
+ &(sdram_params->ch[channel]);
+ sys_reg |= SYS_REG_ROW_3_4(info->row_3_4, channel);
+ sys_reg |= SYS_REG_CHINFO(channel);
+ sys_reg |= SYS_REG_RANK(info->rank, channel);
+ sys_reg |= SYS_REG_COL(info->col, channel);
+ sys_reg |= SYS_REG_BK(info->bk, channel);
+ sys_reg |= SYS_REG_CS0_ROW(info->cs0_row, channel);
+ sys_reg |= SYS_REG_CS1_ROW(info->cs1_row, channel);
+ sys_reg |= SYS_REG_BW(info->bw, channel);
+ sys_reg |= SYS_REG_DBW(info->dbw, channel);
+
+ dram_cfg_rbc(channel, sdram_params);
+ }
+ writel(sys_reg, &rk3288_pmu->sys_reg[2]);
+ writel(RK_CLRSETBITS(0x1F, sdram_params->stride),
+ &rk3288_sgrf->soc_con2);
+}
+
+void sdram_init(const struct rk3288_sdram_params *sdram_params)
+{
+ int channel;
+ int zqcr;
+ printk(BIOS_INFO, "Starting SDRAM initialization...\n");
+
+ if (sdram_params->ddr_freq > 533000000)
+ die("SDRAM frequency is to high!");
+
+ rkclk_configure_ddr(sdram_params->ddr_freq);
+
+ for (channel = 0; channel < sdram_params->num_channels; channel++) {
+ struct rk3288_ddr_pctl_regs *ddr_pctl_regs =
+ rk3288_ddr_pctl[channel];
+ struct rk3288_ddr_publ_regs *ddr_publ_regs =
+ rk3288_ddr_publ[channel];
+
+ phy_pctrl_reset(ddr_publ_regs, channel);
+ phy_dll_bypass_set(ddr_publ_regs, sdram_params->ddr_freq);
+
+ dfi_cfg(ddr_pctl_regs, sdram_params->dramtype);
+
+ pctl_cfg(channel, sdram_params);
+
+ phy_cfg(channel, sdram_params);
+
+ phy_init(ddr_publ_regs);
+
+ writel(POWER_UP_START, &ddr_pctl_regs->powctl);
+ while (!(readl(&ddr_pctl_regs->powstat) & POWER_UP_DONE))
+ ;
+ send_command(ddr_pctl_regs, 3, DESELECT_CMD, 0);
+ udelay(1);
+ send_command(ddr_pctl_regs, 3, PREA_CMD, 0);
+
+ memory_init(ddr_publ_regs, sdram_params->dramtype);
+ move_to_config_state(ddr_publ_regs, ddr_pctl_regs);
+ set_bandwidth_ratio(channel, sdram_params->ch[channel].bw);
+ /*
+ * set cs
+ * CS0, n=1
+ * CS1, n=2
+ * CS0 & CS1, n = 3
+ */
+ clrsetbits_le32(&ddr_publ_regs->pgcr, 0xF << 18,
+ (sdram_params->ch[channel].rank | 1) << 18);
+ /* DS=40ohm,ODT=155ohm */
+ zqcr = ZDEN(1) | PU_ONDIE(0x2) | PD_ONDIE(0x2)
+ | PU_OUTPUT(0x19) | PD_OUTPUT(0x19);
+ writel(zqcr, &ddr_publ_regs->zq1cr[0]);
+ writel(zqcr, &ddr_publ_regs->zq0cr[0]);
+
+ if (sdram_params->dramtype == LPDDR3) {
+ /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+ udelay(10);
+ if (channel == 0) {
+ writel(0, &ddr_pctl_regs->mrrcfg0);
+ send_command(ddr_pctl_regs, 1, MRR_CMD,
+ LPDDR2_MA(0x8));
+ /* S8 */
+ if ((readl(&ddr_pctl_regs->mrrstat0) & 0x3)
+ != 3)
+ die("SDRAM initialization failed!");
+ }
+ }
+
+ if (-1 == data_training(channel, sdram_params)) {
+ if (sdram_params->dramtype == LPDDR3) {
+ rkclk_ddr_phy_ctl_reset(channel, 1);
+ udelay(10);
+ rkclk_ddr_phy_ctl_reset(channel, 0);
+ udelay(10);
+ }
+ die("SDRAM initialization failed!");
+ }
+
+ if (sdram_params->dramtype == LPDDR3) {
+ u32 i;
+ writel(0, &ddr_pctl_regs->mrrcfg0);
+ for (i = 0; i < 17; i++)
+ send_command(ddr_pctl_regs, 1, MRR_CMD,
+ LPDDR2_MA(i));
+ }
+ move_to_access_state(channel);
+ }
+ dram_all_config(sdram_params);
+ printk(BIOS_INFO, "Finish SDRAM initialization...\n");
+}
diff --git a/src/soc/rockchip/rk3288/sdram.h b/src/soc/rockchip/rk3288/sdram.h
new file mode 100644
index 0000000000..1da14b7ed5
--- /dev/null
+++ b/src/soc/rockchip/rk3288/sdram.h
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Rockchip Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SOC_ROCKCHIP_RK3288_SDRAM_H__
+#define __SOC_ROCKCHIP_RK3288_SDRAM_H__
+
+#include <arch/io.h>
+
+enum {
+ DDR3 = 3,
+ LPDDR3 = 6,
+ UNUSED = 0xFF,
+};
+
+struct rk3288_sdram_channel {
+ u8 rank;
+ u8 col;
+ u8 bk;
+ u8 bw;
+ u8 dbw;
+ u8 row_3_4;
+ u8 cs0_row;
+ u8 cs1_row;
+};
+
+struct rk3288_sdram_pctl_timing {
+ u32 togcnt1u;
+ u32 tinit;
+ u32 trsth;
+ u32 togcnt100n;
+ u32 trefi;
+ u32 tmrd;
+ u32 trfc;
+ u32 trp;
+ u32 trtw;
+ u32 tal;
+ u32 tcl;
+ u32 tcwl;
+ u32 tras;
+ u32 trc;
+ u32 trcd;
+ u32 trrd;
+ u32 trtp;
+ u32 twr;
+ u32 twtr;
+ u32 texsr;
+ u32 txp;
+ u32 txpdll;
+ u32 tzqcs;
+ u32 tzqcsi;
+ u32 tdqs;
+ u32 tcksre;
+ u32 tcksrx;
+ u32 tcke;
+ u32 tmod;
+ u32 trstl;
+ u32 tzqcl;
+ u32 tmrr;
+ u32 tckesr;
+ u32 tdpd;
+};
+check_member(rk3288_sdram_pctl_timing, tdpd, 0x144 - 0xc0);
+
+struct rk3288_sdram_phy_timing {
+ u32 dtpr0;
+ u32 dtpr1;
+ u32 dtpr2;
+ u32 mr[4];
+};
+
+struct rk3288_sdram_params {
+ struct rk3288_sdram_channel ch[2];
+ struct rk3288_sdram_pctl_timing pctl_timing;
+ struct rk3288_sdram_phy_timing phy_timing;
+ u32 noc_timing;
+ u32 noc_activate;
+ u32 ddrconfig;
+ u32 ddr_freq;
+ u8 dramtype;
+ u8 num_channels;
+ u8 stride;
+ u8 odt;
+};
+
+void sdram_init(const struct rk3288_sdram_params *sdram_params);
+u32 sdram_get_ram_code(void);
+const struct rk3288_sdram_params *get_sdram_config(void);
+#endif