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