当前位置:网站首页>Imx6ul development board porting EMMC startup process of mainline u-boot
Imx6ul development board porting EMMC startup process of mainline u-boot
2022-06-11 12:39:00 【Zhaokaixin xiansen】
Directly in U-Boot The source code downloaded from the official website can be compiled directly in our imx6ul Running on the development board , But what I read DRAM The capacity is wrong , Now analyze the startup process , Confirm what caused the problem . First of all, it must be a well-known board_init_f function
The function path file is board/engicam/common/spl.c
void board_init_f(ulong dummy)
{
ccgr_init();
/* setup AIPS and disable watchdog */
arch_cpu_init();
if (!(is_mx6ul()))
gpr_init();
/* iomux */
SETUP_IOMUX_PADS(uart_pads);
/* setup GP timer */
timer_init();
/* UART clocks enabled and gd valid - init serial console */
preloader_console_init();
/* DDR initialization */
spl_dram_init(); // This is the function we need to focus on
}
The expansion is the following function
In the file u-boot/board/engicam/common/spl.c in
static void spl_dram_init(void)
{
mx6ul_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs);
mx6_dram_cfg(&ddr_sysinfo, &mx6_mmcd_calib, &mem_ddr);
udelay(100);
}
And then it goes on
u-boot/arch/arm/mach-imx/mx6/ddr.c
void mx6ul_dram_iocfg(unsigned width,
const struct mx6ul_iomux_ddr_regs *ddr,
const struct mx6ul_iomux_grp_regs *grp)
{
struct mx6ul_iomux_ddr_regs *mx6_ddr_iomux;
struct mx6ul_iomux_grp_regs *mx6_grp_iomux;
mx6_ddr_iomux = (struct mx6ul_iomux_ddr_regs *)MX6UL_IOM_DDR_BASE;
mx6_grp_iomux = (struct mx6ul_iomux_grp_regs *)MX6UL_IOM_GRP_BASE;
/* DDR IO TYPE */
writel(grp->grp_ddr_type, &mx6_grp_iomux->grp_ddr_type);
writel(grp->grp_ddrpke, &mx6_grp_iomux->grp_ddrpke);
/* CLOCK */
writel(ddr->dram_sdclk_0, &mx6_ddr_iomux->dram_sdclk_0);
/* ADDRESS */
writel(ddr->dram_cas, &mx6_ddr_iomux->dram_cas);
writel(ddr->dram_ras, &mx6_ddr_iomux->dram_ras);
writel(grp->grp_addds, &mx6_grp_iomux->grp_addds);
/* Control */
writel(ddr->dram_reset, &mx6_ddr_iomux->dram_reset);
writel(ddr->dram_sdba2, &mx6_ddr_iomux->dram_sdba2);
writel(ddr->dram_odt0, &mx6_ddr_iomux->dram_odt0);
writel(ddr->dram_odt1, &mx6_ddr_iomux->dram_odt1);
writel(grp->grp_ctlds, &mx6_grp_iomux->grp_ctlds);
/* Data Strobes */
writel(grp->grp_ddrmode_ctl, &mx6_grp_iomux->grp_ddrmode_ctl);
writel(ddr->dram_sdqs0, &mx6_ddr_iomux->dram_sdqs0);
writel(ddr->dram_sdqs1, &mx6_ddr_iomux->dram_sdqs1);
/* Data */
writel(grp->grp_ddrmode, &mx6_grp_iomux->grp_ddrmode);
writel(grp->grp_b0ds, &mx6_grp_iomux->grp_b0ds);
writel(grp->grp_b1ds, &mx6_grp_iomux->grp_b1ds);
writel(ddr->dram_dqm0, &mx6_ddr_iomux->dram_dqm0);
writel(ddr->dram_dqm1, &mx6_ddr_iomux->dram_dqm1);
}
arch/arm/mach-imx/mx6/ddr.c
void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo,
const struct mx6_mmdc_calibration *calib,
const void *ddr_cfg)
{
if (sysinfo->ddr_type == DDR_TYPE_DDR3) {
mx6_ddr3_cfg(sysinfo, calib, ddr_cfg);// We are DDR3, Perform here
} else if (sysinfo->ddr_type == DDR_TYPE_LPDDR2) {
mx6_lpddr2_cfg(sysinfo, calib, ddr_cfg);
} else {
puts("Unsupported ddr type\n");
hang();
}
}
void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo,
const struct mx6_mmdc_calibration *calib,
const struct mx6_ddr3_cfg *ddr3_cfg)
{
volatile struct mmdc_p_regs *mmdc0;
volatile struct mmdc_p_regs *mmdc1;
struct src *src_regs = (struct src *)SRC_BASE_ADDR;
u8 soc_boot_cfg3 = (readl(&src_regs->sbmr1) >> 16) & 0xff;
u32 val;
u8 tcke, tcksrx, tcksre, txpdll, taofpd, taonpd, trrd;
u8 todtlon, taxpd, tanpd, tcwl, txp, tfaw, tcl;
u8 todt_idle_off = 0x4; /* from DDR3 Script Aid spreadsheet */
u16 trcd, trc, tras, twr, tmrd, trtp, trp, twtr, trfc, txs, txpr;
u16 cs0_end;
u16 tdllk = 0x1ff; /* DLL locking time: 512 cycles (JEDEC DDR3) */
u8 coladdr;
int clkper; /* clock period in picoseconds */
int clock; /* clock freq in MHz */
int cs;
u16 mem_speed = ddr3_cfg->mem_speed;
mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
if (!is_mx6sx() && !is_mx6ul() && !is_mx6ull() && !is_mx6sl())
mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
/* Limit mem_speed for MX6D/MX6Q */
if (is_mx6dq() || is_mx6dqp()) {
if (mem_speed > 1066)
mem_speed = 1066; /* 1066 MT/s */
tcwl = 4;
}
/* Limit mem_speed for MX6S/MX6DL */
else {
if (mem_speed > 800)
mem_speed = 800; /* 800 MT/s */
tcwl = 3;
}
clock = mem_speed / 2;
/* * Data rate of 1066 MT/s requires 533 MHz DDR3 clock, but MX6D/Q supports * up to 528 MHz, so reduce the clock to fit chip specs */
if (is_mx6dq() || is_mx6dqp()) {
if (clock > 528)
clock = 528; /* 528 MHz */
}
clkper = (1000 * 1000) / clock; /* pico seconds */
todtlon = tcwl;
taxpd = tcwl;
tanpd = tcwl;
switch (ddr3_cfg->density) {
case 1: /* 1Gb per chip */
trfc = DIV_ROUND_UP(110000, clkper) - 1;
txs = DIV_ROUND_UP(120000, clkper) - 1;
break;
case 2: /* 2Gb per chip */
trfc = DIV_ROUND_UP(160000, clkper) - 1;
txs = DIV_ROUND_UP(170000, clkper) - 1;
break;
case 4: /* 4Gb per chip */
trfc = DIV_ROUND_UP(260000, clkper) - 1;
txs = DIV_ROUND_UP(270000, clkper) - 1;
break;
case 8: /* 8Gb per chip */
trfc = DIV_ROUND_UP(350000, clkper) - 1;
txs = DIV_ROUND_UP(360000, clkper) - 1;
break;
default:
/* invalid density */
puts("invalid chip density\n");
hang();
break;
}
txpr = txs;
switch (mem_speed) {
case 800:
txp = DIV_ROUND_UP(max(3 * clkper, 7500), clkper) - 1;
tcke = DIV_ROUND_UP(max(3 * clkper, 7500), clkper) - 1;
if (ddr3_cfg->pagesz == 1) {
tfaw = DIV_ROUND_UP(40000, clkper) - 1;
trrd = DIV_ROUND_UP(max(4 * clkper, 10000), clkper) - 1;
} else {
tfaw = DIV_ROUND_UP(50000, clkper) - 1;
trrd = DIV_ROUND_UP(max(4 * clkper, 10000), clkper) - 1;
}
break;
case 1066:
txp = DIV_ROUND_UP(max(3 * clkper, 7500), clkper) - 1;
tcke = DIV_ROUND_UP(max(3 * clkper, 5625), clkper) - 1;
if (ddr3_cfg->pagesz == 1) {
tfaw = DIV_ROUND_UP(37500, clkper) - 1;
trrd = DIV_ROUND_UP(max(4 * clkper, 7500), clkper) - 1;
} else {
tfaw = DIV_ROUND_UP(50000, clkper) - 1;
trrd = DIV_ROUND_UP(max(4 * clkper, 10000), clkper) - 1;
}
break;
default:
puts("invalid memory speed\n");
hang();
break;
}
txpdll = DIV_ROUND_UP(max(10 * clkper, 24000), clkper) - 1;
tcksre = DIV_ROUND_UP(max(5 * clkper, 10000), clkper);
taonpd = DIV_ROUND_UP(2000, clkper) - 1;
tcksrx = tcksre;
taofpd = taonpd;
twr = DIV_ROUND_UP(15000, clkper) - 1;
tmrd = DIV_ROUND_UP(max(12 * clkper, 15000), clkper) - 1;
trc = DIV_ROUND_UP(ddr3_cfg->trcmin, clkper / 10) - 1;
tras = DIV_ROUND_UP(ddr3_cfg->trasmin, clkper / 10) - 1;
tcl = DIV_ROUND_UP(ddr3_cfg->trcd, clkper / 10) - 3;
trp = DIV_ROUND_UP(ddr3_cfg->trcd, clkper / 10) - 1;
twtr = ROUND(max(4 * clkper, 7500) / clkper, 1) - 1;
trcd = trp;
trtp = twtr;
cs0_end = 4 * sysinfo->cs_density - 1;
mmdc0->mpdgctrl0 = calib->p0_mpdgctrl0;
mmdc0->mpdgctrl1 = calib->p0_mpdgctrl1;
mmdc0->mprddlctl = calib->p0_mprddlctl;
mmdc0->mpwrdlctl = calib->p0_mpwrdlctl;
if (sysinfo->dsize > 1) {
MMDC1(mpwldectrl0, calib->p1_mpwldectrl0);
MMDC1(mpwldectrl1, calib->p1_mpwldectrl1);
MMDC1(mpdgctrl0, calib->p1_mpdgctrl0);
MMDC1(mpdgctrl1, calib->p1_mpdgctrl1);
MMDC1(mprddlctl, calib->p1_mprddlctl);
MMDC1(mpwrdlctl, calib->p1_mpwrdlctl);
}
/* Read data DQ Byte0-3 delay */
mmdc0->mprddqby0dl = 0x33333333;
mmdc0->mprddqby1dl = 0x33333333;
if (sysinfo->dsize > 0) {
mmdc0->mprddqby2dl = 0x33333333;
mmdc0->mprddqby3dl = 0x33333333;
}
if (sysinfo->dsize > 1) {
MMDC1(mprddqby0dl, 0x33333333);
MMDC1(mprddqby1dl, 0x33333333);
MMDC1(mprddqby2dl, 0x33333333);
MMDC1(mprddqby3dl, 0x33333333);
}
/* MMDC Termination: rtt_nom:2 RZQ/2(120ohm), rtt_nom:1 RZQ/4(60ohm) */
val = (sysinfo->rtt_nom == 2) ? 0x00011117 : 0x00022227;
mmdc0->mpodtctrl = val;
if (sysinfo->dsize > 1)
MMDC1(mpodtctrl, val);
/* complete calibration */
val = (1 << 11); /* Force measurement on delay-lines */
mmdc0->mpmur0 = val;
if (sysinfo->dsize > 1)
MMDC1(mpmur0, val);
/* Step 1: configuration request */
mmdc0->mdscr = (u32)(1 << 15); /* config request */
/* Step 2: Timing configuration */
mmdc0->mdcfg0 = (trfc << 24) | (txs << 16) | (txp << 13) |
(txpdll << 9) | (tfaw << 4) | tcl;
mmdc0->mdcfg1 = (trcd << 29) | (trp << 26) | (trc << 21) |
(tras << 16) | (1 << 15) /* trpa */ |
(twr << 9) | (tmrd << 5) | tcwl;
mmdc0->mdcfg2 = (tdllk << 16) | (trtp << 6) | (twtr << 3) | trrd;
mmdc0->mdotc = (taofpd << 27) | (taonpd << 24) | (tanpd << 20) |
(taxpd << 16) | (todtlon << 12) | (todt_idle_off << 4);
mmdc0->mdasp = cs0_end; /* CS addressing */
/* Step 3: Configure DDR type */
mmdc0->mdmisc = (sysinfo->cs1_mirror << 19) | (sysinfo->walat << 16) |
(sysinfo->bi_on << 12) | (sysinfo->mif3_mode << 9) |
(sysinfo->ralat << 6);
/* Step 4: Configure delay while leaving reset */
mmdc0->mdor = (txpr << 16) | (sysinfo->sde_to_rst << 8) |
(sysinfo->rst_to_cke << 0);
/* Step 5: Configure DDR physical parameters (density and burst len) */
coladdr = ddr3_cfg->coladdr;
if (ddr3_cfg->coladdr == 8) /* 8-bit COL is 0x3 */
coladdr += 4;
else if (ddr3_cfg->coladdr == 12) /* 12-bit COL is 0x4 */
coladdr += 1;
mmdc0->mdctl = (ddr3_cfg->rowaddr - 11) << 24 | /* ROW */
(coladdr - 9) << 20 | /* COL */
(1 << 19) | /* Burst Length = 8 for DDR3 */
(sysinfo->dsize << 16); /* DDR data bus size */
/* Step 6: Perform ZQ calibration */
val = 0xa1390001; /* one-time HW ZQ calib */
mmdc0->mpzqhwctrl = val;
if (sysinfo->dsize > 1)
MMDC1(mpzqhwctrl, val);
/* Step 7: Enable MMDC with desired chip select */
mmdc0->mdctl |= (1 << 31) | /* SDE_0 for CS0 */
((sysinfo->ncs == 2) ? 1 : 0) << 30; /* SDE_1 for CS1 */
/* Step 8: Write Mode Registers to Init DDR3 devices */
for (cs = 0; cs < sysinfo->ncs; cs++) {
/* MR2 */
val = (sysinfo->rtt_wr & 3) << 9 | (ddr3_cfg->SRT & 1) << 7 |
((tcwl - 3) & 3) << 3;
debug("MR2 CS%d: 0x%08x\n", cs, (u32)MR(val, 2, 3, cs));
mmdc0->mdscr = MR(val, 2, 3, cs);
/* MR3 */
debug("MR3 CS%d: 0x%08x\n", cs, (u32)MR(0, 3, 3, cs));
mmdc0->mdscr = MR(0, 3, 3, cs);
/* MR1 */
val = ((sysinfo->rtt_nom & 1) ? 1 : 0) << 2 |
((sysinfo->rtt_nom & 2) ? 1 : 0) << 6;
debug("MR1 CS%d: 0x%08x\n", cs, (u32)MR(val, 1, 3, cs));
mmdc0->mdscr = MR(val, 1, 3, cs);
/* MR0 */
val = ((tcl - 1) << 4) | /* CAS */
(1 << 8) | /* DLL Reset */
((twr - 3) << 9) | /* Write Recovery */
(sysinfo->pd_fast_exit << 12); /* Precharge PD PLL on */
debug("MR0 CS%d: 0x%08x\n", cs, (u32)MR(val, 0, 3, cs));
mmdc0->mdscr = MR(val, 0, 3, cs);
/* ZQ calibration */
val = (1 << 10);
mmdc0->mdscr = MR(val, 0, 4, cs);
}
/* Step 10: Power down control and self-refresh */
mmdc0->mdpdc = (tcke & 0x7) << 16 |
5 << 12 | /* PWDT_1: 256 cycles */
5 << 8 | /* PWDT_0: 256 cycles */
1 << 6 | /* BOTH_CS_PD */
(tcksrx & 0x7) << 3 |
(tcksre & 0x7);
if (!sysinfo->pd_fast_exit)
mmdc0->mdpdc |= (1 << 7); /* SLOW_PD */
mmdc0->mapsr = 0x00001006; /* ADOPT power down enabled */
/* Step 11: Configure ZQ calibration: one-time and periodic 1ms */
val = 0xa1390003;
mmdc0->mpzqhwctrl = val;
if (sysinfo->dsize > 1)
MMDC1(mpzqhwctrl, val);
/* Step 12: Configure and activate periodic refresh */
mmdc0->mdref = (sysinfo->refsel << 14) | (sysinfo->refr << 11);
/* * Step 13: i.MX6DQP only: If the NoC scheduler is enabled, * configure it and disable MMDC arbitration/reordering (see EB828) */
if (is_mx6dqp() &&
((soc_boot_cfg3 & BOOT_CFG3_DDR_MASK) == DDR_MMAP_NOC_SINGLE ||
(soc_boot_cfg3 & BOOT_CFG3_EXT_DDR_MASK) == DDR_MMAP_NOC_DUAL)) {
struct mx6dqp_noc_sched_regs *noc_sched =
(struct mx6dqp_noc_sched_regs *)MX6DQP_NOC_SCHED_BASE;
/* * These values are fixed based on integration parameters and * should not be modified */
noc_sched->rlat = 0x00000040;
noc_sched->ipu1 = 0x00000020;
noc_sched->ipu2 = 0x00000020;
noc_sched->activate = (1 << NOC_FAW_BANKS_SHIFT) |
(tfaw << NOC_FAW_PERIOD_SHIFT) |
(trrd << NOC_RD_SHIFT);
noc_sched->ddrtiming = (((sysinfo->dsize == 1) ? 1 : 0)
<< NOC_BW_RATIO_SHIFT) |
((tcwl + twtr) << NOC_WR_TO_RD_SHIFT) |
((tcl - tcwl + 2) << NOC_RD_TO_WR_SHIFT) |
(4 << NOC_BURST_LEN_SHIFT) | /* BL8 */
((tcwl + twr + trp + trcd)
<< NOC_WR_TO_MISS_SHIFT) |
((trtp + trp + trcd - 4)
<< NOC_RD_TO_MISS_SHIFT) |
(trc << NOC_ACT_TO_ACT_SHIFT);
if (sysinfo->dsize == 2) {
if (ddr3_cfg->coladdr == 10) {
if (ddr3_cfg->rowaddr == 15 &&
sysinfo->ncs == 2)
noc_sched->ddrconf = 4;
else
noc_sched->ddrconf = 0;
} else if (ddr3_cfg->coladdr == 11) {
noc_sched->ddrconf = 1;
}
} else {
if (ddr3_cfg->coladdr == 9) {
if (ddr3_cfg->rowaddr == 13)
noc_sched->ddrconf = 2;
else if (ddr3_cfg->rowaddr == 14)
noc_sched->ddrconf = 15;
} else if (ddr3_cfg->coladdr == 10) {
if (ddr3_cfg->rowaddr == 14 &&
sysinfo->ncs == 2)
noc_sched->ddrconf = 14;
else if (ddr3_cfg->rowaddr == 15 &&
sysinfo->ncs == 2)
noc_sched->ddrconf = 9;
else
noc_sched->ddrconf = 3;
} else if (ddr3_cfg->coladdr == 11) {
if (ddr3_cfg->rowaddr == 15 &&
sysinfo->ncs == 2)
noc_sched->ddrconf = 4;
else
noc_sched->ddrconf = 0;
} else if (ddr3_cfg->coladdr == 12) {
if (ddr3_cfg->rowaddr == 14)
noc_sched->ddrconf = 1;
}
}
/* Disable MMDC arbitration/reordering */
mmdc0->maarcr = 0x14420000;
}
/* Step 13: Deassert config request - init complete */
mmdc0->mdscr = 0x00000000;
/* wait for auto-ZQ calibration to complete */
mdelay(1);
}
边栏推荐
猜你喜欢

