]>
Commit | Line | Data |
---|---|---|
956b03e1 MD |
1 | /* |
2 | * SPL driver for Diskonchip G4 nand flash | |
3 | * | |
4 | * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com> | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
956b03e1 MD |
7 | * |
8 | * This driver basically mimics the load functionality of a typical IPL (initial | |
9 | * program loader) resident in the 2k NOR-like region of the docg4 that is | |
10 | * mapped to the reset vector. It allows the u-boot SPL to continue loading if | |
11 | * the IPL loads a fixed number of flash blocks that is insufficient to contain | |
12 | * the entire u-boot image. In this case, a concatenated spl + u-boot image is | |
13 | * written at the flash offset from which the IPL loads an image, and when the | |
14 | * IPL jumps to the SPL, the SPL resumes loading where the IPL left off. See | |
15 | * the palmtreo680 for an example. | |
16 | * | |
17 | * This driver assumes that the data was written to the flash using the device's | |
18 | * "reliable" mode, and also assumes that each 512 byte page is stored | |
19 | * redundantly in the subsequent page. This storage format is likely to be used | |
20 | * by all boards that boot from the docg4. The format compensates for the lack | |
21 | * of ecc in the IPL. | |
22 | * | |
23 | * Reliable mode reduces the capacity of a block by half, and the redundant | |
24 | * pages reduce it by half again. As a result, the normal 256k capacity of a | |
25 | * block is reduced to 64k for the purposes of the IPL/SPL. | |
26 | */ | |
27 | ||
28 | #include <asm/io.h> | |
29 | #include <linux/mtd/docg4.h> | |
30 | ||
31 | /* forward declarations */ | |
32 | static inline void write_nop(void __iomem *docptr); | |
33 | static int poll_status(void __iomem *docptr); | |
34 | static void write_addr(void __iomem *docptr, uint32_t docg4_addr); | |
35 | static void address_sequence(unsigned int g4_page, unsigned int g4_index, | |
36 | void __iomem *docptr); | |
37 | static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr); | |
38 | ||
39 | int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) | |
40 | { | |
41 | void *load_addr = dst; | |
42 | uint32_t flash_offset = offs; | |
43 | const unsigned int block_count = | |
44 | (size + DOCG4_BLOCK_CAPACITY_SPL - 1) | |
45 | / DOCG4_BLOCK_CAPACITY_SPL; | |
46 | int i; | |
47 | ||
48 | for (i = 0; i < block_count; i++) { | |
49 | int ret = docg4_load_block_reliable(flash_offset, load_addr); | |
50 | if (ret) | |
51 | return ret; | |
52 | load_addr += DOCG4_BLOCK_CAPACITY_SPL; | |
53 | flash_offset += DOCG4_BLOCK_SIZE; | |
54 | } | |
55 | return 0; | |
56 | } | |
57 | ||
58 | static inline void write_nop(void __iomem *docptr) | |
59 | { | |
60 | writew(0, docptr + DOC_NOP); | |
61 | } | |
62 | ||
63 | static int poll_status(void __iomem *docptr) | |
64 | { | |
65 | /* | |
66 | * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL | |
67 | * register. Operations known to take a long time (e.g., block erase) | |
68 | * should sleep for a while before calling this. | |
69 | */ | |
70 | ||
71 | uint8_t flash_status; | |
72 | ||
73 | /* hardware quirk requires reading twice initially */ | |
74 | flash_status = readb(docptr + DOC_FLASHCONTROL); | |
75 | ||
76 | do { | |
77 | flash_status = readb(docptr + DOC_FLASHCONTROL); | |
78 | } while (!(flash_status & DOC_CTRL_FLASHREADY)); | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
83 | static void write_addr(void __iomem *docptr, uint32_t docg4_addr) | |
84 | { | |
85 | /* write the four address bytes packed in docg4_addr to the device */ | |
86 | ||
87 | writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); | |
88 | docg4_addr >>= 8; | |
89 | writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); | |
90 | docg4_addr >>= 8; | |
91 | writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); | |
92 | docg4_addr >>= 8; | |
93 | writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); | |
94 | } | |
95 | ||
96 | static void address_sequence(unsigned int g4_page, unsigned int g4_index, | |
97 | void __iomem *docptr) | |
98 | { | |
99 | writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE); | |
100 | writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND); | |
101 | write_nop(docptr); | |
102 | write_addr(docptr, ((uint32_t)g4_page << 16) | g4_index); | |
103 | write_nop(docptr); | |
104 | } | |
105 | ||
106 | static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr) | |
107 | { | |
108 | void __iomem *docptr = (void *)CONFIG_SYS_NAND_BASE; | |
109 | unsigned int g4_page = flash_offset >> 11; /* 2k page */ | |
110 | const unsigned int last_g4_page = g4_page + 0x80; /* last in block */ | |
111 | int g4_index = 0; | |
112 | uint16_t flash_status; | |
113 | uint16_t *buf; | |
956b03e1 MD |
114 | |
115 | /* flash_offset must be aligned to the start of a block */ | |
116 | if (flash_offset & 0x3ffff) | |
117 | return -1; | |
118 | ||
119 | writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE); | |
120 | writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND); | |
121 | write_nop(docptr); | |
122 | write_nop(docptr); | |
123 | poll_status(docptr); | |
124 | write_nop(docptr); | |
125 | writew(0x45, docptr + DOC_FLASHSEQUENCE); | |
126 | writew(0xa3, docptr + DOC_FLASHCOMMAND); | |
127 | write_nop(docptr); | |
128 | writew(0x22, docptr + DOC_FLASHCOMMAND); | |
129 | write_nop(docptr); | |
130 | ||
131 | /* read 1st 4 oob bytes of first subpage of block */ | |
132 | address_sequence(g4_page, 0x0100, docptr); /* index at oob */ | |
133 | write_nop(docptr); | |
134 | flash_status = readw(docptr + DOC_FLASHCONTROL); | |
135 | flash_status = readw(docptr + DOC_FLASHCONTROL); | |
136 | if (flash_status & 0x06) /* sequence or protection errors */ | |
137 | return -1; | |
138 | writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND); | |
139 | write_nop(docptr); | |
140 | write_nop(docptr); | |
141 | poll_status(docptr); | |
142 | writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); | |
143 | write_nop(docptr); | |
144 | write_nop(docptr); | |
145 | write_nop(docptr); | |
146 | write_nop(docptr); | |
147 | write_nop(docptr); | |
148 | ||
149 | /* | |
150 | * Here we read the first four oob bytes of the first page of the block. | |
151 | * The IPL on the palmtreo680 requires that this contain a 32 bit magic | |
152 | * number, or the load aborts. We'll ignore it. | |
153 | */ | |
8b6b51a6 MD |
154 | readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ |
155 | readw(docptr + 0x103c); /* lower 16 bits of magic number */ | |
156 | readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */ | |
956b03e1 MD |
157 | writew(0, docptr + DOC_DATAEND); |
158 | write_nop(docptr); | |
159 | write_nop(docptr); | |
160 | ||
161 | /* load contents of block to memory */ | |
162 | buf = (uint16_t *)dest_addr; | |
163 | do { | |
164 | int i; | |
165 | ||
166 | address_sequence(g4_page, g4_index, docptr); | |
167 | writew(DOCG4_CMD_READ2, | |
168 | docptr + DOC_FLASHCOMMAND); | |
169 | write_nop(docptr); | |
170 | write_nop(docptr); | |
171 | poll_status(docptr); | |
172 | writew(DOC_ECCCONF0_READ_MODE | | |
173 | DOC_ECCCONF0_ECC_ENABLE | | |
174 | DOCG4_BCH_SIZE, | |
175 | docptr + DOC_ECCCONF0); | |
176 | write_nop(docptr); | |
177 | write_nop(docptr); | |
178 | write_nop(docptr); | |
179 | write_nop(docptr); | |
180 | write_nop(docptr); | |
181 | ||
182 | /* read the 512 bytes of page data, 2 bytes at a time */ | |
8b6b51a6 | 183 | readw(docptr + 0x103c); /* hw quirk */ |
956b03e1 MD |
184 | for (i = 0; i < 256; i++) |
185 | *buf++ = readw(docptr + 0x103c); | |
186 | ||
187 | /* read oob, but discard it */ | |
188 | for (i = 0; i < 7; i++) | |
8b6b51a6 MD |
189 | readw(docptr + 0x103c); |
190 | readw(docptr + DOCG4_OOB_6_7); | |
191 | readw(docptr + DOCG4_OOB_6_7); | |
956b03e1 MD |
192 | |
193 | writew(0, docptr + DOC_DATAEND); | |
194 | write_nop(docptr); | |
195 | write_nop(docptr); | |
196 | ||
197 | if (!(g4_index & 0x100)) { | |
198 | /* not redundant subpage read; check for ecc error */ | |
199 | write_nop(docptr); | |
200 | flash_status = readw(docptr + DOC_ECCCONF1); | |
201 | flash_status = readw(docptr + DOC_ECCCONF1); | |
202 | if (flash_status & 0x80) { /* ecc error */ | |
203 | g4_index += 0x108; /* read redundant subpage */ | |
204 | buf -= 256; /* back up ram ptr */ | |
205 | continue; | |
206 | } else /* no ecc error */ | |
207 | g4_index += 0x210; /* skip redundant subpage */ | |
208 | } else /* redundant page was just read; skip ecc error check */ | |
209 | g4_index += 0x108; | |
210 | ||
211 | if (g4_index == 0x420) { /* finished with 2k page */ | |
212 | g4_index = 0; | |
213 | g4_page += 2; /* odd-numbered 2k pages skipped */ | |
214 | } | |
215 | ||
216 | } while (g4_page != last_g4_page); /* while still on same block */ | |
217 | ||
218 | return 0; | |
219 | } |