static bool is_mx6q(void) { if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) return true; else return false; }
/* i2c_num can be from 0 - 3 */ int enable_i2c_clk(unsigned char enable, unsigned i2c_num) { u32 reg; u32 mask; u32 *addr; if (i2c_num > 3) return -EINVAL; if (i2c_num < 3) { mask = MXC_CCM_CCGR_CG_MASK << (MXC_CCM_CCGR2_I2C1_SERIAL_OFFSET + (i2c_num << 1)); reg = __raw_readl(&imx_ccm->CCGR2); if (enable) reg |= mask; else reg &= ~mask; __raw_writel(reg, &imx_ccm->CCGR2); } else { if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL)) { mask = MXC_CCM_CCGR6_I2C4_MASK; addr = &imx_ccm->CCGR6; } else { mask = MXC_CCM_CCGR1_I2C4_SERIAL_MASK; addr = &imx_ccm->CCGR1; } reg = __raw_readl(addr); if (enable) reg |= mask; else reg &= ~mask; __raw_writel(reg, addr); } return 0; }
int setup_sata(void) { struct iomuxc_base_regs *const iomuxc_regs = (struct iomuxc_base_regs *)IOMUXC_BASE_ADDR; int ret; if (!is_cpu_type(MXC_CPU_MX6Q) && !is_cpu_type(MXC_CPU_MX6D)) return 1; ret = enable_sata_clock(); if (ret) return ret; clrsetbits_le32(&iomuxc_regs->gpr[13], IOMUXC_GPR13_SATA_MASK, IOMUXC_GPR13_SATA_PHY_8_RXEQ_3P0DB |IOMUXC_GPR13_SATA_PHY_7_SATA2M |IOMUXC_GPR13_SATA_SPEED_3G |(3<<IOMUXC_GPR13_SATA_PHY_6_SHIFT) |IOMUXC_GPR13_SATA_SATA_PHY_5_SS_DISABLED |IOMUXC_GPR13_SATA_SATA_PHY_4_ATTEN_9_16 |IOMUXC_GPR13_SATA_PHY_3_TXBOOST_0P00_DB |IOMUXC_GPR13_SATA_PHY_2_TX_1P104V |IOMUXC_GPR13_SATA_PHY_1_SLOW); return 0; }
static inline int gpt_has_clk_source_osc(void) { #if defined(CONFIG_MX6) if (((is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) && (is_soc_rev(CHIP_REV_1_0) > 0)) || is_cpu_type(MXC_CPU_MX6DL) || is_cpu_type(MXC_CPU_MX6SOLO) || is_cpu_type(MXC_CPU_MX6SX)) return 1; return 0; #else return 0; #endif }
static void spl_dram_init(void) { if (is_cpu_type(MXC_CPU_MX6SOLO)) { mx6sdl_dram_iocfg(32, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&mem_s, &mx6s_512m_mmdc_calib, &h5tq2g63dfr); } else if (is_cpu_type(MXC_CPU_MX6DL)) { mx6sdl_dram_iocfg(64, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&mem_dl, &mx6dl_1g_mmdc_calib, &h5tq2g63dfr); } else if (is_cpu_type(MXC_CPU_MX6Q)) { mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); mx6_dram_cfg(&mem_q, &mx6q_2g_mmdc_calib, &h5t04g63afr); } udelay(100); }
static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, uint32_t page_oob_size) { int ecc_strength; int max_ecc_strength_supported; /* Refer to Chapter 17 for i.MX6DQ, Chapter 18 for i.MX6SX */ if (is_cpu_type(MXC_CPU_MX6SX)) max_ecc_strength_supported = 62; else max_ecc_strength_supported = 40; /* * Determine the ECC layout with the formula: * ECC bits per chunk = (total page spare data bits) / * (bits per ECC level) / (chunks per page) * where: * total page spare data bits = * (page oob size - meta data size) * (bits per byte) */ ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8) / (galois_field * mxs_nand_ecc_chunk_cnt(page_data_size)); return min(round_down(ecc_strength, 2), max_ecc_strength_supported); }
static void i2c_setup_iomux(void) { if (is_cpu_type(MXC_CPU_MX6Q)) setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0); else setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0); }
static u32 mxc_get_pll_pfd(enum pll_clocks pll, int pfd_num) { u32 div; u64 freq; switch (pll) { case PLL_BUS: if (!is_cpu_type(MXC_CPU_MX6UL)) { if (pfd_num == 3) { /* No PFD3 on PPL2 */ return 0; } } div = __raw_readl(&imx_ccm->analog_pfd_528); freq = (u64)decode_pll(PLL_BUS, MXC_HCLK); break; case PLL_USBOTG: div = __raw_readl(&imx_ccm->analog_pfd_480); freq = (u64)decode_pll(PLL_USBOTG, MXC_HCLK); break; default: /* No PFD on other PLL */ return 0; } return lldiv(freq * 18, (div & ANATOP_PFD_FRAC_MASK(pfd_num)) >> ANATOP_PFD_FRAC_SHIFT(pfd_num)); }
void dram_init_banksize(void) { gd->bd->bi_dram[0].start = PHYS_SDRAM_1; gd->bd->bi_dram[1].start = PHYS_SDRAM_2; switch (gd->ram_size) { case 0x10000000: /* DDR_16BIT_256MB */ gd->bd->bi_dram[0].size = 0x10000000; gd->bd->bi_dram[1].size = 0; break; case 0x20000000: /* DDR_32BIT_512MB */ gd->bd->bi_dram[0].size = 0x20000000; gd->bd->bi_dram[1].size = 0; break; case 0x40000000: if (is_cpu_type(MXC_CPU_MX6SOLO)) { /* DDR_32BIT_1GB */ gd->bd->bi_dram[0].size = 0x20000000; gd->bd->bi_dram[1].size = 0x20000000; } else { /* DDR_64BIT_1GB */ gd->bd->bi_dram[0].size = 0x40000000; gd->bd->bi_dram[1].size = 0; } break; case 0x80000000: /* DDR_64BIT_2GB */ gd->bd->bi_dram[0].size = 0x40000000; gd->bd->bi_dram[1].size = 0x40000000; break; case 0xEFF00000: /* DDR_64BIT_4GB */ gd->bd->bi_dram[0].size = 0x70000000; gd->bd->bi_dram[1].size = 0x7FF00000; break; } }
int checkboard(void) { printf("Model: Toradex Colibri iMX7%c\n", is_cpu_type(MXC_CPU_MX7D) ? 'D' : 'S'); return 0; }
int board_late_init(void) { #ifdef CONFIG_CMD_BMODE add_board_boot_modes(board_boot_modes); #endif #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG setenv("board_name", "SABRESD"); if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) setenv("board_rev", "MX6Q"); else if (is_cpu_type(MXC_CPU_MX6DL) || is_cpu_type(MXC_CPU_MX6SOLO)) setenv("board_rev", "MX6DL"); #endif return 0; }
int checkboard(void) { if (is_cpu_type(MXC_CPU_MX6Q)) puts("Board: Udoo Quad\n"); else puts("Board: Udoo DualLite\n"); return 0; }
int board_late_init(void) { #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG if (is_cpu_type(MXC_CPU_MX6Q)) env_set("board_rev", "MX6Q"); else env_set("board_rev", "MX6DL"); #endif return 0; }
int board_init(void) { /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; #ifdef CONFIG_SATA if (is_cpu_type(MXC_CPU_MX6Q)) setup_sata(); #endif return 0; }
static void spl_dram_init(void) { if (is_cpu_type(MXC_CPU_MX6DL)) { mt41k128m16jt_125.mem_speed = 800; mem_qdl.rtt_nom = 1; mem_qdl.rtt_wr = 1; mx6sdl_dram_iocfg(64, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&mem_qdl, &mx6dl_1g_mmdc_calib, &mt41k128m16jt_125); } else if (is_cpu_type(MXC_CPU_MX6Q)) { mt41k128m16jt_125.mem_speed = 1066; mem_qdl.rtt_nom = 2; mem_qdl.rtt_wr = 2; mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); mx6_dram_cfg(&mem_qdl, &mx6q_1g_mmdc_calib, &mt41k128m16jt_125); } udelay(100); }
void setup_ventana_i2c(void) { if (is_cpu_type(MXC_CPU_MX6Q)) { setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0); setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info1); setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info2); } else { setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0); setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info1); setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info2); } }
int board_early_init_f(void) { setup_iomux_uart(); #if defined(CONFIG_VIDEO_IPUV3) setup_display(); #endif #ifdef CONFIG_CMD_SATA /* Only mx6q wandboard has SATA */ if (is_cpu_type(MXC_CPU_MX6Q)) setup_sata(); #endif return 0; }
void enable_uart_clk(unsigned char enable) { u32 mask; if (is_cpu_type(MXC_CPU_MX6UL)) mask = MXC_CCM_CCGR5_UART_MASK; else mask = MXC_CCM_CCGR5_UART_MASK | MXC_CCM_CCGR5_UART_SERIAL_MASK; if (enable) setbits_le32(&imx_ccm->CCGR5, mask); else clrbits_le32(&imx_ccm->CCGR5, mask); }
void enable_enet_clk(unsigned char enable) { u32 mask, *addr; if (is_cpu_type(MXC_CPU_MX6UL)) { mask = MXC_CCM_CCGR3_ENET_MASK; addr = &imx_ccm->CCGR3; } else { mask = MXC_CCM_CCGR1_ENET_MASK; addr = &imx_ccm->CCGR1; } if (enable) setbits_le32(addr, mask); else clrbits_le32(addr, mask); }
int board_ehci_hcd_init(int port) { switch (port) { case 0: break; case 1: if (is_cpu_type(MXC_CPU_MX7S)) return -ENODEV; imx_iomux_v3_setup_multiple_pads(usb_otg2_pads, ARRAY_SIZE(usb_otg2_pads)); break; default: return -EINVAL; } return 0; }
int checkboard(void) { char it[] = " IT"; int minc, maxc; switch (get_cpu_temp_grade(&minc, &maxc)) { case TEMP_AUTOMOTIVE: case TEMP_INDUSTRIAL: break; case TEMP_EXTCOMMERCIAL: default: it[0] = 0; }; printf("Model: Toradex Apalis iMX6 %s %s%s\n", is_cpu_type(MXC_CPU_MX6D) ? "Dual" : "Quad", (gd->ram_size == 0x80000000) ? "2GB" : (gd->ram_size == 0x40000000) ? "1GB" : "512MB", it); return 0; }
void spl_board_init(void) { #if 0 int i; u32 const *regs ; int num_regs; unsigned char mac_address[6]; imx_get_mac_from_fuse(0,mac_address); printf("ethaddr: %pM\n", mac_address); if (is_cpu_type(MXC_CPU_MX6Q)) { #if 1 regs = mx6q_1g; num_regs = ARRAY_SIZE(mx6q_1g); #else regs = mx6q_2g; num_regs = ARRAY_SIZE(mx6q_2g); #endif } else { #if CONFIG_DDR_MB == 512 regs = mx6dl_512m; num_regs = ARRAY_SIZE(mx6dl_512m); printf("Configuring for 512MiB narrow memory bus\n"); #elif CONFIG_DDR_MB == 1024 regs = mx6dl_1gn; num_regs = ARRAY_SIZE(mx6dl_1gn); printf("Configuring for 1GiB narrow memory bus\n"); #elif CONFIG_DDR_MB == 2048 regs = mx6dl_2g; num_regs = ARRAY_SIZE(mx6dl_2g); printf("Configuring for 2GiB wide memory bus\n"); #endif } for (i=0; i < num_regs; i+=2) { writel(regs[i+1],regs[i]); } dram_init(); #endif printf("%s\n", __func__); }
void mx6_dram_cfg(const struct mx6_ddr_sysinfo *i, const struct mx6_mmdc_calibration *c, const struct mx6_ddr3_cfg *m) { volatile struct mmdc_p_regs *mmdc0; volatile struct mmdc_p_regs *mmdc1; u32 reg; 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; mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR; /* MX6D/MX6Q: 1066 MHz memory clock, clkper = 1.894ns = 1894ps */ if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) { clock = 528; tcwl = 4; } /* MX6S/MX6DL: 800 MHz memory clock, clkper = 2.5ns = 2500ps */ else { clock = 400; tcwl = 3; } clkper = (1000*1000)/clock; /* ps */ todtlon = tcwl; taxpd = tcwl; tanpd = tcwl; tcwl = tcwl; switch (m->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 */ printf("invalid chip density\n"); hang(); break; } txpr = txs; switch (m->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 (m->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 (m->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; case 1333: txp = DIV_ROUND_UP(MAX(3*clkper, 6000), clkper) - 1; tcke = DIV_ROUND_UP(MAX(3*clkper, 5625), clkper) - 1; if (m->pagesz == 1) { tfaw = DIV_ROUND_UP(30000, clkper) - 1; trrd = DIV_ROUND_UP(MAX(4*clkper, 6000), clkper) - 1; } else { tfaw = DIV_ROUND_UP(45000, clkper) - 1; trrd = DIV_ROUND_UP(MAX(4*clkper, 7500), clkper) - 1; } break; case 1600: txp = DIV_ROUND_UP(MAX(3*clkper, 6000), clkper) - 1; tcke = DIV_ROUND_UP(MAX(3*clkper, 5000), clkper) - 1; if (m->pagesz == 1) { tfaw = DIV_ROUND_UP(30000, clkper) - 1; trrd = DIV_ROUND_UP(MAX(4*clkper, 6000), clkper) - 1; } else { tfaw = DIV_ROUND_UP(40000, clkper) - 1; trrd = DIV_ROUND_UP(MAX(4*clkper, 7500), clkper) - 1; } break; default: printf("invalid memory speed\n"); hang(); break; } txpdll = DIV_ROUND_UP(MAX(10*clkper, 24000), clkper) - 1; tcl = DIV_ROUND_UP(m->trcd, clkper/10) - 3; tcksre = DIV_ROUND_UP(MAX(5*clkper, 10000), clkper); tcksrx = tcksre; taonpd = DIV_ROUND_UP(2000, clkper) - 1; taofpd = taonpd; trp = DIV_ROUND_UP(m->trcd, clkper/10) - 1; trcd = trp; trc = DIV_ROUND_UP(m->trcmin, clkper/10) - 1; tras = DIV_ROUND_UP(m->trasmin, clkper/10) - 1; twr = DIV_ROUND_UP(15000, clkper) - 1; tmrd = DIV_ROUND_UP(MAX(12*clkper, 15000), clkper) - 1; twtr = ROUND(MAX(4*clkper, 7500)/clkper, 1) - 1; trtp = twtr; CS0_END = ((4*i->cs_density) <= 120) ? (4*i->cs_density)+7 : 127; debug("density:%d Gb (%d Gb per chip)\n", i->cs_density, m->density); debug("clock: %dMHz (%d ps)\n", clock, clkper); debug("memspd:%d\n", m->mem_speed); debug("tcke=%d\n", tcke); debug("tcksrx=%d\n", tcksrx); debug("tcksre=%d\n", tcksre); debug("taofpd=%d\n", taofpd); debug("taonpd=%d\n", taonpd); debug("todtlon=%d\n", todtlon); debug("tanpd=%d\n", tanpd); debug("taxpd=%d\n", taxpd); debug("trfc=%d\n", trfc); debug("txs=%d\n", txs); debug("txp=%d\n", txp); debug("txpdll=%d\n", txpdll); debug("tfaw=%d\n", tfaw); debug("tcl=%d\n", tcl); debug("trcd=%d\n", trcd); debug("trp=%d\n", trp); debug("trc=%d\n", trc); debug("tras=%d\n", tras); debug("twr=%d\n", twr); debug("tmrd=%d\n", tmrd); debug("tcwl=%d\n", tcwl); debug("tdllk=%d\n", tdllk); debug("trtp=%d\n", trtp); debug("twtr=%d\n", twtr); debug("trrd=%d\n", trrd); debug("txpr=%d\n", txpr); debug("CS0_END=%d\n", CS0_END); debug("ncs=%d\n", i->ncs); debug("Rtt_wr=%d\n", i->rtt_wr); debug("Rtt_nom=%d\n", i->rtt_nom); debug("SRT=%d\n", m->SRT); debug("tcl=%d\n", tcl); debug("twr=%d\n", twr); /* * board-specific configuration: * These values are determined empirically and vary per board layout * see: * appnote, ddr3 spreadsheet */ mmdc0->mpwldectrl0 = c->p0_mpwldectrl0; mmdc0->mpwldectrl1 = c->p0_mpwldectrl1; mmdc0->mpdgctrl0 = c->p0_mpdgctrl0; mmdc0->mpdgctrl1 = c->p0_mpdgctrl1; mmdc0->mprddlctl = c->p0_mprddlctl; mmdc0->mpwrdlctl = c->p0_mpwrdlctl; if (i->dsize > 1) { mmdc1->mpwldectrl0 = c->p1_mpwldectrl0; mmdc1->mpwldectrl1 = c->p1_mpwldectrl1; mmdc1->mpdgctrl0 = c->p1_mpdgctrl0; mmdc1->mpdgctrl1 = c->p1_mpdgctrl1; mmdc1->mprddlctl = c->p1_mprddlctl; mmdc1->mpwrdlctl = c->p1_mpwrdlctl; } /* Read data DQ Byte0-3 delay */ mmdc0->mprddqby0dl = (u32)0x33333333; mmdc0->mprddqby1dl = (u32)0x33333333; if (i->dsize > 0) { mmdc0->mprddqby2dl = (u32)0x33333333; mmdc0->mprddqby3dl = (u32)0x33333333; } if (i->dsize > 1) { mmdc1->mprddqby0dl = (u32)0x33333333; mmdc1->mprddqby1dl = (u32)0x33333333; mmdc1->mprddqby2dl = (u32)0x33333333; mmdc1->mprddqby3dl = (u32)0x33333333; } /* MMDC Termination: rtt_nom:2 RZQ/2(120ohm), rtt_nom:1 RZQ/4(60ohm) */ reg = (i->rtt_nom == 2) ? 0x00011117 : 0x00022227; mmdc0->mpodtctrl = reg; if (i->dsize > 1) mmdc1->mpodtctrl = reg; /* complete calibration */ reg = (1 << 11); /* Force measurement on delay-lines */ mmdc0->mpmur0 = reg; if (i->dsize > 1) mmdc1->mpmur0 = reg; /* Step 1: configuration request */ mmdc0->mdscr = (u32)(1 << 15); /* config request */ /* Step 2: Timing configuration */ reg = (trfc << 24) | (txs << 16) | (txp << 13) | (txpdll << 9) | (tfaw << 4) | tcl; mmdc0->mdcfg0 = reg; reg = (trcd << 29) | (trp << 26) | (trc << 21) | (tras << 16) | (1 << 15) | /* trpa */ (twr << 9) | (tmrd << 5) | tcwl; mmdc0->mdcfg1 = reg; reg = (tdllk << 16) | (trtp << 6) | (twtr << 3) | trrd; mmdc0->mdcfg2 = reg; reg = (taofpd << 27) | (taonpd << 24) | (tanpd << 20) | (taxpd << 16) | (todtlon << 12) | (todt_idle_off << 4); mmdc0->mdotc = reg; mmdc0->mdasp = CS0_END; /* CS addressing */ /* Step 3: Configure DDR type */ reg = (i->cs1_mirror << 19) | (i->walat << 16) | (i->bi_on << 12) | (i->mif3_mode << 9) | (i->ralat << 6); mmdc0->mdmisc = reg; /* Step 4: Configure delay while leaving reset */ reg = (txpr << 16) | (i->sde_to_rst << 8) | (i->rst_to_cke << 0); mmdc0->mdor = reg; /* Step 5: Configure DDR physical parameters (density and burst len) */ coladdr = m->coladdr; if (m->coladdr == 8) /* 8-bit COL is 0x3 */ coladdr += 4; else if (m->coladdr == 12) /* 12-bit COL is 0x4 */ coladdr += 1; reg = (m->rowaddr - 11) << 24 | /* ROW */ (coladdr - 9) << 20 | /* COL */ (1 << 19) | /* Burst Length = 8 for DDR3 */ (i->dsize << 16); /* DDR data bus size */ mmdc0->mdctl = reg; /* Step 6: Perform ZQ calibration */ reg = (u32)0xa1390001; /* one-time HW ZQ calib */ mmdc0->mpzqhwctrl = reg; if (i->dsize > 1) mmdc1->mpzqhwctrl = reg; /* Step 7: Enable MMDC with desired chip select */ reg = mmdc0->mdctl | (1 << 31) | /* SDE_0 for CS0 */ ((i->ncs == 2) ? 1 : 0) << 30; /* SDE_1 for CS1 */ mmdc0->mdctl = reg; /* Step 8: Write Mode Registers to Init DDR3 devices */ for (cs = 0; cs < i->ncs; cs++) { /* MR2 */ reg = (i->rtt_wr & 3) << 9 | (m->SRT & 1) << 7 | ((tcwl - 3) & 3) << 3; mmdc0->mdscr = (u32)MR(reg, 2, 3, cs); /* MR3 */ mmdc0->mdscr = (u32)MR(0, 3, 3, cs); /* MR1 */ reg = ((i->rtt_nom & 1) ? 1 : 0) << 2 | ((i->rtt_nom & 2) ? 1 : 0) << 6; mmdc0->mdscr = (u32)MR(reg, 1, 3, cs); reg = ((tcl - 1) << 4) | /* CAS */ (1 << 8) | /* DLL Reset */ ((twr - 3) << 9); /* Write Recovery */ /* MR0 */ mmdc0->mdscr = (u32)MR(reg, 0, 3, cs); /* ZQ calibration */ reg = (1 << 10); mmdc0->mdscr = (u32)MR(reg, 0, 4, cs); } /* Step 10: Power down control and self-refresh */ reg = (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); mmdc0->mdpdc = reg; mmdc0->mapsr = (u32)0x00011006; /* ADOPT power down enabled */ /* Step 11: Configure ZQ calibration: one-time and periodic 1ms */ mmdc0->mpzqhwctrl = (u32)0xa1390003; if (i->dsize > 1) mmdc1->mpzqhwctrl = (u32)0xa1390003; /* Step 12: Configure and activate periodic refresh */ reg = (1 << 14) | /* REF_SEL: Periodic refresh cycles of 32kHz */ (7 << 11); /* REFR: Refresh Rate - 8 refreshes */ mmdc0->mdref = reg; /* Step 13: Deassert config request - init complete */ mmdc0->mdscr = (u32)0x00000000; /* wait for auto-ZQ calibration to complete */ mdelay(1); }
static void spl_dram_init(int width, int size_mb, int board_model) { struct mx6_ddr3_cfg *mem = NULL; struct mx6_mmdc_calibration *calib = NULL; struct mx6_ddr_sysinfo sysinfo = { /* width of data bus:0=16,1=32,2=64 */ .dsize = width/32, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, /* 32Gb per CS */ /* single chip select */ .ncs = 1, .cs1_mirror = 0, .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ #ifdef RTT_NOM_120OHM .rtt_nom = 2 /*DDR3_RTT_120_OHM*/, /* RTT_Nom = RZQ/2 */ #else .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ #endif .walat = 1, /* Write additional latency */ .ralat = 5, /* Read additional latency */ .mif3_mode = 3, /* Command prediction working mode */ .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ .pd_fast_exit = 1, /* enable precharge power-down fast exit */ .ddr_type = DDR_TYPE_DDR3, }; /* * MMDC Calibration requires the following data: * mx6_mmdc_calibration - board-specific calibration (routing delays) * these calibration values depend on board routing, SoC, and DDR * mx6_ddr_sysinfo - board-specific memory architecture (width/cs/etc) * mx6_ddr_cfg - chip specific timing/layout details */ if (width == 16 && size_mb == 128) { mem = &mt41k64m16jt_125; if (is_cpu_type(MXC_CPU_MX6Q)) ; else calib = &mx6sdl_64x16_mmdc_calib; debug("1gB density\n"); } else if (width == 16 && size_mb == 256) { /* 1x 2Gb density chip - same calib as 2x 2Gb */ mem = &mt41k128m16jt_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_128x32_mmdc_calib; else calib = &mx6sdl_128x32_mmdc_calib; debug("2gB density\n"); } else if (width == 16 && size_mb == 512) { mem = &mt41k256m16ha_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_256x16_mmdc_calib; else calib = &mx6sdl_256x16_mmdc_calib; debug("4gB density\n"); } else if (width == 32 && size_mb == 256) { /* Same calib as width==16, size==128 */ mem = &mt41k64m16jt_125; if (is_cpu_type(MXC_CPU_MX6Q)) ; else calib = &mx6sdl_64x16_mmdc_calib; debug("1gB density\n"); } else if (width == 32 && size_mb == 512) { mem = &mt41k128m16jt_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_128x32_mmdc_calib; else calib = &mx6sdl_128x32_mmdc_calib; debug("2gB density\n"); } else if (width == 32 && size_mb == 1024) { mem = &mt41k256m16ha_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_256x32_mmdc_calib; else calib = &mx6sdl_256x32_mmdc_calib; debug("4gB density\n"); } else if (width == 64 && size_mb == 512) { mem = &mt41k64m16jt_125; debug("1gB density\n"); } else if (width == 64 && size_mb == 1024) { mem = &mt41k128m16jt_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_128x64_mmdc_calib; else calib = &mx6sdl_128x64_mmdc_calib; debug("2gB density\n"); } else if (width == 64 && size_mb == 2048) { mem = &mt41k256m16ha_125; if (is_cpu_type(MXC_CPU_MX6Q)) calib = &mx6dq_256x64_mmdc_calib; debug("4gB density\n"); } if (!(mem && calib)) { puts("Error: Invalid Calibration/Board Configuration\n"); printf("MEM : %s\n", mem ? "OKAY" : "NULL"); printf("CALIB : %s\n", calib ? "OKAY" : "NULL"); printf("CPUTYPE: %s\n", is_cpu_type(MXC_CPU_MX6Q) ? "IMX6Q" : "IMX6DL"); printf("SIZE_MB: %d\n", size_mb); printf("WIDTH : %d\n", width); hang(); } if (is_cpu_type(MXC_CPU_MX6Q)) mx6dq_dram_iocfg(width, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); else mx6sdl_dram_iocfg(width, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&sysinfo, calib, mem); } static void ccgr_init(void) { struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; writel(0x00C03F3F, &ccm->CCGR0); writel(0x0030FC03, &ccm->CCGR1); writel(0x0FFFC000, &ccm->CCGR2); writel(0x3FF00000, &ccm->CCGR3); writel(0xFFFFF300, &ccm->CCGR4); /* enable NAND/GPMI/BCH clks */ writel(0x0F0000C3, &ccm->CCGR5); writel(0x000003FF, &ccm->CCGR6); } static void gpr_init(void) { struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; /* enable AXI cache for VDOA/VPU/IPU */ writel(0xF00000CF, &iomux->gpr[4]); /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */ writel(0x007F007F, &iomux->gpr[6]); writel(0x007F007F, &iomux->gpr[7]); } /* * called from C runtime startup code (arch/arm/lib/crt0.S:_main) * - we have a stack and a place to store GD, both in SRAM * - no variable global data is available */ void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model; /* setup clock gating */ ccgr_init(); /* setup AIPS and disable watchdog */ arch_cpu_init(); /* setup AXI */ gpr_init(); /* iomux and setup of i2c */ setup_iomux_uart(); setup_ventana_i2c(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(CONFIG_I2C_GSC, &ventana_info); /* configure model-specific gpio */ setup_iomux_gpio(board_model, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) hang(); /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* disable boot watchdog */ gsc_boot_wd_disable(); } /* called from board_init_r after gd setup if CONFIG_SPL_BOARD_INIT defined */ /* its our chance to print info about boot device */ void spl_board_init(void) { /* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 */ u32 boot_device = spl_boot_device(); switch (boot_device) { case BOOT_DEVICE_MMC1: puts("Booting from MMC\n"); break; case BOOT_DEVICE_NAND: puts("Booting from NAND\n"); break; case BOOT_DEVICE_SATA: puts("Booting from SATA\n"); break; default: puts("Unknown boot device\n"); } /* PMIC init */ setup_pmic(); }
uint32_t authenticate_image(uint32_t ddr_start, uint32_t image_size) { uint32_t load_addr = 0; size_t bytes; ptrdiff_t ivt_offset = 0; int result = 0; ulong start; hab_rvt_authenticate_image_t *hab_rvt_authenticate_image; hab_rvt_entry_t *hab_rvt_entry; hab_rvt_exit_t *hab_rvt_exit; hab_rvt_authenticate_image = hab_rvt_authenticate_image_p; hab_rvt_entry = hab_rvt_entry_p; hab_rvt_exit = hab_rvt_exit_p; if (is_hab_enabled()) { printf("\nAuthenticate image from DDR location 0x%x...\n", ddr_start); hab_caam_clock_enable(1); if (hab_rvt_entry() == HAB_SUCCESS) { /* If not already aligned, Align to ALIGN_SIZE */ ivt_offset = (image_size + ALIGN_SIZE - 1) & ~(ALIGN_SIZE - 1); start = ddr_start; bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE; #ifdef DEBUG printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ddr_start + ivt_offset); puts("Dumping IVT\n"); print_buffer(ddr_start + ivt_offset, (void *)(ddr_start + ivt_offset), 4, 0x8, 0); puts("Dumping CSF Header\n"); print_buffer(ddr_start + ivt_offset+IVT_SIZE, (void *)(ddr_start + ivt_offset+IVT_SIZE), 4, 0x10, 0); get_hab_status(); puts("\nCalling authenticate_image in ROM\n"); printf("\tivt_offset = 0x%x\n", ivt_offset); printf("\tstart = 0x%08lx\n", start); printf("\tbytes = 0x%x\n", bytes); #endif /* * If the MMU is enabled, we have to notify the ROM * code, or it won't flush the caches when needed. * This is done, by setting the "pu_irom_mmu_enabled" * word to 1. You can find its address by looking in * the ROM map. This is critical for * authenticate_image(). If MMU is enabled, without * setting this bit, authentication will fail and may * crash. */ /* Check MMU enabled */ if (get_cr() & CR_M) { if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) { /* * This won't work on Rev 1.0.0 of * i.MX6Q/D, since their ROM doesn't * do cache flushes. don't think any * exist, so we ignore them. */ if (!is_mx6dqp()) writel(1, MX6DQ_PU_IROM_MMU_EN_VAR); } else if (is_cpu_type(MXC_CPU_MX6DL) || is_cpu_type(MXC_CPU_MX6SOLO)) { writel(1, MX6DLS_PU_IROM_MMU_EN_VAR); } else if (is_cpu_type(MXC_CPU_MX6SL)) { writel(1, MX6SL_PU_IROM_MMU_EN_VAR); } } load_addr = (uint32_t)hab_rvt_authenticate_image( HAB_CID_UBOOT, ivt_offset, (void **)&start, (size_t *)&bytes, NULL); if (hab_rvt_exit() != HAB_SUCCESS) { puts("hab exit function fail\n"); load_addr = 0; } } else { puts("hab entry function fail\n"); } hab_caam_clock_enable(0); get_hab_status(); } else { puts("hab fuse not enabled\n"); } if ((!is_hab_enabled()) || (load_addr != 0)) result = 1; return result; }
int __cpuinit mt_smp_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; pr_crit("[AT]Boot slave CPU\n"); atomic_inc(&hotplug_cpu_count); pr_crit("[AT11]Boot slave CPU %d\n",cpu); /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); pr_crit("mt_smp_boot_secondary, cpu: %d\n", cpu); HOTPLUG_INFO("mt_smp_boot_secondary, cpu: %d\n", cpu); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ /* * This is really belt and braces; we hold unintended secondary * CPUs in the holding pen until we're ready for them. However, * since we haven't sent them a soft interrupt, they shouldn't * be there. */ write_pen_release(cpu); #if defined(CONFIG_TRUSTONIC_TEE_SUPPORT) if(cpu >=1 && cpu <=3) mt_secure_call(MC_FC_SET_RESET_VECTOR, virt_to_phys(mt_secondary_startup), cpu, 0); #else mt_smp_set_boot_addr(virt_to_phys(mt_secondary_startup), cpu); #endif switch(cpu) { case 1: #ifdef CONFIG_MTK_FPGA mt_reg_sync_writel(SLAVE1_MAGIC_NUM, SLAVE1_MAGIC_REG); HOTPLUG_INFO("SLAVE1_MAGIC_NUM:%x\n", SLAVE1_MAGIC_NUM); #endif spm_mtcmos_ctrl_cpu1(STA_POWER_ON, 1); break; case 2: #ifdef CONFIG_MTK_FPGA mt_reg_sync_writel(SLAVE2_MAGIC_NUM, SLAVE2_MAGIC_REG); HOTPLUG_INFO("SLAVE2_MAGIC_NUM:%x\n", SLAVE2_MAGIC_NUM); #endif spm_mtcmos_ctrl_cpu2(STA_POWER_ON, 1); break; case 3: #ifdef CONFIG_MTK_FPGA mt_reg_sync_writel(SLAVE3_MAGIC_NUM, SLAVE3_MAGIC_REG); HOTPLUG_INFO("SLAVE3_MAGIC_NUM:%x\n", SLAVE3_MAGIC_NUM); #endif spm_mtcmos_ctrl_cpu3(STA_POWER_ON, 1); break; default: break; } //smp_cross_call(cpumask_of(cpu)); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(1000); } if (pen_release == -1) { #if 0 //FIXME: update to the right register names pr_emerg("SPM_CA7_CPU0_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_CPU0_PWR_CON)); pr_emerg("SPM_CA7_CPU1_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_CPU1_PWR_CON)); pr_emerg("SPM_CA7_CPU2_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_CPU2_PWR_CON)); pr_emerg("SPM_CA7_CPU3_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_CPU3_PWR_CON)); pr_emerg("SPM_CA7_DBG_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_DBG_PWR_CON)); pr_emerg("SPM_CA7_CPUTOP_PWR_CON: 0x%08x\n", REG_READ(SPM_CA7_CPUTOP_PWR_CON)); pr_emerg("SPM_CA15_CPU0_PWR_CON: 0x%08x\n", REG_READ(SPM_CA15_CPU0_PWR_CON)); pr_emerg("SPM_CA15_CPU1_PWR_CON: 0x%08x\n", REG_READ(SPM_CA15_CPU1_PWR_CON)); pr_emerg("SPM_CA15_CPU2_PWR_CON: 0x%08x\n", REG_READ(SPM_CA15_CPU2_PWR_CON)); pr_emerg("SPM_CA15_CPU3_PWR_CON: 0x%08x\n", REG_READ(SPM_CA15_CPU3_PWR_CON)); pr_emerg("SPM_CA15_CPUTOP_PWR_CON: 0x%08x\n", REG_READ(SPM_CA15_CPUTOP_PWR_CON)); #endif return 0; } else { #if 0 //FIXME: how k2 debug monitor if (is_cpu_type(CA7_TYPEID)) { //write back stage pc on ca7 mt_reg_sync_writel(cpu + 8, DBG_MON_CTL); pr_emerg("CPU%u, DBG_MON_CTL: 0x%08x, DBG_MON_DATA: 0x%08x\n", cpu, *(volatile u32 *)(DBG_MON_CTL), *(volatile u32 *)(DBG_MON_DATA)); } else { //decode statge pc on ca15l mt_reg_sync_writel(3+ (cpu - 4) * 4, CA15L_MON_SEL); pr_emerg("CPU%u, CA15L_MON_SEL: 0x%08x, CA15L_MON: 0x%08x\n", cpu, *(volatile u32 *)(CA15L_MON_SEL), *(volatile u32 *)(CA15L_MON)); } #endif on_each_cpu((smp_call_func_t)dump_stack, NULL, 0); atomic_dec(&hotplug_cpu_count); return -ENOSYS; } }
void mx6_dram_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; #ifndef CONFIG_MX6SX volatile struct mmdc_p_regs *mmdc1; #endif 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; #ifndef CONFIG_MX6SX mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR; #endif /* Limit mem_speed for MX6D/MX6Q */ if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) { 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_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) { 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; debug("density:%d Gb (%d Gb per chip)\n", sysinfo->cs_density, ddr3_cfg->density); debug("clock: %dMHz (%d ps)\n", clock, clkper); debug("memspd:%d\n", mem_speed); debug("tcke=%d\n", tcke); debug("tcksrx=%d\n", tcksrx); debug("tcksre=%d\n", tcksre); debug("taofpd=%d\n", taofpd); debug("taonpd=%d\n", taonpd); debug("todtlon=%d\n", todtlon); debug("tanpd=%d\n", tanpd); debug("taxpd=%d\n", taxpd); debug("trfc=%d\n", trfc); debug("txs=%d\n", txs); debug("txp=%d\n", txp); debug("txpdll=%d\n", txpdll); debug("tfaw=%d\n", tfaw); debug("tcl=%d\n", tcl); debug("trcd=%d\n", trcd); debug("trp=%d\n", trp); debug("trc=%d\n", trc); debug("tras=%d\n", tras); debug("twr=%d\n", twr); debug("tmrd=%d\n", tmrd); debug("tcwl=%d\n", tcwl); debug("tdllk=%d\n", tdllk); debug("trtp=%d\n", trtp); debug("twtr=%d\n", twtr); debug("trrd=%d\n", trrd); debug("txpr=%d\n", txpr); debug("cs0_end=%d\n", cs0_end); debug("ncs=%d\n", sysinfo->ncs); debug("Rtt_wr=%d\n", sysinfo->rtt_wr); debug("Rtt_nom=%d\n", sysinfo->rtt_nom); debug("SRT=%d\n", ddr3_cfg->SRT); debug("tcl=%d\n", tcl); debug("twr=%d\n", twr); /* * board-specific configuration: * These values are determined empirically and vary per board layout * see: * appnote, ddr3 spreadsheet */ mmdc0->mpwldectrl0 = calib->p0_mpwldectrl0; mmdc0->mpwldectrl1 = calib->p0_mpwldectrl1; 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 = (1 << 14) | /* REF_SEL: Periodic refresh cycle: 32kHz */ (7 << 11); /* REFR: Refresh Rate - 8 refreshes */ /* Step 13: Deassert config request - init complete */ mmdc0->mdscr = 0x00000000; /* wait for auto-ZQ calibration to complete */ mdelay(1); }
/* setup GPIO pinmux and default configuration per baseboard and env */ void setup_board_gpio(int board, struct ventana_board_info *info) { const char *s; char arg[10]; size_t len; int i; int quiet = simple_strtol(getenv("quiet"), NULL, 10); if (board >= GW_UNKNOWN) return; /* RS232_EN# */ if (gpio_cfg[board].rs232_en) { gpio_direction_output(gpio_cfg[board].rs232_en, (hwconfig("rs232")) ? 0 : 1); } /* MSATA Enable */ if (gpio_cfg[board].msata_en && is_cpu_type(MXC_CPU_MX6Q)) { gpio_direction_output(GP_MSATA_SEL, (hwconfig("msata")) ? 1 : 0); } /* USBOTG Select (PCISKT or FrontPanel) */ if (gpio_cfg[board].usb_sel) { gpio_direction_output(gpio_cfg[board].usb_sel, (hwconfig("usb_pcisel")) ? 1 : 0); } /* * Configure DIO pinmux/padctl registers * see IMX6DQRM/IMX6SDLRM IOMUXC_SW_PAD_CTL_PAD_* register definitions */ for (i = 0; i < gpio_cfg[board].dio_num; i++) { struct dio_cfg *cfg = &gpio_cfg[board].dio_cfg[i]; iomux_v3_cfg_t ctrl = DIO_PAD_CFG; unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1; if (!cfg->gpio_padmux[0] && !cfg->gpio_padmux[1]) continue; sprintf(arg, "dio%d", i); if (!hwconfig(arg)) continue; s = hwconfig_subarg(arg, "padctrl", &len); if (s) { ctrl = MUX_PAD_CTRL(simple_strtoul(s, NULL, 16) & 0x1ffff) | MUX_MODE_SION; } if (hwconfig_subarg_cmp(arg, "mode", "gpio")) { if (!quiet) { printf("DIO%d: GPIO%d_IO%02d (gpio-%d)\n", i, (cfg->gpio_param/32)+1, cfg->gpio_param%32, cfg->gpio_param); } imx_iomux_v3_setup_pad(cfg->gpio_padmux[cputype] | ctrl); gpio_requestf(cfg->gpio_param, "dio%d", i); gpio_direction_input(cfg->gpio_param); } else if (hwconfig_subarg_cmp(arg, "mode", "pwm") && cfg->pwm_padmux) { if (!cfg->pwm_param) { printf("DIO%d: Error: pwm config invalid\n", i); continue; } if (!quiet) printf("DIO%d: pwm%d\n", i, cfg->pwm_param); imx_iomux_v3_setup_pad(cfg->pwm_padmux[cputype] | MUX_PAD_CTRL(ctrl)); } } if (!quiet) { if (gpio_cfg[board].msata_en && is_cpu_type(MXC_CPU_MX6Q)) { printf("MSATA: %s\n", (hwconfig("msata") ? "enabled" : "disabled")); } if (gpio_cfg[board].rs232_en) { printf("RS232: %s\n", (hwconfig("rs232")) ? "enabled" : "disabled"); } } }
static void spl_dram_init(int width, int size, int board_model) { struct mx6_ddr3_cfg *mem = &mt41k128m16jt_125; struct mx6_mmdc_calibration *calib; struct mx6_ddr_sysinfo sysinfo = { /* width of data bus:0=16,1=32,2=64 */ .dsize = width/32, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, /* 32Gb per CS */ /* single chip select */ .ncs = 1, .cs1_mirror = 0, .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ #ifdef RTT_NOM_120OHM .rtt_nom = 2 /*DDR3_RTT_120_OHM*/, /* RTT_Nom = RZQ/2 */ #else .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ #endif .walat = 1, /* Write additional latency */ .ralat = 5, /* Read additional latency */ .mif3_mode = 3, /* Command prediction working mode */ .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ }; /* * MMDC Calibration requires the following data: * mx6_mmdc_calibration - board-specific calibration (routing delays) * mx6_ddr_sysinfo - board-specific memory architecture (width/cs/etc) * mx6_ddr_cfg - chip specific timing/layout details */ switch (board_model) { default: case GW51xx: if (is_cpu_type(MXC_CPU_MX6Q)) calib = &gw51xxq_mmdc_calib; else calib = &gw51xxdl_mmdc_calib; break; case GW52xx: calib = &gw52xxdl_mmdc_calib; break; case GW53xx: if (is_cpu_type(MXC_CPU_MX6Q)) calib = &gw53xxq_mmdc_calib; else calib = &gw53xxdl_mmdc_calib; break; case GW54xx: calib = &gw54xxq_mmdc_calib; break; } if (is_cpu_type(MXC_CPU_MX6Q)) mx6dq_dram_iocfg(width, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); else mx6sdl_dram_iocfg(width, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&sysinfo, calib, mem); } /* * called from C runtime startup code (arch/arm/lib/crt0.S:_main) * - we have a stack and a place to store GD, both in SRAM * - no variable global data is available */ void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model; /* * Zero out global data: * - this shoudl be done by crt0.S * - failure to zero it will cause i2c_setup to fail */ memset((void *)gd, 0, sizeof(struct global_data)); /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0); } void reset_cpu(ulong addr) { }
/* * This section requires the differentiation between Solidrun mx6 boards, but * for now, it will configure only for the mx6dual hummingboard version. */ static void spl_dram_init(int width) { struct mx6_ddr_sysinfo sysinfo = { /* width of data bus: 0=16, 1=32, 2=64 */ .dsize = width / 32, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, /* 32Gb per CS */ .ncs = 1, /* single chip select */ .cs1_mirror = 0, .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ .walat = 1, /* Write additional latency */ .ralat = 5, /* Read additional latency */ .mif3_mode = 3, /* Command prediction working mode */ .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ }; if (is_cpu_type(MXC_CPU_MX6D) || is_cpu_type(MXC_CPU_MX6Q)) mx6dq_dram_iocfg(width, &mx6q_ddr_ioregs, &mx6q_grp_ioregs); else mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs); if (is_cpu_type(MXC_CPU_MX6D)) mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); else if (is_cpu_type(MXC_CPU_MX6Q)) mx6_dram_cfg(&sysinfo, &mx6q_2g_mmcd_calib, &mem_ddr_4g); else if (is_cpu_type(MXC_CPU_MX6DL)) mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); else if (is_cpu_type(MXC_CPU_MX6SOLO)) mx6_dram_cfg(&sysinfo, &mx6dl_512m_mmcd_calib, &mem_ddr_2g); } void board_init_f(ulong dummy) { /* setup AIPS and disable watchdog */ arch_cpu_init(); ccgr_init(); gpr_init(); /* iomux and setup of i2c */ board_early_init_f(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* DDR initialization */ if (is_cpu_type(MXC_CPU_MX6SOLO)) spl_dram_init(32); else spl_dram_init(64); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0); }