7. CAS

flink 数据流图、并行度、算子链、JobGraph与ExecutionGraph、任务和任务槽

Flick grouping sets multidimensional aggregation and setting table state expiration time

The super document downloading tool scihub CN teaches you to download documents with one line of command

Flash framework web development video notes

1. Thread Basics

Evolution of e-commerce development

mysql的主从复制

经营养生理疗馆要注意什么问题?

Redis data type daily use scenarios
随机推荐
美容院管理系统如何解决门店运营的三大难题?
8、原子操作类之18罗汉增强
ftp服务器:serv-u 的下载及使用
This is our golden age
How Oracle exports data to CSV (Excel) files
C# System. Guid. Newguid() format
flink 部署模式和运行时架构(会话模式、单作业模式、应用模式,JobManager、TaskManager,YARN 模式部署以及运行时架构)
Problems encountered recently when using nodejs Pinyin package
After Oracle deletes a user, it can still use the user to log in
UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xc5 in position 13: invalid continuation byte
How can physical stores break through operational difficulties? Take a look at the store operation guide of this physical store applet
What are the elements of running a gymnasium?
Flick controls window behavior (trigger, remover, allow delay, put late data into side output stream)
Flink window table valued function
Moist or not? This is a problem
13、ReentrantLock、ReentrantReadWriteLock、StampedLock讲解
Oracle DatabaseLink cross database connection
China Unicom 22 spring Games Group
What problems should be paid attention to in running health preserving physiotherapy center?
一些比较的常用网站