Commit ab92224f4550f9677be32dd903e99acf1475dbf7
1 parent
2ba863fae6
Exists in
master
and in
50 other branches
sf: ops: Unify read_ops bank configuration
Unified the bar code from read_ops into a spi_flash_bar() Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
Showing 1 changed file with 5 additions and 8 deletions Inline Diff
drivers/mtd/spi/sf_ops.c
1 | /* | 1 | /* |
2 | * SPI flash operations | 2 | * SPI flash operations |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Atmel Corporation | 4 | * Copyright (C) 2008 Atmel Corporation |
5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | 5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik |
6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | 6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
7 | * | 7 | * |
8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <common.h> | 11 | #include <common.h> |
12 | #include <malloc.h> | 12 | #include <malloc.h> |
13 | #include <spi.h> | 13 | #include <spi.h> |
14 | #include <spi_flash.h> | 14 | #include <spi_flash.h> |
15 | #include <watchdog.h> | 15 | #include <watchdog.h> |
16 | 16 | ||
17 | #include "sf_internal.h" | 17 | #include "sf_internal.h" |
18 | 18 | ||
19 | static void spi_flash_addr(u32 addr, u8 *cmd) | 19 | static void spi_flash_addr(u32 addr, u8 *cmd) |
20 | { | 20 | { |
21 | /* cmd[0] is actual command */ | 21 | /* cmd[0] is actual command */ |
22 | cmd[1] = addr >> 16; | 22 | cmd[1] = addr >> 16; |
23 | cmd[2] = addr >> 8; | 23 | cmd[2] = addr >> 8; |
24 | cmd[3] = addr >> 0; | 24 | cmd[3] = addr >> 0; |
25 | } | 25 | } |
26 | 26 | ||
27 | int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) | 27 | int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) |
28 | { | 28 | { |
29 | int ret; | 29 | int ret; |
30 | u8 cmd; | 30 | u8 cmd; |
31 | 31 | ||
32 | cmd = CMD_READ_STATUS; | 32 | cmd = CMD_READ_STATUS; |
33 | ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); | 33 | ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); |
34 | if (ret < 0) { | 34 | if (ret < 0) { |
35 | debug("SF: fail to read status register\n"); | 35 | debug("SF: fail to read status register\n"); |
36 | return ret; | 36 | return ret; |
37 | } | 37 | } |
38 | 38 | ||
39 | return 0; | 39 | return 0; |
40 | } | 40 | } |
41 | 41 | ||
42 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) | 42 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) |
43 | { | 43 | { |
44 | u8 cmd; | 44 | u8 cmd; |
45 | int ret; | 45 | int ret; |
46 | 46 | ||
47 | cmd = CMD_WRITE_STATUS; | 47 | cmd = CMD_WRITE_STATUS; |
48 | ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); | 48 | ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); |
49 | if (ret < 0) { | 49 | if (ret < 0) { |
50 | debug("SF: fail to write status register\n"); | 50 | debug("SF: fail to write status register\n"); |
51 | return ret; | 51 | return ret; |
52 | } | 52 | } |
53 | 53 | ||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | 57 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) |
58 | int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) | 58 | int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) |
59 | { | 59 | { |
60 | int ret; | 60 | int ret; |
61 | u8 cmd; | 61 | u8 cmd; |
62 | 62 | ||
63 | cmd = CMD_READ_CONFIG; | 63 | cmd = CMD_READ_CONFIG; |
64 | ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); | 64 | ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); |
65 | if (ret < 0) { | 65 | if (ret < 0) { |
66 | debug("SF: fail to read config register\n"); | 66 | debug("SF: fail to read config register\n"); |
67 | return ret; | 67 | return ret; |
68 | } | 68 | } |
69 | 69 | ||
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | 72 | ||
73 | int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) | 73 | int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) |
74 | { | 74 | { |
75 | u8 data[2]; | 75 | u8 data[2]; |
76 | u8 cmd; | 76 | u8 cmd; |
77 | int ret; | 77 | int ret; |
78 | 78 | ||
79 | ret = spi_flash_cmd_read_status(flash, &data[0]); | 79 | ret = spi_flash_cmd_read_status(flash, &data[0]); |
80 | if (ret < 0) | 80 | if (ret < 0) |
81 | return ret; | 81 | return ret; |
82 | 82 | ||
83 | cmd = CMD_WRITE_STATUS; | 83 | cmd = CMD_WRITE_STATUS; |
84 | data[1] = wc; | 84 | data[1] = wc; |
85 | ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); | 85 | ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); |
86 | if (ret) { | 86 | if (ret) { |
87 | debug("SF: fail to write config register\n"); | 87 | debug("SF: fail to write config register\n"); |
88 | return ret; | 88 | return ret; |
89 | } | 89 | } |
90 | 90 | ||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | #endif | 93 | #endif |
94 | 94 | ||
95 | #ifdef CONFIG_SPI_FLASH_BAR | 95 | #ifdef CONFIG_SPI_FLASH_BAR |
96 | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | 96 | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) |
97 | { | 97 | { |
98 | u8 cmd; | 98 | u8 cmd; |
99 | int ret; | 99 | int ret; |
100 | 100 | ||
101 | if (flash->bank_curr == bank_sel) { | 101 | if (flash->bank_curr == bank_sel) { |
102 | debug("SF: not require to enable bank%d\n", bank_sel); | 102 | debug("SF: not require to enable bank%d\n", bank_sel); |
103 | return 0; | 103 | return 0; |
104 | } | 104 | } |
105 | 105 | ||
106 | cmd = flash->bank_write_cmd; | 106 | cmd = flash->bank_write_cmd; |
107 | ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); | 107 | ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); |
108 | if (ret < 0) { | 108 | if (ret < 0) { |
109 | debug("SF: fail to write bank register\n"); | 109 | debug("SF: fail to write bank register\n"); |
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | flash->bank_curr = bank_sel; | 112 | flash->bank_curr = bank_sel; |
113 | 113 | ||
114 | return 0; | 114 | return 0; |
115 | } | 115 | } |
116 | 116 | ||
117 | static int spi_flash_bank(struct spi_flash *flash, u32 offset) | 117 | static int spi_flash_bank(struct spi_flash *flash, u32 offset) |
118 | { | 118 | { |
119 | u8 bank_sel; | 119 | u8 bank_sel; |
120 | int ret; | 120 | int ret; |
121 | 121 | ||
122 | bank_sel = offset / SPI_FLASH_16MB_BOUN; | 122 | bank_sel = offset / SPI_FLASH_16MB_BOUN; |
123 | 123 | ||
124 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | 124 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); |
125 | if (ret) { | 125 | if (ret) { |
126 | debug("SF: fail to set bank%d\n", bank_sel); | 126 | debug("SF: fail to set bank%d\n", bank_sel); |
127 | return ret; | 127 | return ret; |
128 | } | 128 | } |
129 | 129 | ||
130 | return 0; | 130 | return bank_sel; |
131 | } | 131 | } |
132 | #endif | 132 | #endif |
133 | 133 | ||
134 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | 134 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) |
135 | { | 135 | { |
136 | struct spi_slave *spi = flash->spi; | 136 | struct spi_slave *spi = flash->spi; |
137 | unsigned long timebase; | 137 | unsigned long timebase; |
138 | int ret; | 138 | int ret; |
139 | u8 status; | 139 | u8 status; |
140 | u8 check_status = 0x0; | 140 | u8 check_status = 0x0; |
141 | u8 poll_bit = STATUS_WIP; | 141 | u8 poll_bit = STATUS_WIP; |
142 | u8 cmd = flash->poll_cmd; | 142 | u8 cmd = flash->poll_cmd; |
143 | 143 | ||
144 | if (cmd == CMD_FLAG_STATUS) { | 144 | if (cmd == CMD_FLAG_STATUS) { |
145 | poll_bit = STATUS_PEC; | 145 | poll_bit = STATUS_PEC; |
146 | check_status = poll_bit; | 146 | check_status = poll_bit; |
147 | } | 147 | } |
148 | 148 | ||
149 | ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | 149 | ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); |
150 | if (ret) { | 150 | if (ret) { |
151 | debug("SF: fail to read %s status register\n", | 151 | debug("SF: fail to read %s status register\n", |
152 | cmd == CMD_READ_STATUS ? "read" : "flag"); | 152 | cmd == CMD_READ_STATUS ? "read" : "flag"); |
153 | return ret; | 153 | return ret; |
154 | } | 154 | } |
155 | 155 | ||
156 | timebase = get_timer(0); | 156 | timebase = get_timer(0); |
157 | do { | 157 | do { |
158 | WATCHDOG_RESET(); | 158 | WATCHDOG_RESET(); |
159 | 159 | ||
160 | ret = spi_xfer(spi, 8, NULL, &status, 0); | 160 | ret = spi_xfer(spi, 8, NULL, &status, 0); |
161 | if (ret) | 161 | if (ret) |
162 | return -1; | 162 | return -1; |
163 | 163 | ||
164 | if ((status & poll_bit) == check_status) | 164 | if ((status & poll_bit) == check_status) |
165 | break; | 165 | break; |
166 | 166 | ||
167 | } while (get_timer(timebase) < timeout); | 167 | } while (get_timer(timebase) < timeout); |
168 | 168 | ||
169 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); | 169 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); |
170 | 170 | ||
171 | if ((status & poll_bit) == check_status) | 171 | if ((status & poll_bit) == check_status) |
172 | return 0; | 172 | return 0; |
173 | 173 | ||
174 | /* Timed out */ | 174 | /* Timed out */ |
175 | debug("SF: time out!\n"); | 175 | debug("SF: time out!\n"); |
176 | return -1; | 176 | return -1; |
177 | } | 177 | } |
178 | 178 | ||
179 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | 179 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |
180 | size_t cmd_len, const void *buf, size_t buf_len) | 180 | size_t cmd_len, const void *buf, size_t buf_len) |
181 | { | 181 | { |
182 | struct spi_slave *spi = flash->spi; | 182 | struct spi_slave *spi = flash->spi; |
183 | unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; | 183 | unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; |
184 | int ret; | 184 | int ret; |
185 | 185 | ||
186 | if (buf == NULL) | 186 | if (buf == NULL) |
187 | timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; | 187 | timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; |
188 | 188 | ||
189 | ret = spi_claim_bus(flash->spi); | 189 | ret = spi_claim_bus(flash->spi); |
190 | if (ret) { | 190 | if (ret) { |
191 | debug("SF: unable to claim SPI bus\n"); | 191 | debug("SF: unable to claim SPI bus\n"); |
192 | return ret; | 192 | return ret; |
193 | } | 193 | } |
194 | 194 | ||
195 | ret = spi_flash_cmd_write_enable(flash); | 195 | ret = spi_flash_cmd_write_enable(flash); |
196 | if (ret < 0) { | 196 | if (ret < 0) { |
197 | debug("SF: enabling write failed\n"); | 197 | debug("SF: enabling write failed\n"); |
198 | return ret; | 198 | return ret; |
199 | } | 199 | } |
200 | 200 | ||
201 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); | 201 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); |
202 | if (ret < 0) { | 202 | if (ret < 0) { |
203 | debug("SF: write cmd failed\n"); | 203 | debug("SF: write cmd failed\n"); |
204 | return ret; | 204 | return ret; |
205 | } | 205 | } |
206 | 206 | ||
207 | ret = spi_flash_cmd_wait_ready(flash, timeout); | 207 | ret = spi_flash_cmd_wait_ready(flash, timeout); |
208 | if (ret < 0) { | 208 | if (ret < 0) { |
209 | debug("SF: write %s timed out\n", | 209 | debug("SF: write %s timed out\n", |
210 | timeout == SPI_FLASH_PROG_TIMEOUT ? | 210 | timeout == SPI_FLASH_PROG_TIMEOUT ? |
211 | "program" : "page erase"); | 211 | "program" : "page erase"); |
212 | return ret; | 212 | return ret; |
213 | } | 213 | } |
214 | 214 | ||
215 | spi_release_bus(spi); | 215 | spi_release_bus(spi); |
216 | 216 | ||
217 | return ret; | 217 | return ret; |
218 | } | 218 | } |
219 | 219 | ||
220 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) | 220 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) |
221 | { | 221 | { |
222 | u32 erase_size; | 222 | u32 erase_size; |
223 | u8 cmd[SPI_FLASH_CMD_LEN]; | 223 | u8 cmd[SPI_FLASH_CMD_LEN]; |
224 | int ret = -1; | 224 | int ret = -1; |
225 | 225 | ||
226 | erase_size = flash->erase_size; | 226 | erase_size = flash->erase_size; |
227 | if (offset % erase_size || len % erase_size) { | 227 | if (offset % erase_size || len % erase_size) { |
228 | debug("SF: Erase offset/length not multiple of erase size\n"); | 228 | debug("SF: Erase offset/length not multiple of erase size\n"); |
229 | return -1; | 229 | return -1; |
230 | } | 230 | } |
231 | 231 | ||
232 | cmd[0] = flash->erase_cmd; | 232 | cmd[0] = flash->erase_cmd; |
233 | while (len) { | 233 | while (len) { |
234 | #ifdef CONFIG_SPI_FLASH_BAR | 234 | #ifdef CONFIG_SPI_FLASH_BAR |
235 | ret = spi_flash_bank(flash, offset); | 235 | ret = spi_flash_bank(flash, offset); |
236 | if (ret < 0) | 236 | if (ret < 0) |
237 | return ret; | 237 | return ret; |
238 | #endif | 238 | #endif |
239 | spi_flash_addr(offset, cmd); | 239 | spi_flash_addr(offset, cmd); |
240 | 240 | ||
241 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | 241 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], |
242 | cmd[2], cmd[3], offset); | 242 | cmd[2], cmd[3], offset); |
243 | 243 | ||
244 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | 244 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); |
245 | if (ret < 0) { | 245 | if (ret < 0) { |
246 | debug("SF: erase failed\n"); | 246 | debug("SF: erase failed\n"); |
247 | break; | 247 | break; |
248 | } | 248 | } |
249 | 249 | ||
250 | offset += erase_size; | 250 | offset += erase_size; |
251 | len -= erase_size; | 251 | len -= erase_size; |
252 | } | 252 | } |
253 | 253 | ||
254 | return ret; | 254 | return ret; |
255 | } | 255 | } |
256 | 256 | ||
257 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, | 257 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, |
258 | size_t len, const void *buf) | 258 | size_t len, const void *buf) |
259 | { | 259 | { |
260 | unsigned long byte_addr, page_size; | 260 | unsigned long byte_addr, page_size; |
261 | size_t chunk_len, actual; | 261 | size_t chunk_len, actual; |
262 | u8 cmd[SPI_FLASH_CMD_LEN]; | 262 | u8 cmd[SPI_FLASH_CMD_LEN]; |
263 | int ret = -1; | 263 | int ret = -1; |
264 | 264 | ||
265 | page_size = flash->page_size; | 265 | page_size = flash->page_size; |
266 | 266 | ||
267 | cmd[0] = flash->write_cmd; | 267 | cmd[0] = flash->write_cmd; |
268 | for (actual = 0; actual < len; actual += chunk_len) { | 268 | for (actual = 0; actual < len; actual += chunk_len) { |
269 | #ifdef CONFIG_SPI_FLASH_BAR | 269 | #ifdef CONFIG_SPI_FLASH_BAR |
270 | ret = spi_flash_bank(flash, offset); | 270 | ret = spi_flash_bank(flash, offset); |
271 | if (ret < 0) | 271 | if (ret < 0) |
272 | return ret; | 272 | return ret; |
273 | #endif | 273 | #endif |
274 | byte_addr = offset % page_size; | 274 | byte_addr = offset % page_size; |
275 | chunk_len = min(len - actual, page_size - byte_addr); | 275 | chunk_len = min(len - actual, page_size - byte_addr); |
276 | 276 | ||
277 | if (flash->spi->max_write_size) | 277 | if (flash->spi->max_write_size) |
278 | chunk_len = min(chunk_len, flash->spi->max_write_size); | 278 | chunk_len = min(chunk_len, flash->spi->max_write_size); |
279 | 279 | ||
280 | spi_flash_addr(offset, cmd); | 280 | spi_flash_addr(offset, cmd); |
281 | 281 | ||
282 | debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | 282 | debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", |
283 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | 283 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); |
284 | 284 | ||
285 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | 285 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), |
286 | buf + actual, chunk_len); | 286 | buf + actual, chunk_len); |
287 | if (ret < 0) { | 287 | if (ret < 0) { |
288 | debug("SF: write failed\n"); | 288 | debug("SF: write failed\n"); |
289 | break; | 289 | break; |
290 | } | 290 | } |
291 | 291 | ||
292 | offset += chunk_len; | 292 | offset += chunk_len; |
293 | } | 293 | } |
294 | 294 | ||
295 | return ret; | 295 | return ret; |
296 | } | 296 | } |
297 | 297 | ||
298 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | 298 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, |
299 | size_t cmd_len, void *data, size_t data_len) | 299 | size_t cmd_len, void *data, size_t data_len) |
300 | { | 300 | { |
301 | struct spi_slave *spi = flash->spi; | 301 | struct spi_slave *spi = flash->spi; |
302 | int ret; | 302 | int ret; |
303 | 303 | ||
304 | ret = spi_claim_bus(flash->spi); | 304 | ret = spi_claim_bus(flash->spi); |
305 | if (ret) { | 305 | if (ret) { |
306 | debug("SF: unable to claim SPI bus\n"); | 306 | debug("SF: unable to claim SPI bus\n"); |
307 | return ret; | 307 | return ret; |
308 | } | 308 | } |
309 | 309 | ||
310 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | 310 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); |
311 | if (ret < 0) { | 311 | if (ret < 0) { |
312 | debug("SF: read cmd failed\n"); | 312 | debug("SF: read cmd failed\n"); |
313 | return ret; | 313 | return ret; |
314 | } | 314 | } |
315 | 315 | ||
316 | spi_release_bus(spi); | 316 | spi_release_bus(spi); |
317 | 317 | ||
318 | return ret; | 318 | return ret; |
319 | } | 319 | } |
320 | 320 | ||
321 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | 321 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |
322 | size_t len, void *data) | 322 | size_t len, void *data) |
323 | { | 323 | { |
324 | u8 *cmd, cmdsz, bank_sel = 0; | 324 | u8 *cmd, cmdsz; |
325 | u32 remain_len, read_len; | 325 | u32 remain_len, read_len; |
326 | int bank_sel = 0; | ||
326 | int ret = -1; | 327 | int ret = -1; |
327 | 328 | ||
328 | /* Handle memory-mapped SPI */ | 329 | /* Handle memory-mapped SPI */ |
329 | if (flash->memory_map) { | 330 | if (flash->memory_map) { |
330 | ret = spi_claim_bus(flash->spi); | 331 | ret = spi_claim_bus(flash->spi); |
331 | if (ret) { | 332 | if (ret) { |
332 | debug("SF: unable to claim SPI bus\n"); | 333 | debug("SF: unable to claim SPI bus\n"); |
333 | return ret; | 334 | return ret; |
334 | } | 335 | } |
335 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); | 336 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); |
336 | memcpy(data, flash->memory_map + offset, len); | 337 | memcpy(data, flash->memory_map + offset, len); |
337 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); | 338 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); |
338 | spi_release_bus(flash->spi); | 339 | spi_release_bus(flash->spi); |
339 | return 0; | 340 | return 0; |
340 | } | 341 | } |
341 | 342 | ||
342 | cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; | 343 | cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; |
343 | cmd = malloc(cmdsz); | 344 | cmd = malloc(cmdsz); |
344 | memset(cmd, 0, cmdsz); | 345 | memset(cmd, 0, cmdsz); |
345 | 346 | ||
346 | cmd[0] = flash->read_cmd; | 347 | cmd[0] = flash->read_cmd; |
347 | while (len) { | 348 | while (len) { |
348 | #ifdef CONFIG_SPI_FLASH_BAR | 349 | #ifdef CONFIG_SPI_FLASH_BAR |
349 | bank_sel = offset / SPI_FLASH_16MB_BOUN; | 350 | bank_sel = spi_flash_bank(flash, offset); |
350 | 351 | if (bank_sel < 0) | |
351 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | ||
352 | if (ret) { | ||
353 | debug("SF: fail to set bank%d\n", bank_sel); | ||
354 | return ret; | 352 | return ret; |
355 | } | ||
356 | #endif | 353 | #endif |
357 | remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; | 354 | remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; |
358 | if (len < remain_len) | 355 | if (len < remain_len) |
359 | read_len = len; | 356 | read_len = len; |
360 | else | 357 | else |
361 | read_len = remain_len; | 358 | read_len = remain_len; |
362 | 359 | ||
363 | spi_flash_addr(offset, cmd); | 360 | spi_flash_addr(offset, cmd); |
364 | 361 | ||
365 | ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); | 362 | ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); |
366 | if (ret < 0) { | 363 | if (ret < 0) { |
367 | debug("SF: read failed\n"); | 364 | debug("SF: read failed\n"); |
368 | break; | 365 | break; |
369 | } | 366 | } |
370 | 367 | ||
371 | offset += read_len; | 368 | offset += read_len; |
372 | len -= read_len; | 369 | len -= read_len; |
373 | data += read_len; | 370 | data += read_len; |
374 | } | 371 | } |
375 | 372 | ||
376 | return ret; | 373 | return ret; |
377 | } | 374 | } |
378 | 375 | ||
379 | #ifdef CONFIG_SPI_FLASH_SST | 376 | #ifdef CONFIG_SPI_FLASH_SST |
380 | static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) | 377 | static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) |
381 | { | 378 | { |
382 | int ret; | 379 | int ret; |
383 | u8 cmd[4] = { | 380 | u8 cmd[4] = { |
384 | CMD_SST_BP, | 381 | CMD_SST_BP, |
385 | offset >> 16, | 382 | offset >> 16, |
386 | offset >> 8, | 383 | offset >> 8, |
387 | offset, | 384 | offset, |
388 | }; | 385 | }; |
389 | 386 | ||
390 | debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | 387 | debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", |
391 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); | 388 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); |
392 | 389 | ||
393 | ret = spi_flash_cmd_write_enable(flash); | 390 | ret = spi_flash_cmd_write_enable(flash); |
394 | if (ret) | 391 | if (ret) |
395 | return ret; | 392 | return ret; |
396 | 393 | ||
397 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); | 394 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); |
398 | if (ret) | 395 | if (ret) |
399 | return ret; | 396 | return ret; |
400 | 397 | ||
401 | return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | 398 | return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); |
402 | } | 399 | } |
403 | 400 | ||
404 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, | 401 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, |
405 | const void *buf) | 402 | const void *buf) |
406 | { | 403 | { |
407 | size_t actual, cmd_len; | 404 | size_t actual, cmd_len; |
408 | int ret; | 405 | int ret; |
409 | u8 cmd[4]; | 406 | u8 cmd[4]; |
410 | 407 | ||
411 | ret = spi_claim_bus(flash->spi); | 408 | ret = spi_claim_bus(flash->spi); |
412 | if (ret) { | 409 | if (ret) { |
413 | debug("SF: Unable to claim SPI bus\n"); | 410 | debug("SF: Unable to claim SPI bus\n"); |
414 | return ret; | 411 | return ret; |
415 | } | 412 | } |
416 | 413 | ||
417 | /* If the data is not word aligned, write out leading single byte */ | 414 | /* If the data is not word aligned, write out leading single byte */ |
418 | actual = offset % 2; | 415 | actual = offset % 2; |
419 | if (actual) { | 416 | if (actual) { |
420 | ret = sst_byte_write(flash, offset, buf); | 417 | ret = sst_byte_write(flash, offset, buf); |
421 | if (ret) | 418 | if (ret) |
422 | goto done; | 419 | goto done; |
423 | } | 420 | } |
424 | offset += actual; | 421 | offset += actual; |
425 | 422 | ||
426 | ret = spi_flash_cmd_write_enable(flash); | 423 | ret = spi_flash_cmd_write_enable(flash); |
427 | if (ret) | 424 | if (ret) |
428 | goto done; | 425 | goto done; |
429 | 426 | ||
430 | cmd_len = 4; | 427 | cmd_len = 4; |
431 | cmd[0] = CMD_SST_AAI_WP; | 428 | cmd[0] = CMD_SST_AAI_WP; |
432 | cmd[1] = offset >> 16; | 429 | cmd[1] = offset >> 16; |
433 | cmd[2] = offset >> 8; | 430 | cmd[2] = offset >> 8; |
434 | cmd[3] = offset; | 431 | cmd[3] = offset; |
435 | 432 | ||
436 | for (; actual < len - 1; actual += 2) { | 433 | for (; actual < len - 1; actual += 2) { |
437 | debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | 434 | debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", |
438 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, | 435 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, |
439 | cmd[0], offset); | 436 | cmd[0], offset); |
440 | 437 | ||
441 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, | 438 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, |
442 | buf + actual, 2); | 439 | buf + actual, 2); |
443 | if (ret) { | 440 | if (ret) { |
444 | debug("SF: sst word program failed\n"); | 441 | debug("SF: sst word program failed\n"); |
445 | break; | 442 | break; |
446 | } | 443 | } |
447 | 444 | ||
448 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | 445 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); |
449 | if (ret) | 446 | if (ret) |
450 | break; | 447 | break; |
451 | 448 | ||
452 | cmd_len = 1; | 449 | cmd_len = 1; |
453 | offset += 2; | 450 | offset += 2; |
454 | } | 451 | } |
455 | 452 | ||
456 | if (!ret) | 453 | if (!ret) |
457 | ret = spi_flash_cmd_write_disable(flash); | 454 | ret = spi_flash_cmd_write_disable(flash); |
458 | 455 | ||
459 | /* If there is a single trailing byte, write it out */ | 456 | /* If there is a single trailing byte, write it out */ |
460 | if (!ret && actual != len) | 457 | if (!ret && actual != len) |
461 | ret = sst_byte_write(flash, offset, buf + actual); | 458 | ret = sst_byte_write(flash, offset, buf + actual); |
462 | 459 | ||
463 | done: | 460 | done: |
464 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", | 461 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", |
465 | ret ? "failure" : "success", len, offset - actual); | 462 | ret ? "failure" : "success", len, offset - actual); |
466 | 463 | ||
467 | spi_release_bus(flash->spi); | 464 | spi_release_bus(flash->spi); |
468 | return ret; | 465 | return ret; |
469 | } | 466 | } |
470 | #endif | 467 | #endif |