diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | board/freescale/mx31_3stack/Makefile | 47 | ||||
-rw-r--r-- | board/freescale/mx31_3stack/config.mk | 1 | ||||
-rw-r--r-- | board/freescale/mx31_3stack/lowlevel_init.S | 248 | ||||
-rw-r--r-- | board/freescale/mx31_3stack/mx31_3stack.c | 75 | ||||
-rw-r--r-- | board/freescale/mx31_3stack/u-boot.lds | 72 | ||||
-rw-r--r-- | cpu/arm1136/mx31/Makefile | 4 | ||||
-rw-r--r-- | cpu/arm1136/mx31/nand_load.S | 160 | ||||
-rw-r--r-- | cpu/arm1136/start.S | 113 | ||||
-rw-r--r-- | cpu/arm926ejs/mx27/timer.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/mx31_nand.c | 969 | ||||
-rw-r--r-- | include/asm-arm/arch-mx31/mx31-regs.h | 96 | ||||
-rw-r--r-- | include/configs/mx31_3stack.h | 165 |
14 files changed, 1925 insertions, 30 deletions
@@ -3229,6 +3229,9 @@ mx31pdk_nand_config : unconfig fi @$(MKCONFIG) -a mx31pdk arm arm1136 mx31pdk freescale mx31 +Mx31_3stack_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm1136 mx31_3stack freescale mx31 + mx35_3stack_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm1136 mx35_3stack freescale mx35 diff --git a/board/freescale/mx31_3stack/Makefile b/board/freescale/mx31_3stack/Makefile new file mode 100644 index 0000000..836c19c --- /dev/null +++ b/board/freescale/mx31_3stack/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := mx31_3stack.o +SOBJS := lowlevel_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/freescale/mx31_3stack/config.mk b/board/freescale/mx31_3stack/config.mk new file mode 100644 index 0000000..d34dc02 --- /dev/null +++ b/board/freescale/mx31_3stack/config.mk @@ -0,0 +1 @@ +TEXT_BASE = 0x87f00000 diff --git a/board/freescale/mx31_3stack/lowlevel_init.S b/board/freescale/mx31_3stack/lowlevel_init.S new file mode 100644 index 0000000..bd0de81 --- /dev/null +++ b/board/freescale/mx31_3stack/lowlevel_init.S @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> + * Copyright (C) 2008, Freescale Semiconductor + * Modifications for MX31 3Stack board + * + * 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 <asm/arch/mx31-regs.h> + +.macro REG reg, val + ldr r2, =\reg + ldr r3, =\val + str r3, [r2] +.endm + +.macro REG8 reg, val + ldr r2, =\reg + ldr r3, =\val + strb r3, [r2] +.endm + +.macro DELAY loops + ldr r2, =\loops +1: + subs r2, r2, #1 + nop + bcs 1b +.endm + +.macro init_aips + /* + * Set all MPROTx to be non-bufferable, trusted for R/W, + * not forced to user-mode. + */ + ldr r0, =0x43F00000 + ldr r1, =0x77777777 + str r1, [r0, #0x00] + str r1, [r0, #0x04] + ldr r0, =0x53F00000 + str r1, [r0, #0x00] + str r1, [r0, #0x04] + + /* + * Clear the on and off peripheral modules Supervisor Protect bit + * for SDMA to access them. Did not change the AIPS control registers + * (offset 0x20) access type + */ + ldr r0, =0x43F00000 + ldr r1, =0x0 + str r1, [r0, #0x40] + str r1, [r0, #0x44] + str r1, [r0, #0x48] + str r1, [r0, #0x4C] + ldr r1, [r0, #0x50] + and r1, r1, #0x00FFFFFF + str r1, [r0, #0x50] + + ldr r0, =0x53F00000 + ldr r1, =0x0 + str r1, [r0, #0x40] + str r1, [r0, #0x44] + str r1, [r0, #0x48] + str r1, [r0, #0x4C] + ldr r1, [r0, #0x50] + and r1, r1, #0x00FFFFFF + str r1, [r0, #0x50] +.endm /* init_aips */ + +.macro init_max + ldr r0, =0x43F04000 + /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ + ldr r1, =0x00302154 + str r1, [r0, #0x000] /* for S0 */ + str r1, [r0, #0x100] /* for S1 */ + str r1, [r0, #0x200] /* for S2 */ + str r1, [r0, #0x300] /* for S3 */ + str r1, [r0, #0x400] /* for S4 */ + /* SGPCR - always park on last master */ + ldr r1, =0x10 + str r1, [r0, #0x010] /* for S0 */ + str r1, [r0, #0x110] /* for S1 */ + str r1, [r0, #0x210] /* for S2 */ + str r1, [r0, #0x310] /* for S3 */ + str r1, [r0, #0x410] /* for S4 */ + /* MGPCR - restore default values */ + ldr r1, =0x0 + str r1, [r0, #0x800] /* for M0 */ + str r1, [r0, #0x900] /* for M1 */ + str r1, [r0, #0xA00] /* for M2 */ + str r1, [r0, #0xB00] /* for M3 */ + str r1, [r0, #0xC00] /* for M4 */ + str r1, [r0, #0xD00] /* for M5 */ +.endm /* init_max */ + +.macro init_m3if + /* Configure M3IF registers */ + ldr r1, =0xB8003000 + /* + * M3IF Control Register (M3IFCTL) + * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 + * MRRP[1] = L2CC1 not on priority list (0 << 0) = 0x00000000 + * MRRP[2] = MBX not on priority list (0 << 0) = 0x00000000 + * MRRP[3] = MAX1 not on priority list (0 << 0) = 0x00000000 + * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 + * MRRP[5] = MPEG4 not on priority list (0 << 0) = 0x00000000 + * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 + * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 + * ------------ + * 0x00000040 + */ + ldr r0, =0x00000040 + str r0, [r1] /* M3IF control reg */ +.endm /* init_m3if */ + +.macro init_drive_strength + /* + * Disable maximum drive strength SDRAM/DDR lines by clearing DSE1 bits + * in SW_PAD_CTL registers + */ + + /* SDCLK */ + ldr r1, =0x43FAC200 + ldr r0, [r1, #0x6C] + bic r0, r0, #(1 << 12) + str r0, [r1, #0x6C] + + /* CAS */ + ldr r0, [r1, #0x70] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x70] + + /* RAS */ + ldr r0, [r1, #0x74] + bic r0, r0, #(1 << 2) + str r0, [r1, #0x74] + + /* CS2 (CSD0) */ + ldr r0, [r1, #0x7C] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x7C] + + /* DQM3 */ + ldr r0, [r1, #0x84] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x84] + + /* DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2DC) */ + ldr r2, =22 /* (0x2E0 - 0x288) / 4 = 22 */ +pad_loop: + ldr r0, [r1, #0x88] + bic r0, r0, #(1 << 22) + bic r0, r0, #(1 << 12) + bic r0, r0, #(1 << 2) + str r0, [r1, #0x88] + add r1, r1, #4 + subs r2, r2, #0x1 + bne pad_loop +.endm /* init_drive_strength */ + +.section ".text.init", "x" + +.globl lowlevel_init +lowlevel_init: + + ldr r0, =0x40000015 /* start from AIPS 2GB region */ + mcr p15, 0, r0, c15, c2, 4 + + init_aips + + init_max + + init_m3if + + init_drive_strength + + /* Image Processing Unit: */ + /* Too early to switch display on? */ + REG IPU_CONF, IPU_CONF_DI_EN + /* Clock Control Module: */ + REG CCM_CCMR, 0x074B0BF5 /* Use CKIH, MCU PLL off */ + + DELAY 0x40000 + + REG CCM_CCMR, 0x074B0BF5 | CCMR_MPE /* MCU PLL on */ + /* Switch to MCU PLL */ + REG CCM_CCMR, (0x074B0BF5 | CCMR_MPE) & ~CCMR_MDS + + /* 532-133-66.5 */ + ldr r0, =CCM_BASE + ldr r1, =0xFF871D58 + /* PDR0 */ + str r1, [r0, #0x4] + ldr r1, MPCTL_PARAM_532 + /* MPCTL */ + str r1, [r0, #0x10] + + /* Set UPLL=240MHz, USB=60MHz */ + ldr r1, =0x49FCFE7F + /* PDR1 */ + str r1, [r0, #0x8] + ldr r1, UPCTL_PARAM_240 + /* UPCTL */ + str r1, [r0, #0x14] + /* default CLKO to 1/8 of the ARM core */ + mov r1, #0x000002C0 + add r1, r1, #0x00000006 + /* COSR */ + str r1, [r0, #0x1c] + + /* initial CSD0 MDDR */ + REG 0xB8001004, 0x0075E73A + REG 0xB8001010, 0x00000002 /* reset */ + REG 0xB8001010, 0x00000004 + DELAY 0x10000 + + REG 0xB8001000, 0x92100000 + REG 0x80000F00, 0x0 + REG 0xB8001000, 0xA2100000 + REG 0x80000000, 0x0 + REG 0xB8001000, 0xB2100000 + REG8 0x80000033, 0x0 + REG8 0x81000000, 0xff + REG 0xB8001000, 0x82226080 + REG 0x80000000, 0x0 + REG 0xB8001010, 0x0000000c + + mov r13, ip + /* copy blocks of total uboot to DDR */ + b mxc_nand_load + +MPCTL_PARAM_532: + .word (((1-1) << 26) + ((52-1) << 16) + (10 << 10) + (12 << 0)) +UPCTL_PARAM_240: + .word (((2-1) << 26) + ((13-1) << 16) + (9 << 10) + (3 << 0)) diff --git a/board/freescale/mx31_3stack/mx31_3stack.c b/board/freescale/mx31_3stack/mx31_3stack.c new file mode 100644 index 0000000..33adfd3 --- /dev/null +++ b/board/freescale/mx31_3stack/mx31_3stack.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Modifications for MX31 3Stack board + * + * 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 <asm/io.h> +#include <asm/arch/mx31.h> +#include <asm/arch/mx31-regs.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return 0; +} + +int board_init(void) +{ + /* CS5: Debug board for ethernet */ + __REG(CSCR_U(5)) = 0x0000D843; + __REG(CSCR_L(5)) = 0x22252521; + __REG(CSCR_A(5)) = 0x22220A00; + + /* setup pins for UART1 */ + mx31_gpio_mux(MUX_RXD1__UART1_RXD_MUX); + mx31_gpio_mux(MUX_TXD1__UART1_TXD_MUX); + mx31_gpio_mux(MUX_RTS1__UART1_RTS_B); + mx31_gpio_mux(MUX_RTS1__UART1_CTS_B); + + /* SPI2 */ + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_SS2); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_SCLK); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_SPI_RDY); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_MOSI); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_MISO); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_SS0); + mx31_gpio_mux((MUX_CTL_FUNC << 8) | MUX_CTL_CSPI2_SS1); + + /* start SPI2 clock */ + __REG(CCM_CGR2) = __REG(CCM_CGR2) | (3 << 4); + + gd->bd->bi_arch_number = MACH_TYPE_MX31_3DS; /* board id for linux */ + gd->bd->bi_boot_params = 0x80000100; /* adress of boot parameters */ + + return 0; +} + +int checkboard(void) +{ + printf("Board: MX31 3Stack\n"); + return 0; +} diff --git a/board/freescale/mx31_3stack/u-boot.lds b/board/freescale/mx31_3stack/u-boot.lds new file mode 100644 index 0000000..8b717ff --- /dev/null +++ b/board/freescale/mx31_3stack/u-boot.lds @@ -0,0 +1,72 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(reset) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector layout of our flash chips! XXX FIXME XXX */ + + * (.text.head) /* arm reset handler */ + * (.text.init) /* lowlevel initial */ + * (.text.load) /* nand copy and load */ + * (.text.setup) + board/freescale/mx31_3stack/libmx31_3stack.a (.text) + lib_arm/libarm.a (.text) + net/libnet.a (.text) + drivers/mtd/libmtd.a (.text) + + . = DEFINED(env_offset) ? env_offset : .; + common/environment.o(.text) + + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/cpu/arm1136/mx31/Makefile b/cpu/arm1136/mx31/Makefile index c8e18f7..a57465f 100644 --- a/cpu/arm1136/mx31/Makefile +++ b/cpu/arm1136/mx31/Makefile @@ -29,6 +29,10 @@ COBJS += generic.o COBJS += timer.o COBJS += devices.o +ifdef CONFIG_NAND_BOOT +SOBJS = nand_load.o +endif + SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/arm1136/mx31/nand_load.S b/cpu/arm1136/mx31/nand_load.S new file mode 100644 index 0000000..c0d099a --- /dev/null +++ b/cpu/arm1136/mx31/nand_load.S @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, 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; 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 <config.h> +#include <asm/arch/mx31-regs.h> + +.section ".text.load", "x" + +.macro wait_op_done +1: ldrh r3, [r12, #NAND_FLASH_CONFIG2_REG_OFF] + ands r3, r3, #NAND_FLASH_CONFIG2_INT_DONE + beq 1b +.endm + +data_output: + strh r8, [r12, #RAM_BUFFER_ADDRESS_REG_OFF] + mov r3, #FDO_PAGE_SPARE_VAL + strh r3, [r12, #NAND_FLASH_CONFIG2_REG_OFF] + wait_op_done + bx lr + +send_addr: + strh r3, [r12, #NAND_FLASH_ADD_REG_OFF] + mov r3, #NAND_FLASH_CONFIG2_FADD_EN + strh r3, [r12, #NAND_FLASH_CONFIG2_REG_OFF] + wait_op_done + bx lr + +send_cmd: + strh r3, [r12, #NAND_FLASH_CMD_REG_OFF] + mov r3, #NAND_FLASH_CONFIG2_FCMD_EN + strh r3, [r12, #NAND_FLASH_CONFIG2_REG_OFF] + wait_op_done + bx lr + + +nand_read_page: + + mov r7, lr + + mov r3, #0x0 + /* send command */ + bl send_cmd + /* 5 cycles address input */ + mov r3, #0x0 + bl send_addr + mov r3, #0x0 + bl send_addr + mov r3, r0 + bl send_addr + mov r3, #0x0 + bl send_addr + mov r3, #0x0 + bl send_addr + /* confirm read */ + mov r3, #0x30 + bl send_cmd + /* data output */ + mov r8, #0x0 + mov r4, #0x4 +1: + bl data_output + add r8, r8, #0x01 + cmp r8, r4 + bne 1b + ldrh r3, [r12, #ECC_STATUS_RESULT_REG_OFF] + tst r3, #0x0a + bne . + mov pc, r7 + +.global mxc_nand_load +mxc_nand_load: + + /* Copy image from flash to SDRAM first */ + mov r0, #NFC_BASE_ADDR + add r12, r0, #0xE00 /* register */ + add r2, r0, #0x800 /* 2K */ + ldr r1, __TEXT_BASE + +1: ldmia r0!, {r3-r10} + stmia r1!, {r3-r10} + cmp r0, r2 + blo 1b + /* Jump to SDRAM */ + ldr r1, =0x0FFF + and r0, pc, r1 /* offset of pc */ + ldr r1, __TEXT_BASE + add r1, r1, #0x10 + add pc, r0, r1 + nop + nop + nop + nop + +nand_copy_block: + + /* wait for boot complete */ +4: + ldrh r3, [r12, #NAND_FLASH_CONFIG2_REG_OFF] + tst r3, #0x8000 + beq 4b + + /* unlock buffer and blocks */ + mov r3, #0x02 + strh r3, [r12, #NFC_CONFIGURATION_REG_OFF] + mov r3, #0x0 + strh r3, [r12, #UNLOCK_START_BLK_ADD_REG_OFF] + mov r3, #0x800 + strh r3, [r12, #UNLOCK_END_BLK_ADD_REG_OFF] + mov r3, #0x04 + strh r3, [r12, #NF_WR_PROT_REG_OFF] + mov r3, #0x10 + strh r3, [r12, #NAND_FLASH_CONFIG1_REG_OFF] + + /* read 1 block, 256K */ + mov r0, #0x01 /* page offset */ + ldr r11, __TEXT_BASE + add r11, r11, #0x800 + + mov r1, #NFC_BASE_ADDR + add r2, r1, #0x800 +2: + bl nand_read_page /* r0, r1, r2, r11 has been used */ + /* copy data from internal buffer */ +3: ldmia r1!, {r3-r10} + stmia r11!, {r3-r10} + cmp r1, r2 + blo 3b + + add r0, r0, #0x01 + cmp r0, #0x80 + mov r1, #NFC_BASE_ADDR + bne 2b + + /* set pc to _set_env */ + ldr r11, __TEXT_BASE + ldr r1, =0x7FF + /* correct the lr */ + and r13, r13, r1 + add r13, r13, r11 + mov pc, r13 + +__TEXT_BASE: + .word TEXT_BASE diff --git a/cpu/arm1136/start.S b/cpu/arm1136/start.S index 957f438..a957ccc 100644 --- a/cpu/arm1136/start.S +++ b/cpu/arm1136/start.S @@ -85,40 +85,15 @@ _end_vect: ************************************************************************* */ -_TEXT_BASE: - .word TEXT_BASE - -.globl _armboot_start -_armboot_start: - .word _start - /* - * These are defined in the board-specific linker script. + * the actual reset code */ -.globl _bss_start -_bss_start: - .word __bss_start - -.globl _bss_end -_bss_end: - .word _end -#ifdef CONFIG_USE_IRQ -/* IRQ stack memory (calculated at run-time) */ -.globl IRQ_STACK_START -IRQ_STACK_START: - .word 0x0badc0de - -/* IRQ stack memory (calculated at run-time) */ -.globl FIQ_STACK_START -FIQ_STACK_START: - .word 0x0badc0de +#ifdef CONFIG_NAND_BOOT +.section ".text.head", "x" #endif -/* - * the actual reset code - */ - +.globl reset reset: /* * set the cpu to SVC32 mode @@ -150,6 +125,86 @@ next: #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif + b setup_env + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +cpu_init_crit: + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0 + + /* + * Jump to board specific initialization... The Mask ROM will have already initialized + * basic memory. Go here to bump up clock rate and handle wake up conditions. + */ + mov ip, lr /* persevere link reg across call */ + bl lowlevel_init /* go setup pll,mux,memory */ + mov lr, ip /* restore link */ + mov pc, lr /* back to my caller */ + + +#ifdef CONFIG_NAND_BOOT +.section ".text.setup" +#endif + +.globl _TEST_BASE +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: +#ifndef CONFIG_NAND_BOOT + .word _start +#else + .word reset +#endif + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +setup_env: #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ diff --git a/cpu/arm926ejs/mx27/timer.c b/cpu/arm926ejs/mx27/timer.c index 9011058..1e13627 100644 --- a/cpu/arm926ejs/mx27/timer.c +++ b/cpu/arm926ejs/mx27/timer.c @@ -118,7 +118,6 @@ int timer_init(void) writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, ®s->gpt_tctl); writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); - return 0; } diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 89ccec2..975a1b8 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o +COBJS-$(CONFIG_MX31_NAND) += mx31_nand.o endif COBJS := $(COBJS-y) diff --git a/drivers/mtd/nand/mx31_nand.c b/drivers/mtd/nand/mx31_nand.c new file mode 100644 index 0000000..325e0f0 --- /dev/null +++ b/drivers/mtd/nand/mx31_nand.c @@ -0,0 +1,969 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <common.h> +#include <nand.h> +#include <asm-arm/arch/mx31-regs.h> + +/* + * Define delays in microsec for NAND device operations + */ +#define TROP_US_DELAY 2000 + +/* + * Macros to get byte and bit positions of ECC + */ +#define COLPOS(x) ((x) >> 4) +#define BITPOS(x) ((x) & 0xf) + +/* Define single bit Error positions in Main & Spare area */ +#define MAIN_SINGLEBIT_ERROR 0x4 +#define SPARE_SINGLEBIT_ERROR 0x1 + +struct nand_info { + int oob; + int read_status; + int largepage; + u16 col; +}; + +static struct nand_info nandinfo; +static int ecc_disabled; + +/* + * OOB placement block for use with hardware ecc generation + */ +static struct nand_oobinfo nand_hw_eccoob_8 = { + .useecc = MTD_NANDECC_AUTOPL_USR, + .eccbytes = 5, + .eccpos = {6, 7, 8, 9, 10}, + .oobfree = { + {0, 5}, + {11, 5} + } +}; + +static struct nand_oobinfo nand_hw_eccoob_2k = { + .useecc = MTD_NANDECC_AUTOPL_USR, + .eccbytes = 20, + .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, + 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, + .oobfree = { + {0, 5}, + {11, 10}, + {27, 10}, + {43, 10}, + {59, 5} + } +}; + +/* Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. */ +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr smallpage_memorybased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 5, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern +}; + +/* Generic flash bbt decriptors */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/** + * memcpy variant that copies 32 bit words. This is needed since the + * NFC only allows 32 bit accesses. Added for U-boot. + */ +static void *memcpy_32(void *dest, const void *src, size_t n) +{ + u32 *dst_32 = (u32 *) dest; + const u32 *src_32 = (u32 *) src; + + while (n > 0) { + *dst_32++ = *src_32++; + n -= 4; + } + + return dest; +} + +/** + * This function polls the NANDFC to wait for the basic operation to + * complete by checking the INT bit of config2 register. + * + * @param max_retries number of retry attempts (separated by 1 us) + */ +static void wait_op_done(int max_retries) +{ + while (max_retries-- > 0) { + if (NFC_CONFIG2 & NFC_INT) { + NFC_CONFIG2 &= ~NFC_INT; + break; + } + udelay(1); + } + if (max_retries <= 0) + DEBUG(MTD_DEBUG_LEVEL0, "wait: INT not set\n"); +} + +/** + * This function issues the specified command to the NAND device and + * waits for completion. + * + * @param cmd command for NAND Flash + */ +static void send_cmd(u16 cmd) +{ + DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(0x%x)\n", cmd); + + NFC_FLASH_CMD = (u16) cmd; + NFC_CONFIG2 = NFC_CMD; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); +} + +/** + * This function sends an address (or partial address) to the + * NAND device. The address is used to select the source/destination for + * a NAND command. + * + * @param addr address to be written to NFC. + * @param islast 1 if this is the last address cycle for command + */ +static void send_addr(u16 addr) +{ + DEBUG(MTD_DEBUG_LEVEL3, "send_addr(0x%x %d)\n", addr); + + NFC_FLASH_ADDR = addr; + NFC_CONFIG2 = NFC_ADDR; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); +} + +/** + * This function requests the NANDFC to initate the transfer + * of data currently in the NANDFC RAM buffer to the NAND device. + * + * @param buf_id Specify Internal RAM Buffer number (0-3) + * @param oob set to 1 if only the spare area is transferred + */ +static void send_prog_page(u8 buf_id) +{ + DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", nandinfo.oob); + + /* NANDFC buffer 0 is used for page read/write */ + + NFC_BUF_ADDR = buf_id; + + /* Configure spare or page+spare access */ + if (!nandinfo.largepage) { + if (nandinfo.oob) + NFC_CONFIG1 |= NFC_SP_EN; + else + NFC_CONFIG1 &= ~NFC_SP_EN; + } + NFC_CONFIG2 = NFC_INPUT; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); +} + +/** + * This function will correct the single bit ECC error + * + * @param buf_id Specify Internal RAM Buffer number (0-3) + * @param eccpos Ecc byte and bit position + * @param oob set to 1 if only spare area needs correction + */ +static void mxc_nd_correct_error(u8 buf_id, u16 eccpos, int oob) +{ + u16 col; + u8 pos; + u16 *buf; + + /* Get col & bit position of error + these macros works for both 8 & 16 bits */ + col = COLPOS(eccpos); /* Get half-word position */ + pos = BITPOS(eccpos); /* Get bit position */ + + DEBUG(MTD_DEBUG_LEVEL3, + "mxc_nd_correct_error (col=%d pos=%d)\n", col, pos); + + /* Set the pointer for main / spare area */ + if (!oob) + buf = (u16 *)(MAIN_AREA0 + col + (256 * buf_id)); + else + buf = (u16 *)(SPARE_AREA0 + col + (8 * buf_id)); + + /* Fix the data */ + *buf ^= 1 << pos; +} + +/** + * This function will maintains state of single bit Error + * in Main & spare area + * + * @param buf_id Specify Internal RAM Buffer number (0-3) + * @param spare set to 1 if only spare area needs correction + */ +static void mxc_nd_correct_ecc(u8 buf_id, int spare) +{ + u16 value, ecc_status; + + /* Read the ECC result */ + ecc_status = NFC_ECC_STATUS_RESULT; + DEBUG(MTD_DEBUG_LEVEL3, + "mxc_nd_correct_ecc (Ecc status=%x)\n", ecc_status); + + if (((ecc_status & 0xC) == MAIN_SINGLEBIT_ERROR) + || ((ecc_status & 0x3) == SPARE_SINGLEBIT_ERROR)) { + if (ecc_disabled) { + if ((ecc_status & 0xC) == MAIN_SINGLEBIT_ERROR) { + value = NFC_RSLTMAIN_AREA; + /* Correct single bit error in Mainarea + NFC will not correct the error in + current page */ + mxc_nd_correct_error(buf_id, value, 0); + } + if ((ecc_status & 0x3) == SPARE_SINGLEBIT_ERROR) { + value = NFC_RSLTSPARE_AREA; + /* Correct single bit error in Mainarea + NFC will not correct the error in + current page */ + mxc_nd_correct_error(buf_id, value, 1); + } + + } else { + /* Disable ECC */ + NFC_CONFIG1 &= ~NFC_ECC_EN; + ecc_disabled = 1; + } + } else if (ecc_status == 0) { + if (ecc_disabled) { + /* Enable ECC */ + NFC_CONFIG1 |= NFC_ECC_EN; + ecc_disabled = 0; + } + } /* else 2-bit Error. Do nothing */ +} + +/** + * This function requests the NANDFC to initated the transfer + * of data from the NAND device into in the NANDFC ram buffer. + * + * @param buf_id Specify Internal RAM Buffer number (0-3) + * @param oob set 1 if only the spare area is + * transferred + */ +static void send_read_page(u8 buf_id) +{ + DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", nandinfo.oob); + + /* NANDFC buffer 0 is used for page read/write */ + NFC_BUF_ADDR = buf_id; + + /* Configure spare or page+spare access */ + if (!nandinfo.largepage) { + if (nandinfo.oob) + NFC_CONFIG1 |= NFC_SP_EN; + else + NFC_CONFIG1 &= ~NFC_SP_EN; + } + + NFC_CONFIG2 = NFC_OUTPUT; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); + + /* If there are single bit errors in + two consecutive page reads then + the error is not corrected by the + NFC for the second page. + Correct single bit error in driver */ + + mxc_nd_correct_ecc(buf_id, nandinfo.oob); +} + +/** + * This function requests the NANDFC to perform a read of the + * NAND device ID. + */ +static void send_read_id(void) +{ + /* NANDFC buffer 0 is used for device ID output */ + NFC_BUF_ADDR = 0x0; + + /* Read ID into main buffer */ + NFC_CONFIG1 &= ~NFC_SP_EN; + NFC_CONFIG2 = NFC_ID; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); +} + +/** + * This function requests the NANDFC to perform a read of the + * NAND device status and returns the current status. + * + * @return device status + */ +static u16 get_dev_status(void) +{ + volatile u16 *mainbuf = MAIN_AREA1; + u32 store; + u16 ret; + /* Issue status request to NAND device */ + + /* store the main area1 first word, later do recovery */ + store = *((u32 *) mainbuf); + /* + * NANDFC buffer 1 is used for device status to prevent + * corruption of read/write buffer on status requests. + */ + NFC_BUF_ADDR = 1; + + /* Read status into main buffer */ + NFC_CONFIG1 &= ~NFC_SP_EN; + NFC_CONFIG2 = NFC_STATUS; + + /* Wait for operation to complete */ + wait_op_done(TROP_US_DELAY); + + /* Status is placed in first word of main buffer */ + /* get status, then recovery area 1 data */ + ret = mainbuf[0]; + *((u32 *) mainbuf) = store; + + return ret; +} + +static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + /* + * If HW ECC is enabled, we turn it on during init. There is + * no need to enable again here. + */ +} + +static int mxc_nand_correct_data(struct mtd_info *mtd, unsigned char *dat, + unsigned char *read_ecc, unsigned char *calc_ecc) +{ + /* + * 1-Bit errors are automatically corrected in HW. No need for + * additional correction. 2-Bit errors cannot be corrected by + * HW ECC, so we need to return failure + */ + u16 ecc_status = NFC_ECC_STATUS_RESULT; + + if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { + DEBUG(MTD_DEBUG_LEVEL0, + "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + return -1; + } + + return 0; +} + +static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *dat, + unsigned char *ecc_code) +{ + /* + * Just return success. HW ECC does not read/write the NFC spare + * buffer. Only the FLASH spare area contains the calcuated ECC. + */ + return 0; +} + +/** + * This function reads byte from the NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * + * @return data read from the NAND Flash + */ +static unsigned char mxc_nand_read_byte(struct mtd_info *mtd) +{ + unsigned char ret_val = 0; + u16 col, rd_word; + volatile u16 *mainbuf = MAIN_AREA0; + volatile u16 *sparebuf = SPARE_AREA0; + + /* Check for status request */ + if (nandinfo.read_status) + return get_dev_status() & 0xFF; + + /* Get column for 16-bit access */ + col = nandinfo.col >> 1; + + /* If we are accessing the spare region */ + if (nandinfo.oob) + rd_word = sparebuf[col]; + else + rd_word = mainbuf[col]; + + /* Pick upper/lower byte of word from RAM buffer */ + if (nandinfo.col & 0x1) + ret_val = (rd_word >> 8) & 0xFF; + else + ret_val = rd_word & 0xFF; + + /* Update saved column address */ + nandinfo.col++; + + return ret_val; +} + +/** + * This function reads word from the NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * + * @return data read from the NAND Flash + */ +static u16 mxc_nand_read_word(struct mtd_info *mtd) +{ + u16 col; + u16 rd_word, ret_val; + volatile u16 *p; + + DEBUG(MTD_DEBUG_LEVEL3, "mxc_nand_read_word(col = %d)\n", nandinfo.col); + + col = nandinfo.col; + /* Adjust saved column address */ + if (col < mtd->oobblock && nandinfo.oob) + col += mtd->oobblock; + + if (col < mtd->oobblock) + p = (MAIN_AREA0) + (col >> 1); + else + p = (SPARE_AREA0) + ((col - mtd->oobblock) >> 1); + + if (col & 1) { + rd_word = *p; + ret_val = (rd_word >> 8) & 0xff; + rd_word = *(p + 1); + ret_val |= (rd_word << 8) & 0xff00; + + } else + ret_val = *p; + + /* Update saved column address */ + nandinfo.col = col + 2; + + return ret_val; +} + +/** + * This function writes data of length \b len to buffer \b buf. The data + * to be written on NAND Flash is first copied to RAMbuffer. After the + * Data Input Operation by the NFC, the data is written to NAND Flash. + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be written to NAND Flash + * @param len number of bytes to be written + */ +static void mxc_nand_write_buf(struct mtd_info *mtd, + const unsigned char *buf, int len) +{ + int n; + int col; + int i = 0; + + DEBUG(MTD_DEBUG_LEVEL3, + "mxc_nand_write_buf(col = %d, len = %d)\n", nandinfo.col, len); + + col = nandinfo.col; + + /* Adjust saved column address */ + if (col < mtd->oobblock && nandinfo.oob) + col += mtd->oobblock; + + n = mtd->oobblock + mtd->oobsize - col; + if (len > mtd->oobblock + mtd->oobsize - col) + DEBUG(MTD_DEBUG_LEVEL1, "Error: too much data.\n"); + + n = min(len, n); + + DEBUG(MTD_DEBUG_LEVEL3, + "%s:%d: col = %d, n = %d\n", __FUNCTION__, __LINE__, col, n); + + while (n) { + volatile u32 *p; + if (col < mtd->oobblock) + p = (volatile u32 *)((ulong) (MAIN_AREA0) + (col & ~3)); + else + p = (volatile u32 *)((ulong) (SPARE_AREA0) - + mtd->oobblock + (col & ~3)); + + DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", + __FUNCTION__, __LINE__, p); + + if (((col | (int)&buf[i]) & 3) || n < 16) { + u32 data = 0; + + if (col & 3 || n < 4) + data = *p; + + switch (col & 3) { + case 0: + if (n) { + data = (data & 0xffffff00) | + (buf[i++] << 0); + n--; + col++; + } + case 1: + if (n) { + data = (data & 0xffff00ff) | + (buf[i++] << 8); + n--; + col++; + } + case 2: + if (n) { + data = (data & 0xff00ffff) | + (buf[i++] << 16); + n--; + col++; + } + case 3: + if (n) { + data = (data & 0x00ffffff) | + (buf[i++] << 24); + n--; + col++; + } + } + + *p = data; + } else { + int m = mtd->oobblock - col; + + if (col >= mtd->oobblock) + m += mtd->oobsize; + + m = min(n, m) & ~3; + + DEBUG(MTD_DEBUG_LEVEL3, + "%s:%d: n = %d, m = %d, i = %d, col = %d\n", + __FUNCTION__, __LINE__, n, m, i, col); + + memcpy_32((void *)(p), &buf[i], m); + col += m; + i += m; + n -= m; + } + } + /* Update saved column address */ + nandinfo.col = col; +} + +/** + * This function id is used to read the data buffer from the NAND Flash. To + * read the data from NAND Flash first the data output cycle is initiated by + * the NFC, which copies the data to RAMbuffer. This data of length \b len is + * then copied to buffer \b buf. + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be read from NAND Flash + * @param len number of bytes to be read + */ +static void mxc_nand_read_buf(struct mtd_info *mtd, unsigned char *buf, int len) +{ + int n; + int col; + int i = 0; + + DEBUG(MTD_DEBUG_LEVEL3, + "mxc_nand_read_buf(col = %d, len = %d)\n", nandinfo.col, len); + + col = nandinfo.col; + /** + * Adjust saved column address + * for nand_read_oob will pass col within oobsize + */ + if (col < mtd->oobblock && nandinfo.oob) + col += mtd->oobblock; + + n = mtd->oobblock + mtd->oobsize - col; + n = min(len, n); + + while (n) { + volatile u32 *p; + + if (col < mtd->oobblock) + p = (volatile u32 *)((ulong) (MAIN_AREA0) + (col & ~3)); + else + p = (volatile u32 *)((ulong) (SPARE_AREA0) - + mtd->oobblock + (col & ~3)); + + if (((col | (int)&buf[i]) & 3) || n < 16) { + u32 data; + + data = *p; + switch (col & 3) { + case 0: + if (n) { + buf[i++] = (u8) (data); + n--; + col++; + } + case 1: + if (n) { + buf[i++] = (u8) (data >> 8); + n--; + col++; + } + case 2: + if (n) { + buf[i++] = (u8) (data >> 16); + n--; + col++; + } + case 3: + if (n) { + buf[i++] = (u8) (data >> 24); + n--; + col++; + } + } + } else { + int m = mtd->oobblock - col; + + if (col >= mtd->oobblock) + m += mtd->oobsize; + + m = min(n, m) & ~3; + memcpy_32(&buf[i], (void *)(p), m); + col += m; + i += m; + n -= m; + } + } + /* Update saved column address */ + nandinfo.col = col; +} + +/** + * This function is used by the upper layer to verify the data in NAND Flash + * with the data in the \b buf. + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be verified + * @param len length of the data to be verified + * + * @return -EFAULT if error else 0 + */ +static int +mxc_nand_verify_buf(struct mtd_info *mtd, const unsigned char *buf, int len) +{ + return -1; /* Was -EFAULT */ +} + +/** + * This function is used by upper layer for select and deselect of the NAND + * chip. + * + * @param mtd MTD structure for the NAND Flash + * @param chip val indicating select or deselect + */ +static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) +{ +} + +/** + * This function is used by the upper layer to write command to NAND Flash + * for different operations to be carried out on NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * @param command command for NAND Flash + * @param column column offset for the page read + * @param page_addr page to be read from NAND Flash + */ +static void mxc_nand_command(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + DEBUG(MTD_DEBUG_LEVEL3, + "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + command, column, page_addr); + + /* Reset command state information */ + nandinfo.read_status = 0; + nandinfo.oob = 0; + + /* Command pre-processing step */ + switch (command) { + + case NAND_CMD_STATUS: + nandinfo.col = 0; + nandinfo.read_status = 1; + break; + + case NAND_CMD_READ0: + nandinfo.col = column; + break; + + case NAND_CMD_READOOB: + nandinfo.col = column; + nandinfo.oob = 1; + if (nandinfo.largepage) + command = NAND_CMD_READ0; + break; + + case NAND_CMD_SEQIN: + if (column >= mtd->oobblock) { + /* write oob routine caller */ + if (nandinfo.largepage) { + /* + * FIXME: before send SEQIN command for + * write OOB, we must read one page out. + * For 2K nand has no READ1 command to set + * current HW pointer to spare area, we must + * write the whole page including OOB together. + */ + /* call itself to read a page */ + mxc_nand_command(mtd, NAND_CMD_READ0, 0, + page_addr); + } + nandinfo.col = column - mtd->oobblock; + nandinfo.oob = 1; + /* Set program pointer to spare region */ + if (!nandinfo.largepage) + send_cmd(NAND_CMD_READOOB); + } else { + nandinfo.oob = 0; + nandinfo.col = column; + /* Set program pointer to page start */ + if (!nandinfo.largepage) + send_cmd(NAND_CMD_READ0); + } + break; + + case NAND_CMD_PAGEPROG: + if (ecc_disabled) { + /* Enable Ecc for page writes */ + NFC_CONFIG1 |= NFC_ECC_EN; + } + send_prog_page(0); + + if (nandinfo.largepage) { + /* data in 4 areas datas */ + send_prog_page(1); + send_prog_page(2); + send_prog_page(3); + } + + break; + + case NAND_CMD_ERASE1: + break; + } + + /* + * Write out the command to the device. + */ + send_cmd(command); + + /* + * Write out column address, if necessary + */ + if (column != -1) { + /* + * MXC NANDFC can only perform full page+spare or + * spare-only read/write. When the upper layers + * layers perform a read/write buf operation, + * we will used the saved column adress to index into + * the full page. + */ + send_addr(0); + if (nandinfo.largepage) + /* another col addr cycle for 2k page */ + send_addr(0); + } + + /* + * Write out page address, if necessary + */ + if (page_addr != -1) { + /* paddr_0 - p_addr_7 */ + send_addr((page_addr & 0xff)); + + if (nandinfo.largepage) { + /* One more address cycle for higher + * density devices */ + + if (mtd->size >= 0x10000000) { + /* paddr_8 - paddr_15 */ + send_addr((page_addr >> 8) & 0xff); + send_addr((page_addr >> 16) & 0xff); + } else + /* paddr_8 - paddr_15 */ + send_addr((page_addr >> 8) & 0xff); + } else { + /* One more address cycle for higher + * density devices */ + + if (mtd->size >= 0x4000000) { + /* paddr_8 - paddr_15 */ + send_addr((page_addr >> 8) & 0xff); + send_addr((page_addr >> 16) & 0xff); + } else + /* paddr_8 - paddr_15 */ + send_addr((page_addr >> 8) & 0xff); + } + } + + /* + * Command post-processing step + */ + switch (command) { + + case NAND_CMD_RESET: + break; + + case NAND_CMD_READOOB: + case NAND_CMD_READ0: + if (nandinfo.largepage) { + /* send read confirm command */ + send_cmd(NAND_CMD_READSTART); + /* read for each AREA */ + send_read_page(0); + send_read_page(1); + send_read_page(2); + send_read_page(3); + } else + send_read_page(0); + break; + + case NAND_CMD_READID: + send_read_id(); + break; + + case NAND_CMD_PAGEPROG: + if (ecc_disabled) { + /* Disable Ecc after page writes */ + NFC_CONFIG1 &= ~NFC_ECC_EN; + } + break; + + case NAND_CMD_ERASE2: + break; + } +} + +static int mxc_nand_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + /* Config before scanning */ + /* Do not rely on NFMS_BIT, set/clear NFMS bit based + * on mtd->oobblock */ + if (mtd->oobblock == 2048) + NFMS |= 1 << NFMS_BIT; + else if ((NFMS >> NFMS_BIT) & 0x1) + NFMS &= ~(1 << NFMS_BIT); + + /* use flash based bbt */ + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + + /* update flash based bbt */ + this->options |= NAND_USE_FLASH_BBT; + + if (!this->badblock_pattern) { + if (nandinfo.largepage) + this->badblock_pattern = &smallpage_memorybased; + else + this->badblock_pattern = (mtd->oobblock > 512) ? + &largepage_memorybased : &smallpage_memorybased; + } + /* Build bad block table */ + return nand_scan_bbt(mtd, this->badblock_pattern); +} + +int board_nand_init(struct nand_chip *nand) +{ + nand->chip_delay = 0; + + nand->cmdfunc = mxc_nand_command; + nand->select_chip = mxc_nand_select_chip; + nand->read_byte = mxc_nand_read_byte; + nand->read_word = mxc_nand_read_word; + nand->write_buf = mxc_nand_write_buf; + nand->read_buf = mxc_nand_read_buf; + nand->verify_buf = mxc_nand_verify_buf; + nand->scan_bbt = mxc_nand_scan_bbt; + nand->calculate_ecc = mxc_nand_calculate_ecc; + nand->correct_data = mxc_nand_correct_data; + nand->enable_hwecc = mxc_nand_enable_hwecc; + nand->eccmode = NAND_ECC_HW3_512; + nand->eccbytes = 512; + nand->eccsize = 3; + + /* Reset NAND */ + NFC_CONFIG1 |= NFC_INT_MSK | NFC_RST | NFC_ECC_EN; + + /* Unlock the internal RAM buffer */ + NFC_CONFIG = 0x2; + + /* Block to be unlocked */ + NFC_UNLOCKSTART_BLKADDR = 0x0; + NFC_UNLOCKEND_BLKADDR = 0x4000; + + /* Unlock Block Command for given address range */ + NFC_WRPROT = 0x4; + + /* Only 8 bit bus support for now */ + nand->options |= 0; + + if ((NFMS >> NFMS_BIT) & 1) { + nandinfo.largepage = 1; + nand->autooob = &nand_hw_eccoob_2k; + } else { + nandinfo.largepage = 0; + nand->autooob = &nand_hw_eccoob_8; + } + + return 0; +} diff --git a/include/asm-arm/arch-mx31/mx31-regs.h b/include/asm-arm/arch-mx31/mx31-regs.h index 51b02a2..a8b7c10 100644 --- a/include/asm-arm/arch-mx31/mx31-regs.h +++ b/include/asm-arm/arch-mx31/mx31-regs.h @@ -255,4 +255,100 @@ */ #define NFC_BASE_ADDR 0xB8000000 +/* + * Addresses for NFC registers + */ +#define NFC_BUF_SIZE (*((volatile u16 *)(NFC_BASE_ADDR + 0xE00))) +#define NFC_BUF_ADDR (*((volatile u16 *)(NFC_BASE_ADDR + 0xE04))) +#define NFC_FLASH_ADDR (*((volatile u16 *)(NFC_BASE_ADDR + 0xE06))) +#define NFC_FLASH_CMD (*((volatile u16 *)(NFC_BASE_ADDR + 0xE08))) +#define NFC_CONFIG (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0A))) +#define NFC_ECC_STATUS_RESULT (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0C))) +#define NFC_RSLTMAIN_AREA (*((volatile u16 *)(NFC_BASE_ADDR + 0xE0E))) +#define NFC_RSLTSPARE_AREA (*((volatile u16 *)(NFC_BASE_ADDR + 0xE10))) +#define NFC_WRPROT (*((volatile u16 *)(NFC_BASE_ADDR + 0xE12))) +#define NFC_UNLOCKSTART_BLKADDR (*((volatile u16 *)(NFC_BASE_ADDR + 0xE14))) +#define NFC_UNLOCKEND_BLKADDR (*((volatile u16 *)(NFC_BASE_ADDR + 0xE16))) +#define NFC_NF_WRPRST (*((volatile u16 *)(NFC_BASE_ADDR + 0xE18))) +#define NFC_CONFIG1 (*((volatile u16 *)(NFC_BASE_ADDR + 0xE1A))) +#define NFC_CONFIG2 (*((volatile u16 *)(NFC_BASE_ADDR + 0xE1C))) + +#define NFC_BUFSIZE_REG_OFF (0 + 0x00) +#define RAM_BUFFER_ADDRESS_REG_OFF (0 + 0x04) +#define NAND_FLASH_ADD_REG_OFF (0 + 0x06) +#define NAND_FLASH_CMD_REG_OFF (0 + 0x08) +#define NFC_CONFIGURATION_REG_OFF (0 + 0x0A) +#define ECC_STATUS_RESULT_REG_OFF (0 + 0x0C) +#define ECC_RSLT_MAIN_AREA_REG_OFF (0 + 0x0E) +#define ECC_RSLT_SPARE_AREA_REG_OFF (0 + 0x10) +#define NF_WR_PROT_REG_OFF (0 + 0x12) +#define UNLOCK_START_BLK_ADD_REG_OFF (0 + 0x14) +#define UNLOCK_END_BLK_ADD_REG_OFF (0 + 0x16) +#define NAND_FLASH_WR_PR_ST_REG_OFF (0 + 0x18) +#define NAND_FLASH_CONFIG1_REG_OFF (0 + 0x1A) +#define NAND_FLASH_CONFIG2_REG_OFF (0 + 0x1C) +#define RAM_BUFFER_ADDRESS_RBA_3 0x3 +#define NFC_BUFSIZE_1KB 0x0 +#define NFC_BUFSIZE_2KB 0x1 +#define NFC_CONFIGURATION_UNLOCKED 0x2 +#define ECC_STATUS_RESULT_NO_ERR 0x0 +#define ECC_STATUS_RESULT_1BIT_ERR 0x1 +#define ECC_STATUS_RESULT_2BIT_ERR 0x2 +#define NF_WR_PROT_UNLOCK 0x4 +#define NAND_FLASH_CONFIG1_FORCE_CE (1 << 7) +#define NAND_FLASH_CONFIG1_RST (1 << 6) +#define NAND_FLASH_CONFIG1_BIG (1 << 5) +#define NAND_FLASH_CONFIG1_INT_MSK (1 << 4) +#define NAND_FLASH_CONFIG1_ECC_EN (1 << 3) +#define NAND_FLASH_CONFIG1_SP_EN (1 << 2) +#define NAND_FLASH_CONFIG2_INT_DONE (1 << 15) +#define NAND_FLASH_CONFIG2_FDO_PAGE (0 << 3) +#define NAND_FLASH_CONFIG2_FDO_ID (2 << 3) +#define NAND_FLASH_CONFIG2_FDO_STATUS (4 << 3) +#define NAND_FLASH_CONFIG2_FDI_EN (1 << 2) +#define NAND_FLASH_CONFIG2_FADD_EN (1 << 1) +#define NAND_FLASH_CONFIG2_FCMD_EN (1 << 0) +#define FDO_PAGE_SPARE_VAL 0x8 +#define NAND_FLASH_BOOT 0x10000000 +#define MXCFIS_NAND 0x10000000 + +/* + * Addresses for NFC RAM BUFFER Main area 0 + */ +#define MAIN_AREA0 (volatile u16 *)(NFC_BASE_ADDR + 0x000) +#define MAIN_AREA1 (volatile u16 *)(NFC_BASE_ADDR + 0x200) +#define MAIN_AREA2 (volatile u16 *)(NFC_BASE_ADDR + 0x400) +#define MAIN_AREA3 (volatile u16 *)(NFC_BASE_ADDR + 0x600) + +/* + * Addresses for NFC SPARE BUFFER Spare area 0 + */ +#define SPARE_AREA0 (volatile u16 *)(NFC_BASE_ADDR + 0x800) +#define SPARE_AREA1 (volatile u16 *)(NFC_BASE_ADDR + 0x810) +#define SPARE_AREA2 (volatile u16 *)(NFC_BASE_ADDR + 0x820) +#define SPARE_AREA3 (volatile u16 *)(NFC_BASE_ADDR + 0x830) + +#define NFC_CMD 0x1 +#define NFC_ADDR 0x2 +#define NFC_INPUT 0x4 +#define NFC_OUTPUT 0x8 +#define NFC_ID 0x10 +#define NFC_STATUS 0x20 +#define NFC_INT 0x8000 + +#define NFC_SP_EN (1 << 2) +#define NFC_ECC_EN (1 << 3) +#define NFC_INT_MSK (1 << 4) +#define NFC_BIG (1 << 5) +#define NFC_RST (1 << 6) +#define NFC_CE (1 << 7) +#define NFC_ONE_CYCLE (1 << 8) + +/* + * NFMS bit in RCSR register for pagesize of nandflash + */ +#define NFMS (*((volatile u32 *)CCM_RCSR)) +#define NFMS_BIT 30 + #endif /* __ASM_ARCH_MX31_REGS_H */ + diff --git a/include/configs/mx31_3stack.h b/include/configs/mx31_3stack.h new file mode 100644 index 0000000..7aaef4f --- /dev/null +++ b/include/configs/mx31_3stack.h @@ -0,0 +1,165 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Configuration settings for the MX31 3Stack Freescale board. + * + * 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 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <asm/arch/mx31-regs.h> + + /* High Level Configuration Options */ +#define CONFIG_ARM1136 1 /* This is an arm1136 CPU core */ +#define CONFIG_MX31 1 /* in a mx31 */ +#define CONFIG_MX31_HCLK_FREQ 26000000 +#define CONFIG_MX31_CLK32 32768 + +#define CONFIG_MX31_NAND + +#define CONFIG_DISPLAY_CPUINFO +#define CONFIG_DISPLAY_BOARDINFO + +#define CONFIG_NAND_BOOT +#define CONFIG_SKIP_RELOCATE_UBOOT + +#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ +#define CONFIG_SETUP_MEMORY_TAGS 1 +#define CONFIG_INITRD_TAG 1 + +/* + * Size of malloc() pool + */ +#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128 * 1024) +#define CFG_GBL_DATA_SIZE 128 + +/* + * Hardware drivers + */ + +#define CONFIG_MX31_UART 1 +#define CFG_MX31_UART1 1 + +#define CONFIG_HARD_SPI 1 +#define CONFIG_MXC_SPI 1 +#define CONFIG_MXC_SPI_IFACE 1 + +#define CONFIG_RTC_MC13783 1 + +/* allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE +#define CONFIG_CONS_INDEX 1 +#define CONFIG_BAUDRATE 115200 +#define CFG_BAUDRATE_TABLE {9600, 19200, 38400, 57600, 115200} + +/*********************************************************** + * Command definition + ***********************************************************/ + +#include <config_cmd_default.h> + +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_SPI +#define CONFIG_CMD_DATE +#define CONFIG_CMD_NAND +#undef CONFIG_CMD_IMLS + +#define CONFIG_BOOTDELAY 3 + +#define CONFIG_LOADADDR 0x80800000 /* loadaddr env var */ + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth0\0" \ + "uboot=u-boot.bin\0" \ + "kernel=uImage\0" \ + "loadaddr=0x80010000\0" \ + "tftp_server=10.192.225.58\0" \ + "serverip=10.192.225.211\0" \ + "nfsroot=/tools/rootfs/rootfs-2.6.24\0" \ + "bootargs_base=setenv bootargs console=ttymxc0,115200\0" \ + "bootargs_nfs=setenv bootargs ${bootargs} root=/dev/nfs " \ + "ip=dhcp nfsroot=${serverip}:${nfsroot} rw\0" \ + "bootcmd=run bootcmd_net\0" \ + "bootcmd_net=run bootargs_base bootargs_nfs; " \ + "tftpboot ${loadaddr} ${tftp_server}:${kernel}; bootm\0" + +/* configure for smc91xx debug board ethernet */ +#define CONFIG_NET_MULTI 1 +#define CONFIG_DRIVER_SMC911X 1 +#define CONFIG_DRIVER_SMC911X_BASE CS5_BASE +#define CONFIG_DRIVER_SMC911X_32_BIT 1 + +#define CONFIG_ARP_TIMEOUT 200UL + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_PROMPT "=> " +#define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +/* Print Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE + sizeof(CFG_PROMPT) + 16) +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ + +#define CFG_MEMTEST_START 0 /* memtest works on */ +#define CFG_MEMTEST_END 0x10000 + +#undef CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */ + +#define CFG_LOAD_ADDR CONFIG_LOADADDR + +#define CFG_HZ CONFIG_MX31_CLK32 + +#define CONFIG_CMDLINE_EDITING 1 + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE (128 * 1024) /* regular stack */ + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 1 +#define PHYS_SDRAM_1 CSD0_BASE +#define PHYS_SDRAM_1_SIZE (128 * 1024 * 1024) + +/* + * TODO: NAND Flash configure + */ + +#define CFG_NO_FLASH +#define NAND_MAX_CHIPS 1 +#define CFG_MAX_NAND_DEVICE 1 +#define CFG_NAND_BASE 0x40000000 + +#define CFG_ENV_IS_IN_NAND 1 +#define CFG_ENV_OFFSET 0x40000 /* 2nd block */ +#define CFG_ENV_SIZE (128*1024) + +/* + * JFFS2 partitions TODO: + */ +#undef CONFIG_JFFS2_CMDLINE +#define CONFIG_JFFS2_DEV "nand0" + +#endif /* __CONFIG_H */ |