1##=============================================================================
2##
3##      nand_init.S
4##
5##      The bootrom copies data from the NAND flash to the internal RAM but
6##      due to a bug/feature we can only trust the 256 first bytes. So this
7##      code copies more data from NAND flash to internal RAM. Obvioulsy this
8##      code must fit in the first 256 bytes so alter with care.
9##
10##	Some notes about the bug/feature for future reference:
11##        The bootrom copies the first 127 KB from NAND flash to internal
12##        memory. The problem is that it does a bytewise copy. NAND flashes
13##        does autoincrement on the address so for a 16-bite device each
14##        read/write increases the address by two. So the copy loop in the
15##        bootrom will discard every second byte. This is solved by inserting
16##        zeroes in every second byte in the first erase block.
17##
18##        The bootrom also incorrectly assumes that it can read the flash
19##        linear with only one read command but the flash will actually
20##        switch between normal area and spare area if you do that so we
21##        can't trust more than the first 256 bytes.
22##
23##=============================================================================
24
25#include <asm/arch/hwregs/asm/reg_map_asm.h>
26#include <asm/arch/hwregs/asm/gio_defs_asm.h>
27#include <asm/arch/hwregs/asm/pinmux_defs_asm.h>
28#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
29#include <asm/arch/hwregs/asm/config_defs_asm.h>
30
31;; There are 8-bit NAND flashes and 16-bit NAND flashes.
32;; We need to treat them slightly different.
33#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
34#define PAGE_SIZE 256
35#else
36#error 2
37#define PAGE_SIZE 512
38#endif
39#define ERASE_BLOCK 16384
40
41;; GPIO pins connected to NAND flash
42#define CE 4
43#define CLE 5
44#define ALE 6
45#define BY 7
46
47;; Address space for NAND flash
48#define NAND_RD_ADDR 0x90000000
49#define NAND_WR_ADDR 0x94000000
50
51#define READ_CMD 0x00
52
53;; Readability macros
54#define CSP_MASK \
55	REG_MASK(bif_core, rw_grp3_cfg, gated_csp0) | \
56	REG_MASK(bif_core, rw_grp3_cfg, gated_csp1)
57#define CSP_VAL \
58	REG_STATE(bif_core, rw_grp3_cfg, gated_csp0, rd) | \
59	REG_STATE(bif_core, rw_grp3_cfg, gated_csp1, wr)
60
61;;----------------------------------------------------------------------------
62;; Macros to set/clear GPIO bits
63
64.macro SET x
65	or.b   (1<<\x),$r9
66	move.d $r9, [$r2]
67.endm
68
69.macro CLR x
70	and.b  ~(1<<\x),$r9
71	move.d $r9, [$r2]
72.endm
73
74;;----------------------------------------------------------------------------
75
76nand_boot:
77	;; Check if nand boot was selected
78	move.d REG_ADDR(config, regi_config, r_bootsel), $r0
79	move.d [$r0], $r0
80	and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
81	cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
82	bne normal_boot ; No NAND boot
83	nop
84
85copy_nand_to_ram:
86	;; copy_nand_to_ram
87	;; Arguments
88	;;   r10 - destination
89	;;   r11 - source offset
90	;;   r12 - size
91	;;   r13 - Address to jump to after completion
92	;; Note : r10-r12 are clobbered on return
93	;; Registers used:
94	;;   r0 - NAND_RD_ADDR
95	;;   r1 - NAND_WR_ADDR
96	;;   r2 - reg_gio_rw_pa_dout
97	;;   r3 - reg_gio_r_pa_din
98	;;   r4 - tmp
99	;;   r5 - byte counter within a page
100	;;   r6 - reg_pinmux_rw_pa
101	;;   r7 - reg_gio_rw_pa_oe
102	;;   r8 - reg_bif_core_rw_grp3_cfg
103	;;   r9 - reg_gio_rw_pa_dout shadow
104	move.d 0x90000000, $r0
105	move.d 0x94000000, $r1
106	move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r2
107	move.d REG_ADDR(gio, regi_gio, r_pa_din), $r3
108	move.d REG_ADDR(pinmux, regi_pinmux, rw_pa), $r6
109	move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r7
110	move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r8
111
112#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
113	lsrq	1, $r11
114#endif
115	;; Set up GPIO
116	move.d [$r2], $r9
117	move.d [$r7], $r4
118	or.b (1<<ALE) | (1 << CLE) | (1<<CE), $r4
119	move.d $r4, [$r7]
120
121	;; Set up bif
122	move.d [$r8], $r4
123	and.d CSP_MASK, $r4
124	or.d CSP_VAL, $r4
125	move.d $r4, [$r8]
126
1271:	;; Copy one page
128	CLR CE
129	SET CLE
130	moveq	READ_CMD, $r4
131	move.b	$r4, [$r1]
132	moveq	20, $r4
1332:	bne	2b
134	subq	1, $r4
135	CLR CLE
136	SET ALE
137	clear.w [$r1] 		; Column address = 0
138	move.d	$r11, $r4
139	lsrq	8, $r4
140	move.b	$r4, [$r1]	; Row address
141	lsrq	8, $r4
142	move.b	$r4, [$r1]	; Row adddress
143	moveq	20, $r4
1442:	bne	2b
145	subq	1, $r4
146	CLR ALE
1472:	move.d	[$r3], $r4
148	and.d	1 << BY, $r4
149	beq 2b
150	movu.w  PAGE_SIZE, $r5
1512:	; Copy one byte/word
152#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
153	move.w  [$r0], $r4
154#else
155	move.b  [$r0], $r4
156#endif
157	subq	1, $r5
158	bne	2b
159#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
160	move.w  $r4, [$r10+]
161	subu.w	PAGE_SIZE*2, $r12
162#else
163	move.b  $r4, [$r10+]
164	subu.w	PAGE_SIZE, $r12
165#endif
166	bpl	1b
167	addu.w	PAGE_SIZE, $r11
168
169	;; End of copy
170	jump	$r13
171	nop
172
173	;; This will warn if the code above is too large. If you consider
174	;; to remove this you don't understand the bug/feature.
175	.org 256
176	.org ERASE_BLOCK
177
178normal_boot:
179