blob: 39e06ecae0dcf341464a11f8eebea3afe4ab2c92 [file] [log] [blame]
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +05301/*
2 * SPI flash operations
3 *
4 * Copyright (C) 2008 Atmel Corporation
5 * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
6 * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
7 *
Jagannadha Sutradharudu Tekid1452702013-10-10 22:32:55 +05308 * SPDX-License-Identifier: GPL-2.0+
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +05309 */
10
11#include <common.h>
12#include <spi.h>
13#include <spi_flash.h>
14#include <watchdog.h>
15
Jagannadha Sutradharudu Tekiac8242d2013-09-26 16:00:15 +053016#include "sf_internal.h"
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053017
18static void spi_flash_addr(u32 addr, u8 *cmd)
19{
20 /* cmd[0] is actual command */
21 cmd[1] = addr >> 16;
22 cmd[2] = addr >> 8;
23 cmd[3] = addr >> 0;
24}
25
26int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
27{
28 u8 cmd;
29 int ret;
30
31 cmd = CMD_WRITE_STATUS;
32 ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1);
33 if (ret < 0) {
34 debug("SF: fail to write status register\n");
35 return ret;
36 }
37
38 return 0;
39}
40
Jagannadha Sutradharudu Teki8a9c9682013-12-23 15:47:48 +053041static int spi_flash_cmd_write_config(struct spi_flash *flash, u8 cr)
42{
43 u8 data[2];
44 u8 cmd;
45 int ret;
46
47 cmd = CMD_READ_STATUS;
48 ret = spi_flash_read_common(flash, &cmd, 1, &data[0], 1);
49 if (ret < 0) {
50 debug("SF: fail to read status register\n");
51 return ret;
52 }
53
54 cmd = CMD_WRITE_STATUS;
55 data[1] = cr;
56 ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
57 if (ret) {
58 debug("SF: fail to write config register\n");
59 return ret;
60 }
61
62 return 0;
63}
64
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053065#ifdef CONFIG_SPI_FLASH_BAR
Jagannadha Sutradharudu Teki86a380e2013-08-28 14:57:03 +053066static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053067{
68 u8 cmd;
69 int ret;
70
71 if (flash->bank_curr == bank_sel) {
72 debug("SF: not require to enable bank%d\n", bank_sel);
73 return 0;
74 }
75
76 cmd = flash->bank_write_cmd;
77 ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
78 if (ret < 0) {
79 debug("SF: fail to write bank register\n");
80 return ret;
81 }
82 flash->bank_curr = bank_sel;
83
84 return 0;
85}
Jagannadha Sutradharudu Tekie14596c2013-10-08 23:26:47 +053086
87static int spi_flash_bank(struct spi_flash *flash, u32 offset)
88{
89 u8 bank_sel;
90 int ret;
91
92 bank_sel = offset / SPI_FLASH_16MB_BOUN;
93
94 ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
95 if (ret) {
96 debug("SF: fail to set bank%d\n", bank_sel);
97 return ret;
98 }
99
100 return 0;
101}
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530102#endif
103
104int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
105{
106 struct spi_slave *spi = flash->spi;
107 unsigned long timebase;
108 int ret;
109 u8 status;
110 u8 check_status = 0x0;
111 u8 poll_bit = STATUS_WIP;
112 u8 cmd = flash->poll_cmd;
113
114 if (cmd == CMD_FLAG_STATUS) {
115 poll_bit = STATUS_PEC;
116 check_status = poll_bit;
117 }
118
119 ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
120 if (ret) {
121 debug("SF: fail to read %s status register\n",
122 cmd == CMD_READ_STATUS ? "read" : "flag");
123 return ret;
124 }
125
126 timebase = get_timer(0);
127 do {
128 WATCHDOG_RESET();
129
130 ret = spi_xfer(spi, 8, NULL, &status, 0);
131 if (ret)
132 return -1;
133
134 if ((status & poll_bit) == check_status)
135 break;
136
137 } while (get_timer(timebase) < timeout);
138
139 spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
140
141 if ((status & poll_bit) == check_status)
142 return 0;
143
144 /* Timed out */
145 debug("SF: time out!\n");
146 return -1;
147}
148
149int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
150 size_t cmd_len, const void *buf, size_t buf_len)
151{
152 struct spi_slave *spi = flash->spi;
153 unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
154 int ret;
155
156 if (buf == NULL)
157 timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
158
159 ret = spi_claim_bus(flash->spi);
160 if (ret) {
161 debug("SF: unable to claim SPI bus\n");
162 return ret;
163 }
164
165 ret = spi_flash_cmd_write_enable(flash);
166 if (ret < 0) {
167 debug("SF: enabling write failed\n");
168 return ret;
169 }
170
171 ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
172 if (ret < 0) {
173 debug("SF: write cmd failed\n");
174 return ret;
175 }
176
177 ret = spi_flash_cmd_wait_ready(flash, timeout);
178 if (ret < 0) {
179 debug("SF: write %s timed out\n",
180 timeout == SPI_FLASH_PROG_TIMEOUT ?
181 "program" : "page erase");
182 return ret;
183 }
184
185 spi_release_bus(spi);
186
187 return ret;
188}
189
Jagannadha Sutradharudu Teki25dc86a2013-10-02 19:38:49 +0530190int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530191{
192 u32 erase_size;
193 u8 cmd[4];
194 int ret = -1;
195
Jagannadha Sutradharudu Tekibc0f8792013-10-02 19:36:58 +0530196 erase_size = flash->erase_size;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530197 if (offset % erase_size || len % erase_size) {
198 debug("SF: Erase offset/length not multiple of erase size\n");
199 return -1;
200 }
201
Jagannadha Sutradharudu Tekibc0f8792013-10-02 19:36:58 +0530202 cmd[0] = flash->erase_cmd;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530203 while (len) {
204#ifdef CONFIG_SPI_FLASH_BAR
Jagannadha Sutradharudu Tekie14596c2013-10-08 23:26:47 +0530205 ret = spi_flash_bank(flash, offset);
206 if (ret < 0)
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530207 return ret;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530208#endif
209 spi_flash_addr(offset, cmd);
210
211 debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
212 cmd[2], cmd[3], offset);
213
214 ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
215 if (ret < 0) {
216 debug("SF: erase failed\n");
217 break;
218 }
219
220 offset += erase_size;
221 len -= erase_size;
222 }
223
224 return ret;
225}
226
Jagannadha Sutradharudu Teki25dc86a2013-10-02 19:38:49 +0530227int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530228 size_t len, const void *buf)
229{
230 unsigned long byte_addr, page_size;
231 size_t chunk_len, actual;
232 u8 cmd[4];
233 int ret = -1;
234
235 page_size = flash->page_size;
236
Jagannadha Sutradharudu Tekie0ebabc2014-01-11 15:13:11 +0530237 cmd[0] = flash->write_cmd;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530238 for (actual = 0; actual < len; actual += chunk_len) {
239#ifdef CONFIG_SPI_FLASH_BAR
Jagannadha Sutradharudu Tekie14596c2013-10-08 23:26:47 +0530240 ret = spi_flash_bank(flash, offset);
241 if (ret < 0)
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530242 return ret;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530243#endif
244 byte_addr = offset % page_size;
245 chunk_len = min(len - actual, page_size - byte_addr);
246
247 if (flash->spi->max_write_size)
248 chunk_len = min(chunk_len, flash->spi->max_write_size);
249
250 spi_flash_addr(offset, cmd);
251
252 debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
253 buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
254
255 ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
256 buf + actual, chunk_len);
257 if (ret < 0) {
258 debug("SF: write failed\n");
259 break;
260 }
261
262 offset += chunk_len;
263 }
264
265 return ret;
266}
267
268int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
269 size_t cmd_len, void *data, size_t data_len)
270{
271 struct spi_slave *spi = flash->spi;
272 int ret;
273
274 ret = spi_claim_bus(flash->spi);
275 if (ret) {
276 debug("SF: unable to claim SPI bus\n");
277 return ret;
278 }
279
280 ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
281 if (ret < 0) {
282 debug("SF: read cmd failed\n");
283 return ret;
284 }
285
286 spi_release_bus(spi);
287
288 return ret;
289}
290
Jagannadha Sutradharudu Teki25dc86a2013-10-02 19:38:49 +0530291int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530292 size_t len, void *data)
293{
294 u8 cmd[5], bank_sel = 0;
295 u32 remain_len, read_len;
296 int ret = -1;
297
298 /* Handle memory-mapped SPI */
299 if (flash->memory_map) {
Poddar, Sourav47e21e02013-11-14 21:01:15 +0530300 ret = spi_claim_bus(flash->spi);
301 if (ret) {
302 debug("SF: unable to claim SPI bus\n");
303 return ret;
304 }
Poddar, Souravdbbe68d2013-10-07 15:53:01 +0530305 spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP);
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530306 memcpy(data, flash->memory_map + offset, len);
Poddar, Souravdbbe68d2013-10-07 15:53:01 +0530307 spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
Poddar, Sourav47e21e02013-11-14 21:01:15 +0530308 spi_release_bus(flash->spi);
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530309 return 0;
310 }
311
Jagannadha Sutradharudu Teki02eee9a2014-01-11 15:10:28 +0530312 cmd[0] = flash->read_cmd;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530313 cmd[4] = 0x00;
314
315 while (len) {
316#ifdef CONFIG_SPI_FLASH_BAR
317 bank_sel = offset / SPI_FLASH_16MB_BOUN;
318
319 ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
320 if (ret) {
321 debug("SF: fail to set bank%d\n", bank_sel);
322 return ret;
323 }
324#endif
Jagannadha Sutradharudu Teki84fb8632013-10-10 22:14:09 +0530325 remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530326 if (len < remain_len)
327 read_len = len;
328 else
329 read_len = remain_len;
330
331 spi_flash_addr(offset, cmd);
332
333 ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
334 data, read_len);
335 if (ret < 0) {
336 debug("SF: read failed\n");
337 break;
338 }
339
340 offset += read_len;
341 len -= read_len;
342 data += read_len;
343 }
344
345 return ret;
346}
Jagannadha Sutradharudu Teki08032422013-10-02 19:34:53 +0530347
348#ifdef CONFIG_SPI_FLASH_SST
349static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
350{
351 int ret;
352 u8 cmd[4] = {
353 CMD_SST_BP,
354 offset >> 16,
355 offset >> 8,
356 offset,
357 };
358
359 debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
360 spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset);
361
362 ret = spi_flash_cmd_write_enable(flash);
363 if (ret)
364 return ret;
365
366 ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1);
367 if (ret)
368 return ret;
369
370 return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
371}
372
373int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
374 const void *buf)
375{
376 size_t actual, cmd_len;
377 int ret;
378 u8 cmd[4];
379
380 ret = spi_claim_bus(flash->spi);
381 if (ret) {
382 debug("SF: Unable to claim SPI bus\n");
383 return ret;
384 }
385
386 /* If the data is not word aligned, write out leading single byte */
387 actual = offset % 2;
388 if (actual) {
389 ret = sst_byte_write(flash, offset, buf);
390 if (ret)
391 goto done;
392 }
393 offset += actual;
394
395 ret = spi_flash_cmd_write_enable(flash);
396 if (ret)
397 goto done;
398
399 cmd_len = 4;
400 cmd[0] = CMD_SST_AAI_WP;
401 cmd[1] = offset >> 16;
402 cmd[2] = offset >> 8;
403 cmd[3] = offset;
404
405 for (; actual < len - 1; actual += 2) {
406 debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
407 spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual,
408 cmd[0], offset);
409
410 ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len,
411 buf + actual, 2);
412 if (ret) {
413 debug("SF: sst word program failed\n");
414 break;
415 }
416
417 ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
418 if (ret)
419 break;
420
421 cmd_len = 1;
422 offset += 2;
423 }
424
425 if (!ret)
426 ret = spi_flash_cmd_write_disable(flash);
427
428 /* If there is a single trailing byte, write it out */
429 if (!ret && actual != len)
430 ret = sst_byte_write(flash, offset, buf + actual);
431
432 done:
433 debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
434 ret ? "failure" : "success", len, offset - actual);
435
436 spi_release_bus(flash->spi);
437 return ret;
438}
439#endif