| /* |
| * |
| * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * 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; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| #include <common.h> |
| #include <init.h> |
| #include <mach/imx-regs.h> |
| #include <mach/imx-pll.h> |
| #include <mach/esdctl.h> |
| #include <asm/cache-l2x0.h> |
| #include <asm/io.h> |
| #include <mach/imx-nand.h> |
| #include <asm/barebox-arm.h> |
| #include <asm-generic/memory_layout.h> |
| #include <asm/system.h> |
| |
| /* Assuming 24MHz input clock */ |
| #define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) |
| #define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) |
| #define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) |
| |
| #define SDRAM_MODE_BL_8 0x0003 |
| #define SDRAM_MODE_BSEQ 0x0000 |
| #define SDRAM_MODE_CL_3 0x0030 |
| #define MDDR_DS_HALF 0x20 |
| #define SDRAM_COMPARE_CONST1 0x55555555 |
| #define SDRAM_COMPARE_CONST2 0xaaaaaaaa |
| |
| #ifdef CONFIG_NAND_IMX_BOOT |
| static void __bare_init __naked insdram(void) |
| { |
| uint32_t r; |
| |
| /* Speed up NAND controller by adjusting the NFC divider */ |
| r = readl(IMX_CCM_BASE + CCM_PDR4); |
| r &= ~(0xf << 28); |
| r |= 0x1 << 28; |
| writel(r, IMX_CCM_BASE + CCM_PDR4); |
| |
| /* setup a stack to be able to call imx_nand_load_image() */ |
| r = STACK_BASE + STACK_SIZE - 12; |
| __asm__ __volatile__("mov sp, %0" : : "r"(r)); |
| |
| imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); |
| |
| board_init_lowlevel_return(); |
| } |
| #endif |
| |
| static void __bare_init noinline setup_sdram(u32 memsize, u32 mode, u32 sdram_addr) |
| { |
| volatile int loop; |
| void *r9 = (void *)IMX_SDRAM_CS0; |
| u32 r11 = 0xda; /* dummy constant */ |
| u32 r1, r0; |
| |
| /* disable second SDRAM region to save power */ |
| r1 = readl(ESDCTL1); |
| r1 &= ~ESDCTL0_SDE; |
| writel(r1, ESDCTL1); |
| |
| mode |= ESDMISC_RST | ESDMISC_MDDR_DL_RST; |
| writel(mode, ESDMISC); |
| |
| mode &= ~(ESDMISC_RST | ESDMISC_MDDR_DL_RST); |
| writel(mode, ESDMISC); |
| |
| /* wait for esdctl reset */ |
| for (loop = 0; loop < 0x20000; loop++); |
| |
| r1 = ESDCFGx_tXP_4 | ESDCFGx_tWTR_1 | |
| ESDCFGx_tRP_3 | ESDCFGx_tMRD_2 | |
| ESDCFGx_tWR_1_2 | ESDCFGx_tRAS_6 | |
| ESDCFGx_tRRD_2 | ESDCFGx_tCAS_3 | |
| ESDCFGx_tRCD_3 | ESDCFGx_tRC_20; |
| |
| writel(r1, ESDCFG0); |
| |
| /* enable SDRAM controller */ |
| writel(memsize | ESDCTL0_SMODE_NORMAL, ESDCTL0); |
| |
| /* Micron Datasheet Initialization Step 3: Wait 200us before first command */ |
| for (loop = 0; loop < 1000; loop++); |
| |
| /* Micron Datasheet Initialization Step 4: PRE CHARGE ALL */ |
| writel(memsize | ESDCTL0_SMODE_PRECHARGE, ESDCTL0); |
| writeb(r11, sdram_addr); |
| |
| /* Micron Datasheet Initialization Step 5: NOP for tRP (at least 22.5ns) |
| * The CPU is not fast enough to cause a problem here |
| */ |
| |
| /* Micron Datasheet Initialization Step 6: 2 AUTO REFRESH and tRFC NOP |
| * (at least 140ns) |
| */ |
| writel(memsize | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0); |
| writeb(r11, r9); /* AUTO REFRESH #1 */ |
| |
| for (loop = 0; loop < 3; loop++); /* ~140ns delay at 532MHz */ |
| |
| writeb(r11, r9); /* AUTO REFRESH #2 */ |
| |
| for (loop = 0; loop < 3; loop++); /* ~140ns delay at 532MHz */ |
| |
| /* Micron Datasheet Initialization Step 7: LOAD MODE REGISTER */ |
| writel(memsize | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0); |
| writeb(r11, r9 + (SDRAM_MODE_BL_8 | SDRAM_MODE_BSEQ | SDRAM_MODE_CL_3)); |
| |
| /* Micron Datasheet Initialization Step 8: tMRD = 2 tCK NOP |
| * (The memory controller will take care of this delay) |
| */ |
| |
| /* Micron Datasheet Initialization Step 9: LOAD MODE REGISTER EXTENDED */ |
| writeb(r11, 0x84000000 | MDDR_DS_HALF); /*we assume 14 Rows / 10 Cols here */ |
| |
| /* Micron Datasheet Initialization Step 9: tMRD = 2 tCK NOP |
| * (The memory controller will take care of this delay) |
| */ |
| |
| /* Now configure SDRAM-Controller and check that it works */ |
| writel(memsize | ESDCTL0_BL | ESDCTL0_REF4, ESDCTL0); |
| |
| /* Freescale asks for first access to be a write to properly |
| * initialize DQS pin-state and keepers |
| */ |
| writel(0xdeadbeef, r9); |
| |
| /* test that the RAM is in fact working */ |
| writel(SDRAM_COMPARE_CONST1, r9); |
| writel(SDRAM_COMPARE_CONST2, r9 + 0x4); |
| |
| if (readl(r9) != SDRAM_COMPARE_CONST1) |
| while (1); |
| |
| /* Verify that the correct row and coloumn is selected */ |
| |
| /* So far we asssumed that we have 14 rows, verify this */ |
| writel(SDRAM_COMPARE_CONST1, r9); |
| writel(SDRAM_COMPARE_CONST2, r9 + (1 << 25)); |
| |
| /* if both value are identical, we don't have 14 rows. assume 13 instead */ |
| if (readl(r9) == readl(r9 + (1 << 25))) { |
| r0 = readl(ESDCTL0); |
| r0 &= ~ESDCTL0_ROW_MASK; |
| r0 |= ESDCTL0_ROW13; |
| writel(r0, ESDCTL0); |
| } |
| |
| /* So far we asssumed that we have 10 columns, verify this */ |
| writel(SDRAM_COMPARE_CONST1, r9); |
| writel(SDRAM_COMPARE_CONST2, r9 + (1 << 11)); |
| |
| /* if both value are identical, we don't have 10 cols. assume 9 instead */ |
| if (readl(r9) == readl(r9 + (1 << 11))) { |
| r0 = readl(ESDCTL0); |
| r0 &= ~ESDCTL0_COL_MASK; |
| r0 |= ESDCTL0_COL9; |
| writel(r0, ESDCTL0); |
| } |
| } |
| |
| #define BRANCH_PREDICTION_ENABLE |
| #define UNALIGNED_ACCESS_ENABLE |
| #define LOW_INT_LATENCY_ENABLE |
| |
| void __bare_init __naked board_init_lowlevel(void) |
| { |
| u32 r0, r1; |
| void *iomuxc_base = (void *)IMX_IOMUXC_BASE; |
| int i; |
| #ifdef CONFIG_NAND_IMX_BOOT |
| unsigned int *trg, *src; |
| #endif |
| |
| r0 = 0x10000000 + 128 * 1024 - 16; |
| __asm__ __volatile__("mov sp, %0" : : "r"(r0)); |
| |
| /* |
| * ARM1136 init |
| * - invalidate I/D cache/TLB and drain write buffer; |
| * - invalidate L2 cache |
| * - unaligned access |
| * - branch predictions |
| */ |
| #ifdef TURN_OFF_IMPRECISE_ABORT |
| __asm__ __volatile__("mrs %0, cpsr":"=r"(r0)); |
| r0 &= ~0x100; |
| __asm__ __volatile__("msr cpsr, %0" : : "r"(r0)); |
| #endif |
| /* ensure L1 caches and MMU are turned-off for now */ |
| r1 = get_cr(); |
| r1 &= ~(CR_I | CR_M | CR_C); |
| |
| /* setup core features */ |
| __asm__ __volatile__("mrc p15, 0, r0, c1, c0, 1":"=r"(r0)); |
| #ifdef BRANCH_PREDICTION_ENABLE |
| r0 |= 7; |
| r1 |= CR_Z; |
| #else |
| r0 &= ~7; |
| r1 &= ~CR_Z; |
| #endif |
| __asm__ __volatile__("mcr p15, 0, r0, c1, c0, 1" : : "r"(r0)); |
| |
| #ifdef UNALIGNED_ACCESS_ENABLE |
| r1 |= CR_U; |
| #else |
| r1 &= ~CR_U; |
| #endif |
| |
| #ifdef LOW_INT_LATENCY_ENABLE |
| r1 |= CR_FI; |
| #else |
| r1 &= ~CR_FI; |
| #endif |
| set_cr(r1); |
| |
| r0 = 0; |
| __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 6" : : "r"(r0)); |
| |
| /* invalidate I cache and D cache */ |
| __asm__ __volatile__("mcr p15, 0, r0, c7, c7, 0" : : "r"(r0)); |
| /* invalidate TLBs */ |
| __asm__ __volatile__("mcr p15, 0, r0, c8, c7, 0" : : "r"(r0)); |
| /* Drain the write buffer */ |
| __asm__ __volatile__("mcr p15, 0, r0, c7, c10, 4" : : "r"(r0)); |
| |
| /* Also setup the Peripheral Port Remap register inside the core */ |
| r0 = 0x40000015; /* start from AIPS 2GB region */ |
| __asm__ __volatile__("mcr p15, 0, r0, c15, c2, 4" : : "r"(r0)); |
| |
| #define WDOG_WMCR 0x8 |
| /* silence reset WDOG */ |
| writew(0, IMX_WDOG_BASE + WDOG_WMCR); |
| |
| /* Skip SDRAM initialization if we run from RAM */ |
| r0 = get_pc(); |
| if (r0 > 0x80000000 && r0 < 0x90000000) |
| board_init_lowlevel_return(); |
| |
| /* Configure drive strength */ |
| |
| /* Configure DDR-pins to correct mode */ |
| r0 = 0x00001800; |
| writel(r0, iomuxc_base + 0x794); |
| writel(r0, iomuxc_base + 0x798); |
| writel(r0, iomuxc_base + 0x79c); |
| writel(r0, iomuxc_base + 0x7a0); |
| writel(r0, iomuxc_base + 0x7a4); |
| |
| /* Set drive strength for DDR-pins */ |
| for (i = 0x368; i <= 0x4c8; i += 4) { |
| r0 = readl(iomuxc_base + i); |
| r0 &= ~0x6; |
| r0 |= 0x2; |
| writel(r0, iomuxc_base + i); |
| if (i == 0x468) |
| i = 0x4a4; |
| } |
| |
| r0 = readl(iomuxc_base + 0x480); |
| r0 &= ~0x6; |
| r0 |= 0x2; |
| writel(r0, iomuxc_base + 0x480); |
| |
| r0 = readl(iomuxc_base + 0x4b8); |
| r0 &= ~0x6; |
| r0 |= 0x2; |
| writel(r0, iomuxc_base + 0x4b8); |
| |
| /* Configure static chip-selects */ |
| r0 = readl(iomuxc_base + 0x000); |
| r0 &= ~1; /* configure CS2/CSD0 for SDRAM */ |
| writel(r0, iomuxc_base + 0x000); |
| |
| /* start-up code doesn't need any static chip-select. |
| * Leave their initialization to high-level code that |
| * can initialize them depending on the baseboard. |
| */ |
| |
| /* Configure clocks */ |
| |
| /* setup cpu/bus clocks */ |
| writel(0x003f4208, IMX_CCM_BASE + CCM_CCMR); |
| |
| /* configure MPLL */ |
| writel(MPCTL_PARAM_532, IMX_CCM_BASE + CCM_MPCTL); |
| |
| /* configure PPLL */ |
| writel(PPCTL_PARAM_300, IMX_CCM_BASE + CCM_PPCTL); |
| |
| /* configure core dividers */ |
| r0 = PDR0_CCM_PER_AHB(1) | PDR0_HSP_PODF(2); |
| |
| writel(r0, IMX_CCM_BASE + CCM_PDR0); |
| |
| /* configure clock-gates */ |
| r0 = readl(IMX_CCM_BASE + CCM_CGR0); |
| r0 |= 0x00300000; |
| writel(r0, IMX_CCM_BASE + CCM_CGR0); |
| |
| r0 = readl(IMX_CCM_BASE + CCM_CGR1); |
| r0 |= 0x00000c03; |
| writel(r0, IMX_CCM_BASE + CCM_CGR1); |
| |
| /* Configure SDRAM */ |
| /* Try 32-Bit 256 MB DDR memory */ |
| r0 = ESDCTL0_SDE | ESDCTL0_ROW14 | ESDCTL0_COL10 | ESDCTL0_DSIZ_31_0; /* 1024 MBit DDR-SDRAM */ |
| setup_sdram(r0, ESDMISC_MDDR_EN, 0x80000f00); |
| |
| #ifdef CONFIG_NAND_IMX_BOOT |
| /* skip NAND boot if not running from NFC space */ |
| r0 = get_pc(); |
| if (r0 < IMX_NFC_BASE || r0 > IMX_NFC_BASE + 0x800) |
| board_init_lowlevel_return(); |
| |
| src = (unsigned int *)IMX_NFC_BASE; |
| trg = (unsigned int *)TEXT_BASE; |
| |
| /* Move ourselves out of NFC SRAM */ |
| for (i = 0; i < 0x800 / sizeof(int); i++) |
| *trg++ = *src++; |
| |
| /* Jump to SDRAM */ |
| r0 = (unsigned int)&insdram; |
| __asm__ __volatile__("mov pc, %0" : : "r"(r0)); |
| #else |
| board_init_lowlevel_return(); |
| #endif |
| } |
| |