]> git.sur5r.net Git - u-boot/blob - drivers/mtd/spi/stmicro.c
Merge branch 'mimc200' into next
[u-boot] / drivers / mtd / spi / stmicro.c
1 /*
2  * (C) Copyright 2000-2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Copyright 2008, Network Appliance Inc.
6  * Jason McMullan <mcmullan@netapp.com>
7  *
8  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
9  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of
17  * the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27  * MA 02111-1307 USA
28  */
29
30 #include <common.h>
31 #include <malloc.h>
32 #include <spi_flash.h>
33
34 #include "spi_flash_internal.h"
35
36 /* M25Pxx-specific commands */
37 #define CMD_M25PXX_WREN         0x06    /* Write Enable */
38 #define CMD_M25PXX_WRDI         0x04    /* Write Disable */
39 #define CMD_M25PXX_RDSR         0x05    /* Read Status Register */
40 #define CMD_M25PXX_WRSR         0x01    /* Write Status Register */
41 #define CMD_M25PXX_READ         0x03    /* Read Data Bytes */
42 #define CMD_M25PXX_FAST_READ    0x0b    /* Read Data Bytes at Higher Speed */
43 #define CMD_M25PXX_PP           0x02    /* Page Program */
44 #define CMD_M25PXX_SE           0xd8    /* Sector Erase */
45 #define CMD_M25PXX_BE           0xc7    /* Bulk Erase */
46 #define CMD_M25PXX_DP           0xb9    /* Deep Power-down */
47 #define CMD_M25PXX_RES          0xab    /* Release from DP, and Read Signature */
48
49 #define STM_ID_M25P16           0x15
50 #define STM_ID_M25P20           0x12
51 #define STM_ID_M25P32           0x16
52 #define STM_ID_M25P40           0x13
53 #define STM_ID_M25P64           0x17
54 #define STM_ID_M25P80           0x14
55 #define STM_ID_M25P128          0x18
56
57 #define STMICRO_SR_WIP          (1 << 0)        /* Write-in-Progress */
58
59 struct stmicro_spi_flash_params {
60         u8 idcode1;
61         u16 page_size;
62         u16 pages_per_sector;
63         u16 nr_sectors;
64         const char *name;
65 };
66
67 /* spi_flash needs to be first so upper layers can free() it */
68 struct stmicro_spi_flash {
69         struct spi_flash flash;
70         const struct stmicro_spi_flash_params *params;
71 };
72
73 static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
74                                                              *flash)
75 {
76         return container_of(flash, struct stmicro_spi_flash, flash);
77 }
78
79 static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
80         {
81                 .idcode1 = STM_ID_M25P16,
82                 .page_size = 256,
83                 .pages_per_sector = 256,
84                 .nr_sectors = 32,
85                 .name = "M25P16",
86         },
87         {
88                 .idcode1 = STM_ID_M25P20,
89                 .page_size = 256,
90                 .pages_per_sector = 256,
91                 .nr_sectors = 4,
92                 .name = "M25P20",
93         },
94         {
95                 .idcode1 = STM_ID_M25P32,
96                 .page_size = 256,
97                 .pages_per_sector = 256,
98                 .nr_sectors = 64,
99                 .name = "M25P32",
100         },
101         {
102                 .idcode1 = STM_ID_M25P40,
103                 .page_size = 256,
104                 .pages_per_sector = 256,
105                 .nr_sectors = 8,
106                 .name = "M25P40",
107         },
108         {
109                 .idcode1 = STM_ID_M25P64,
110                 .page_size = 256,
111                 .pages_per_sector = 256,
112                 .nr_sectors = 128,
113                 .name = "M25P64",
114         },
115         {
116                 .idcode1 = STM_ID_M25P80,
117                 .page_size = 256,
118                 .pages_per_sector = 256,
119                 .nr_sectors = 16,
120                 .name = "M25P80",
121         },
122         {
123                 .idcode1 = STM_ID_M25P128,
124                 .page_size = 256,
125                 .pages_per_sector = 1024,
126                 .nr_sectors = 64,
127                 .name = "M25P128",
128         },
129 };
130
131 static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
132 {
133         struct spi_slave *spi = flash->spi;
134         unsigned long timebase;
135         int ret;
136         u8 status;
137         u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff };
138
139         ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN);
140         if (ret) {
141                 debug("SF: Failed to send command %02x: %d\n", cmd[0], ret);
142                 return ret;
143         }
144
145         timebase = get_timer(0);
146         do {
147                 ret = spi_xfer(spi, 8, NULL, &status, 0);
148                 if (ret)
149                         return -1;
150
151                 if ((status & STMICRO_SR_WIP) == 0)
152                         break;
153
154         } while (get_timer(timebase) < timeout);
155
156         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
157
158         if ((status & STMICRO_SR_WIP) == 0)
159                 return 0;
160
161         /* Timed out */
162         return -1;
163 }
164
165 static int stmicro_read_fast(struct spi_flash *flash,
166                              u32 offset, size_t len, void *buf)
167 {
168         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
169         unsigned long page_addr;
170         unsigned long page_size;
171         u8 cmd[5];
172
173         page_size = stm->params->page_size;
174         page_addr = offset / page_size;
175
176         cmd[0] = CMD_READ_ARRAY_FAST;
177         cmd[1] = page_addr >> 8;
178         cmd[2] = page_addr;
179         cmd[3] = offset % page_size;
180         cmd[4] = 0x00;
181
182         return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
183 }
184
185 static int stmicro_write(struct spi_flash *flash,
186                          u32 offset, size_t len, const void *buf)
187 {
188         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
189         unsigned long page_addr;
190         unsigned long byte_addr;
191         unsigned long page_size;
192         size_t chunk_len;
193         size_t actual;
194         int ret;
195         u8 cmd[4];
196
197         page_size = stm->params->page_size;
198         page_addr = offset / page_size;
199         byte_addr = offset % page_size;
200
201         ret = spi_claim_bus(flash->spi);
202         if (ret) {
203                 debug("SF: Unable to claim SPI bus\n");
204                 return ret;
205         }
206
207         ret = 0;
208         for (actual = 0; actual < len; actual += chunk_len) {
209                 chunk_len = min(len - actual, page_size - byte_addr);
210
211                 cmd[0] = CMD_M25PXX_PP;
212                 cmd[1] = page_addr >> 8;
213                 cmd[2] = page_addr;
214                 cmd[3] = byte_addr;
215
216                 debug
217                     ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
218                      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
219
220                 ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
221                 if (ret < 0) {
222                         debug("SF: Enabling Write failed\n");
223                         break;
224                 }
225
226                 ret = spi_flash_cmd_write(flash->spi, cmd, 4,
227                                           buf + actual, chunk_len);
228                 if (ret < 0) {
229                         debug("SF: STMicro Page Program failed\n");
230                         break;
231                 }
232
233                 ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
234                 if (ret < 0) {
235                         debug("SF: STMicro page programming timed out\n");
236                         break;
237                 }
238
239                 page_addr++;
240                 byte_addr = 0;
241         }
242
243         debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n",
244               len, offset);
245
246         spi_release_bus(flash->spi);
247         return ret;
248 }
249
250 int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
251 {
252         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
253         unsigned long sector_size;
254         size_t actual;
255         int ret;
256         u8 cmd[4];
257
258         /*
259          * This function currently uses sector erase only.
260          * probably speed things up by using bulk erase
261          * when possible.
262          */
263
264         sector_size = stm->params->page_size * stm->params->pages_per_sector;
265
266         if (offset % sector_size || len % sector_size) {
267                 debug("SF: Erase offset/length not multiple of sector size\n");
268                 return -1;
269         }
270
271         len /= sector_size;
272         cmd[0] = CMD_M25PXX_SE;
273         cmd[2] = 0x00;
274         cmd[3] = 0x00;
275
276         ret = spi_claim_bus(flash->spi);
277         if (ret) {
278                 debug("SF: Unable to claim SPI bus\n");
279                 return ret;
280         }
281
282         ret = 0;
283         for (actual = 0; actual < len; actual++) {
284                 cmd[1] = (offset / sector_size) + actual;
285
286                 ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
287                 if (ret < 0) {
288                         debug("SF: Enabling Write failed\n");
289                         break;
290                 }
291
292                 ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
293                 if (ret < 0) {
294                         debug("SF: STMicro page erase failed\n");
295                         break;
296                 }
297
298                 /* Up to 2 seconds */
299                 ret = stmicro_wait_ready(flash, 2 * CONFIG_SYS_HZ);
300                 if (ret < 0) {
301                         debug("SF: STMicro page erase timed out\n");
302                         break;
303                 }
304         }
305
306         debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
307               len * sector_size, offset);
308
309         spi_release_bus(flash->spi);
310         return ret;
311 }
312
313 struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
314 {
315         const struct stmicro_spi_flash_params *params;
316         struct stmicro_spi_flash *stm;
317         unsigned int i;
318         int ret;
319         u8 id[3];
320
321         ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
322         if (ret)
323                 return NULL;
324
325         for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) {
326                 params = &stmicro_spi_flash_table[i];
327                 if (params->idcode1 == idcode[2]) {
328                         break;
329                 }
330         }
331
332         if (i == ARRAY_SIZE(stmicro_spi_flash_table)) {
333                 debug("SF: Unsupported STMicro ID %02x\n", id[1]);
334                 return NULL;
335         }
336
337         stm = malloc(sizeof(struct stmicro_spi_flash));
338         if (!stm) {
339                 debug("SF: Failed to allocate memory\n");
340                 return NULL;
341         }
342
343         stm->params = params;
344         stm->flash.spi = spi;
345         stm->flash.name = params->name;
346
347         stm->flash.write = stmicro_write;
348         stm->flash.erase = stmicro_erase;
349         stm->flash.read = stmicro_read_fast;
350         stm->flash.size = params->page_size * params->pages_per_sector
351             * params->nr_sectors;
352
353         debug("SF: Detected %s with page size %u, total %u bytes\n",
354               params->name, params->page_size, stm->flash.size);
355
356         return &stm->flash;
357 }