]> git.sur5r.net Git - u-boot/blob - drivers/mtd/spi/atmel.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc83xx
[u-boot] / drivers / mtd / spi / atmel.c
1 /*
2  * Atmel SPI DataFlash support
3  *
4  * Copyright (C) 2008 Atmel Corporation
5  */
6 #define DEBUG
7 #include <common.h>
8 #include <malloc.h>
9 #include <spi_flash.h>
10
11 #include "spi_flash_internal.h"
12
13 /* AT45-specific commands */
14 #define CMD_AT45_READ_STATUS            0xd7
15 #define CMD_AT45_ERASE_PAGE             0x81
16 #define CMD_AT45_LOAD_PROG_BUF1         0x82
17 #define CMD_AT45_LOAD_BUF1              0x84
18 #define CMD_AT45_LOAD_PROG_BUF2         0x85
19 #define CMD_AT45_LOAD_BUF2              0x87
20 #define CMD_AT45_PROG_BUF1              0x88
21 #define CMD_AT45_PROG_BUF2              0x89
22
23 /* AT45 status register bits */
24 #define AT45_STATUS_P2_PAGE_SIZE        (1 << 0)
25 #define AT45_STATUS_READY               (1 << 7)
26
27 /* DataFlash family IDs, as obtained from the second idcode byte */
28 #define DF_FAMILY_AT26F                 0
29 #define DF_FAMILY_AT45                  1
30 #define DF_FAMILY_AT26DF                2       /* AT25DF and AT26DF */
31
32 struct atmel_spi_flash_params {
33         u8              idcode1;
34         /* Log2 of page size in power-of-two mode */
35         u8              l2_page_size;
36         u8              pages_per_block;
37         u8              blocks_per_sector;
38         u8              nr_sectors;
39         const char      *name;
40 };
41
42 /* spi_flash needs to be first so upper layers can free() it */
43 struct atmel_spi_flash {
44         struct spi_flash flash;
45         const struct atmel_spi_flash_params *params;
46 };
47
48 static inline struct atmel_spi_flash *
49 to_atmel_spi_flash(struct spi_flash *flash)
50 {
51         return container_of(flash, struct atmel_spi_flash, flash);
52 }
53
54 static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
55         {
56                 .idcode1                = 0x28,
57                 .l2_page_size           = 10,
58                 .pages_per_block        = 8,
59                 .blocks_per_sector      = 32,
60                 .nr_sectors             = 32,
61                 .name                   = "AT45DB642D",
62         },
63 };
64
65 static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout)
66 {
67         struct spi_slave *spi = flash->spi;
68         unsigned long timebase;
69         int ret;
70         u8 cmd = CMD_AT45_READ_STATUS;
71         u8 status;
72
73         timebase = get_timer(0);
74
75         ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
76         if (ret)
77                 return -1;
78
79         do {
80                 ret = spi_xfer(spi, 8, NULL, &status, 0);
81                 if (ret)
82                         return -1;
83
84                 if (status & AT45_STATUS_READY)
85                         break;
86         } while (get_timer(timebase) < timeout);
87
88         /* Deactivate CS */
89         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
90
91         if (status & AT45_STATUS_READY)
92                 return 0;
93
94         /* Timed out */
95         return -1;
96 }
97
98 /*
99  * Assemble the address part of a command for AT45 devices in
100  * non-power-of-two page size mode.
101  */
102 static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset)
103 {
104         unsigned long page_addr;
105         unsigned long byte_addr;
106         unsigned long page_size;
107         unsigned int page_shift;
108
109         /*
110          * The "extra" space per page is the power-of-two page size
111          * divided by 32.
112          */
113         page_shift = asf->params->l2_page_size;
114         page_size = (1 << page_shift) + (1 << (page_shift - 5));
115         page_shift++;
116         page_addr = offset / page_size;
117         byte_addr = offset % page_size;
118
119         cmd[0] = page_addr >> (16 - page_shift);
120         cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8);
121         cmd[2] = byte_addr;
122 }
123
124 static int dataflash_read_fast_p2(struct spi_flash *flash,
125                 u32 offset, size_t len, void *buf)
126 {
127         u8 cmd[5];
128
129         cmd[0] = CMD_READ_ARRAY_FAST;
130         cmd[1] = offset >> 16;
131         cmd[2] = offset >> 8;
132         cmd[3] = offset;
133         cmd[4] = 0x00;
134
135         return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
136 }
137
138 static int dataflash_read_fast_at45(struct spi_flash *flash,
139                 u32 offset, size_t len, void *buf)
140 {
141         struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
142         u8 cmd[5];
143
144         cmd[0] = CMD_READ_ARRAY_FAST;
145         at45_build_address(asf, cmd + 1, offset);
146         cmd[4] = 0x00;
147
148         return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
149 }
150
151 static int dataflash_write_at45(struct spi_flash *flash,
152                 u32 offset, size_t len, const void *buf)
153 {
154         struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
155         unsigned long page_addr;
156         unsigned long byte_addr;
157         unsigned long page_size;
158         unsigned int page_shift;
159         size_t chunk_len;
160         size_t actual;
161         int ret;
162         u8 cmd[4];
163
164         page_shift = asf->params->l2_page_size;
165         page_size = (1 << page_shift) + (1 << (page_shift - 5));
166         page_shift++;
167         page_addr = offset / page_size;
168         byte_addr = offset % page_size;
169
170         ret = spi_claim_bus(flash->spi);
171         if (ret) {
172                 debug("SF: Unable to claim SPI bus\n");
173                 return ret;
174         }
175
176         for (actual = 0; actual < len; actual += chunk_len) {
177                 chunk_len = min(len - actual, page_size - byte_addr);
178
179                 /* Use the same address bits for both commands */
180                 cmd[0] = CMD_AT45_LOAD_BUF1;
181                 cmd[1] = page_addr >> (16 - page_shift);
182                 cmd[2] = page_addr << (page_shift - 8) | (byte_addr >> 8);
183                 cmd[3] = byte_addr;
184
185                 ret = spi_flash_cmd_write(flash->spi, cmd, 4,
186                                 buf + actual, chunk_len);
187                 if (ret < 0) {
188                         debug("SF: Loading AT45 buffer failed\n");
189                         goto out;
190                 }
191
192                 cmd[0] = CMD_AT45_PROG_BUF1;
193                 ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
194                 if (ret < 0) {
195                         debug("SF: AT45 page programming failed\n");
196                         goto out;
197                 }
198
199                 ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
200                 if (ret < 0) {
201                         debug("SF: AT45 page programming timed out\n");
202                         goto out;
203                 }
204
205                 page_addr++;
206                 byte_addr = 0;
207         }
208
209         debug("SF: AT45: Successfully programmed %zu bytes @ 0x%x\n",
210                         len, offset);
211         ret = 0;
212
213 out:
214         spi_release_bus(flash->spi);
215         return ret;
216 }
217
218 int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len)
219 {
220         struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
221         unsigned long page_addr;
222         unsigned long page_size;
223         unsigned int page_shift;
224         size_t actual;
225         int ret;
226         u8 cmd[4];
227
228         /*
229          * TODO: This function currently uses page erase only. We can
230          * probably speed things up by using block and/or sector erase
231          * when possible.
232          */
233
234         page_shift = asf->params->l2_page_size;
235         page_size = (1 << page_shift) + (1 << (page_shift - 5));
236         page_shift++;
237         page_addr = offset / page_size;
238
239         if (offset % page_size || len % page_size) {
240                 debug("SF: Erase offset/length not multiple of page size\n");
241                 return -1;
242         }
243
244         cmd[0] = CMD_AT45_ERASE_PAGE;
245         cmd[3] = 0x00;
246
247         ret = spi_claim_bus(flash->spi);
248         if (ret) {
249                 debug("SF: Unable to claim SPI bus\n");
250                 return ret;
251         }
252
253         for (actual = 0; actual < len; actual += page_size) {
254                 cmd[1] = page_addr >> (16 - page_shift);
255                 cmd[2] = page_addr << (page_shift - 8);
256
257                 ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
258                 if (ret < 0) {
259                         debug("SF: AT45 page erase failed\n");
260                         goto out;
261                 }
262
263                 ret = at45_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
264                 if (ret < 0) {
265                         debug("SF: AT45 page erase timed out\n");
266                         goto out;
267                 }
268
269                 page_addr++;
270         }
271
272         debug("SF: AT45: Successfully erased %zu bytes @ 0x%x\n",
273                         len, offset);
274         ret = 0;
275
276 out:
277         spi_release_bus(flash->spi);
278         return ret;
279 }
280
281 struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
282 {
283         const struct atmel_spi_flash_params *params;
284         unsigned long page_size;
285         unsigned int family;
286         struct atmel_spi_flash *asf;
287         unsigned int i;
288         int ret;
289         u8 status;
290
291         for (i = 0; i < ARRAY_SIZE(atmel_spi_flash_table); i++) {
292                 params = &atmel_spi_flash_table[i];
293                 if (params->idcode1 == idcode[1])
294                         break;
295         }
296
297         if (i == ARRAY_SIZE(atmel_spi_flash_table)) {
298                 debug("SF: Unsupported DataFlash ID %02x\n",
299                                 idcode[1]);
300                 return NULL;
301         }
302
303         asf = malloc(sizeof(struct atmel_spi_flash));
304         if (!asf) {
305                 debug("SF: Failed to allocate memory\n");
306                 return NULL;
307         }
308
309         asf->params = params;
310         asf->flash.spi = spi;
311         asf->flash.name = params->name;
312
313         /* Assuming power-of-two page size initially. */
314         page_size = 1 << params->l2_page_size;
315
316         family = idcode[1] >> 5;
317
318         switch (family) {
319         case DF_FAMILY_AT45:
320                 /*
321                  * AT45 chips have configurable page size. The status
322                  * register indicates which configuration is active.
323                  */
324                 ret = spi_flash_cmd(spi, CMD_AT45_READ_STATUS, &status, 1);
325                 if (ret)
326                         goto err;
327
328                 debug("SF: AT45 status register: %02x\n", status);
329
330                 if (!(status & AT45_STATUS_P2_PAGE_SIZE)) {
331                         asf->flash.read = dataflash_read_fast_at45;
332                         asf->flash.write = dataflash_write_at45;
333                         asf->flash.erase = dataflash_erase_at45;
334                         page_size += 1 << (params->l2_page_size - 5);
335                 } else {
336                         asf->flash.read = dataflash_read_fast_p2;
337                 }
338
339                 break;
340
341         case DF_FAMILY_AT26F:
342         case DF_FAMILY_AT26DF:
343                 asf->flash.read = dataflash_read_fast_p2;
344                 break;
345
346         default:
347                 debug("SF: Unsupported DataFlash family %u\n", family);
348                 goto err;
349         }
350
351         asf->flash.size = page_size * params->pages_per_block
352                                 * params->blocks_per_sector
353                                 * params->nr_sectors;
354
355         debug("SF: Detected %s with page size %lu, total %u bytes\n",
356                         params->name, page_size, asf->flash.size);
357
358         return &asf->flash;
359
360 err:
361         free(asf);
362         return NULL;
363 }