| ##============================================================================= |
| ## |
| ## 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 address |
| 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: |