diff options
Diffstat (limited to 'arch/cris/arch-v32/lib/nand_init.S')
-rw-r--r-- | arch/cris/arch-v32/lib/nand_init.S | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/lib/nand_init.S b/arch/cris/arch-v32/lib/nand_init.S new file mode 100644 index 000000000000..aba5c751c282 --- /dev/null +++ b/arch/cris/arch-v32/lib/nand_init.S @@ -0,0 +1,179 @@ +##============================================================================= +## +## nand_init.S +## +## The bootrom copies data from the NAND flash to the internal RAM but +## due to a bug/feature we can only trust the 256 first bytes. So this +## code copies more data from NAND flash to internal RAM. Obvioulsy this +## code must fit in the first 256 bytes so alter with care. +## +## Some notes about the bug/feature for future reference: +## The bootrom copies the first 127 KB from NAND flash to internal +## memory. The problem is that it does a bytewise copy. NAND flashes +## does autoincrement on the address so for a 16-bite device each +## read/write increases the address by two. So the copy loop in the +## bootrom will discard every second byte. This is solved by inserting +## zeroes in every second byte in the first erase block. +## +## The bootrom also incorrectly assumes that it can read the flash +## linear with only one read command but the flash will actually +## switch between normal area and spare area if you do that so we +## can't trust more than the first 256 bytes. +## +##============================================================================= + +#include <asm/arch/hwregs/asm/reg_map_asm.h> +#include <asm/arch/hwregs/asm/gio_defs_asm.h> +#include <asm/arch/hwregs/asm/pinmux_defs_asm.h> +#include <asm/arch/hwregs/asm/bif_core_defs_asm.h> +#include <asm/arch/hwregs/asm/config_defs_asm.h> +#include <linux/config.h> + +;; There are 8-bit NAND flashes and 16-bit NAND flashes. +;; We need to treat them slightly different. +#if CONFIG_ETRAX_FLASH_BUSWIDTH==2 +#define PAGE_SIZE 256 +#else +#error 2 +#define PAGE_SIZE 512 +#endif +#define ERASE_BLOCK 16384 + +;; GPIO pins connected to NAND flash +#define CE 4 +#define CLE 5 +#define ALE 6 +#define BY 7 + +;; Address space for NAND flash +#define NAND_RD_ADDR 0x90000000 +#define NAND_WR_ADDR 0x94000000 + +#define READ_CMD 0x00 + +;; Readability macros +#define CSP_MASK \ + REG_MASK(bif_core, rw_grp3_cfg, gated_csp0) | \ + REG_MASK(bif_core, rw_grp3_cfg, gated_csp1) +#define CSP_VAL \ + REG_STATE(bif_core, rw_grp3_cfg, gated_csp0, rd) | \ + REG_STATE(bif_core, rw_grp3_cfg, gated_csp1, wr) + +;;---------------------------------------------------------------------------- +;; Macros to set/clear GPIO bits + +.macro SET x + or.b (1<<\x),$r9 + move.d $r9, [$r2] +.endm + +.macro CLR x + and.b ~(1<<\x),$r9 + move.d $r9, [$r2] +.endm + +;;---------------------------------------------------------------------------- + +nand_boot: + ;; Check if nand boot was selected + move.d REG_ADDR(config, regi_config, r_bootsel), $r0 + move.d [$r0], $r0 + and.d REG_MASK(config, r_bootsel, boot_mode), $r0 + cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 + bne normal_boot ; No NAND boot + nop + +copy_nand_to_ram: + ;; copy_nand_to_ram + ;; Arguments + ;; r10 - destination + ;; r11 - source offset + ;; r12 - size + ;; r13 - Address to jump to after completion + ;; Note : r10-r12 are clobbered on return + ;; Registers used: + ;; r0 - NAND_RD_ADDR + ;; r1 - NAND_WR_ADDR + ;; r2 - reg_gio_rw_pa_dout + ;; r3 - reg_gio_r_pa_din + ;; r4 - tmp + ;; r5 - byte counter within a page + ;; r6 - reg_pinmux_rw_pa + ;; r7 - reg_gio_rw_pa_oe + ;; r8 - reg_bif_core_rw_grp3_cfg + ;; r9 - reg_gio_rw_pa_dout shadow + move.d 0x90000000, $r0 + move.d 0x94000000, $r1 + move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r2 + move.d REG_ADDR(gio, regi_gio, r_pa_din), $r3 + move.d REG_ADDR(pinmux, regi_pinmux, rw_pa), $r6 + move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r7 + move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r8 + +#if CONFIG_ETRAX_FLASH_BUSWIDTH==2 + lsrq 1, $r11 +#endif + ;; Set up GPIO + move.d [$r2], $r9 + move.d [$r7], $r4 + or.b (1<<ALE) | (1 << CLE) | (1<<CE), $r4 + move.d $r4, [$r7] + + ;; Set up bif + move.d [$r8], $r4 + and.d CSP_MASK, $r4 + or.d CSP_VAL, $r4 + move.d $r4, [$r8] + +1: ;; Copy one page + CLR CE + SET CLE + moveq READ_CMD, $r4 + move.b $r4, [$r1] + moveq 20, $r4 +2: bne 2b + subq 1, $r4 + CLR CLE + SET ALE + clear.w [$r1] ; Column address = 0 + move.d $r11, $r4 + lsrq 8, $r4 + move.b $r4, [$r1] ; Row address + lsrq 8, $r4 + move.b $r4, [$r1] ; Row adddress + moveq 20, $r4 +2: bne 2b + subq 1, $r4 + CLR ALE +2: move.d [$r3], $r4 + and.d 1 << BY, $r4 + beq 2b + movu.w PAGE_SIZE, $r5 +2: ; Copy one byte/word +#if CONFIG_ETRAX_FLASH_BUSWIDTH==2 + move.w [$r0], $r4 +#else + move.b [$r0], $r4 +#endif + subq 1, $r5 + bne 2b +#if CONFIG_ETRAX_FLASH_BUSWIDTH==2 + move.w $r4, [$r10+] + subu.w PAGE_SIZE*2, $r12 +#else + move.b $r4, [$r10+] + subu.w PAGE_SIZE, $r12 +#endif + bpl 1b + addu.w PAGE_SIZE, $r11 + + ;; End of copy + jump $r13 + nop + + ;; This will warn if the code above is too large. If you consider + ;; to remove this you don't understand the bug/feature. + .org 256 + .org ERASE_BLOCK + +normal_boot: |