rk3288: add ddr driver

Supports DDR3 and LPDDR3.Supports dual channel.ddr max freq is 533mhz.
ddr timing config file in src\mainboard\google\veyron\sdram_inf
Remove dpll init in rk clk_init(), add rkclk_configure_ddr(unsigned int hz).

BUG=chrome-os-partner:29778
TEST=Build coreboot

Change-Id: I429eb0b8c365c6285fb6cfef008b41776cc9c2d9
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 52838c68fe6963285c974af5dc5837e819efc321
Original-Change-Id: I6ddfe30b8585002b45060fe998c9238cbb611c05
Original-Signed-off-by: jinkun.hong <jinkun.hong@rock-chips.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/209465
Original-Reviewed-by: Julius Werner <jwerner@chromium.org>
Original-Commit-Queue: Julius Werner <jwerner@chromium.org>
Reviewed-on: http://review.coreboot.org/8865
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins)
This commit is contained in:
Jinkun Hong 2014-08-28 09:37:22 -07:00 committed by Patrick Georgi
parent d5fb66e060
commit c33ce3554d
13 changed files with 1498 additions and 14 deletions

View File

@ -18,6 +18,7 @@
##
romstage-y += romstage.c
romstage-y += sdram_configs.c
ramstage-y += mainboard.c
ramstage-y += chromeos.c

View File

@ -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);

View File

@ -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];
}

View File

@ -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
},

View File

@ -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
},

View File

@ -0,0 +1,3 @@
{
.dramtype= UNUSED
},

View File

@ -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

View File

@ -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;

View File

@ -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__ */

View File

@ -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)

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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