original_kernel/arch/cris/arch-v32/lib/nand_init.S

179 lines
4.6 KiB
ArmAsm

##=============================================================================
##
## 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 <arch/hwregs/asm/reg_map_asm.h>
#include <arch/hwregs/asm/gio_defs_asm.h>
#include <arch/hwregs/asm/pinmux_defs_asm.h>
#include <arch/hwregs/asm/bif_core_defs_asm.h>
#include <arch/hwregs/asm/config_defs_asm.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: