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