/* * * (c) 2007 Pengutronix, Sascha Hauer * * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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(MX35_CCM_BASE_ADDR + CCM_PDR4); r &= ~(0xf << 28); r |= 0x1 << 28; writel(r, MX35_CCM_BASE_ADDR + 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(_text, barebox_image_size); 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 *)MX35_CSD0_BASE_ADDR; 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 reset(void) { u32 r0, r1; void *iomuxc_base = (void *)IMX_IOMUXC_BASE; int i; #ifdef CONFIG_NAND_IMX_BOOT unsigned int *trg, *src; #endif common_reset(); 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, MX35_WDOG_BASE_ADDR + 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, MX35_CCM_BASE_ADDR + CCM_CCMR); /* configure MPLL */ writel(MPCTL_PARAM_532, MX35_CCM_BASE_ADDR + CCM_MPCTL); /* configure PPLL */ writel(PPCTL_PARAM_300, MX35_CCM_BASE_ADDR + CCM_PPCTL); /* configure core dividers */ r0 = PDR0_CCM_PER_AHB(1) | PDR0_HSP_PODF(2); writel(r0, MX35_CCM_BASE_ADDR + CCM_PDR0); /* configure clock-gates */ r0 = readl(MX35_CCM_BASE_ADDR + CCM_CGR0); r0 |= 0x00300000; writel(r0, MX35_CCM_BASE_ADDR + CCM_CGR0); r0 = readl(MX35_CCM_BASE_ADDR + CCM_CGR1); r0 |= 0x00000c03; writel(r0, MX35_CCM_BASE_ADDR + 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 < MX35_NFC_BASE_ADDR || r0 > MX35_NFC_BASE_ADDR + 0x800) board_init_lowlevel_return(); src = (unsigned int *)MX35_NFC_BASE_ADDR; trg = (unsigned int *)_text; /* 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 }