]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/spi/stmicro.c
rename CFG_ macros to CONFIG_SYS
[karo-tx-uboot.git] / 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 struct stmicro_spi_flash {
68         const struct stmicro_spi_flash_params *params;
69         struct spi_flash flash;
70 };
71
72 static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
73                                                              *flash)
74 {
75         return container_of(flash, struct stmicro_spi_flash, flash);
76 }
77
78 static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
79         {
80                 .idcode1 = STM_ID_M25P16,
81                 .page_size = 256,
82                 .pages_per_sector = 256,
83                 .nr_sectors = 32,
84                 .name = "M25P16",
85         },
86         {
87                 .idcode1 = STM_ID_M25P20,
88                 .page_size = 256,
89                 .pages_per_sector = 256,
90                 .nr_sectors = 4,
91                 .name = "M25P20",
92         },
93         {
94                 .idcode1 = STM_ID_M25P32,
95                 .page_size = 256,
96                 .pages_per_sector = 256,
97                 .nr_sectors = 64,
98                 .name = "M25P32",
99         },
100         {
101                 .idcode1 = STM_ID_M25P40,
102                 .page_size = 256,
103                 .pages_per_sector = 256,
104                 .nr_sectors = 8,
105                 .name = "M25P40",
106         },
107         {
108                 .idcode1 = STM_ID_M25P64,
109                 .page_size = 256,
110                 .pages_per_sector = 256,
111                 .nr_sectors = 128,
112                 .name = "M25P64",
113         },
114         {
115                 .idcode1 = STM_ID_M25P80,
116                 .page_size = 256,
117                 .pages_per_sector = 256,
118                 .nr_sectors = 16,
119                 .name = "M25P80",
120         },
121         {
122                 .idcode1 = STM_ID_M25P128,
123                 .page_size = 256,
124                 .pages_per_sector = 1024,
125                 .nr_sectors = 64,
126                 .name = "M25P128",
127         },
128 };
129
130 static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
131 {
132         struct spi_slave *spi = flash->spi;
133         unsigned long timebase;
134         int ret;
135         u8 status;
136         u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff };
137
138         ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN);
139         if (ret) {
140                 debug("SF: Failed to send command %02x: %d\n", cmd, ret);
141                 return ret;
142         }
143
144         timebase = get_timer(0);
145         do {
146                 ret = spi_xfer(spi, 8, NULL, &status, 0);
147                 if (ret)
148                         return -1;
149
150                 if ((status & STMICRO_SR_WIP) == 0)
151                         break;
152
153         } while (get_timer(timebase) < timeout);
154
155         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
156
157         if ((status & STMICRO_SR_WIP) == 0)
158                 return 0;
159
160         /* Timed out */
161         return -1;
162 }
163
164 static int stmicro_read_fast(struct spi_flash *flash,
165                              u32 offset, size_t len, void *buf)
166 {
167         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
168         unsigned long page_addr;
169         unsigned long page_size;
170         u8 cmd[5];
171
172         page_size = stm->params->page_size;
173         page_addr = offset / page_size;
174
175         cmd[0] = CMD_READ_ARRAY_FAST;
176         cmd[1] = page_addr >> 8;
177         cmd[2] = page_addr;
178         cmd[3] = offset % page_size;
179         cmd[4] = 0x00;
180
181         return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
182 }
183
184 static int stmicro_write(struct spi_flash *flash,
185                          u32 offset, size_t len, const void *buf)
186 {
187         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
188         unsigned long page_addr;
189         unsigned long byte_addr;
190         unsigned long page_size;
191         size_t chunk_len;
192         size_t actual;
193         int ret;
194         u8 cmd[4];
195
196         page_size = stm->params->page_size;
197         page_addr = offset / page_size;
198         byte_addr = offset % page_size;
199
200         ret = spi_claim_bus(flash->spi);
201         if (ret) {
202                 debug("SF: Unable to claim SPI bus\n");
203                 return ret;
204         }
205
206         ret = 0;
207         for (actual = 0; actual < len; actual += chunk_len) {
208                 chunk_len = min(len - actual, page_size - byte_addr);
209
210                 cmd[0] = CMD_M25PXX_PP;
211                 cmd[1] = page_addr >> 8;
212                 cmd[2] = page_addr;
213                 cmd[3] = byte_addr;
214
215                 debug
216                     ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
217                      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
218
219                 ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
220                 if (ret < 0) {
221                         debug("SF: Enabling Write failed\n");
222                         break;
223                 }
224
225                 ret = spi_flash_cmd_write(flash->spi, cmd, 4,
226                                           buf + actual, chunk_len);
227                 if (ret < 0) {
228                         debug("SF: STMicro Page Program failed\n");
229                         break;
230                 }
231
232                 ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
233                 if (ret < 0) {
234                         debug("SF: STMicro page programming timed out\n");
235                         break;
236                 }
237
238                 page_addr++;
239                 byte_addr = 0;
240         }
241
242         debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n",
243               len, offset);
244
245         spi_release_bus(flash->spi);
246         return ret;
247 }
248
249 int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
250 {
251         struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
252         unsigned long sector_size;
253         size_t actual;
254         int ret;
255         u8 cmd[4];
256
257         /*
258          * This function currently uses sector erase only.
259          * probably speed things up by using bulk erase
260          * when possible.
261          */
262
263         sector_size = stm->params->page_size * stm->params->pages_per_sector;
264
265         if (offset % sector_size || len % sector_size) {
266                 debug("SF: Erase offset/length not multiple of sector size\n");
267                 return -1;
268         }
269
270         len /= sector_size;
271         cmd[0] = CMD_M25PXX_SE;
272         cmd[2] = 0x00;
273         cmd[3] = 0x00;
274
275         ret = spi_claim_bus(flash->spi);
276         if (ret) {
277                 debug("SF: Unable to claim SPI bus\n");
278                 return ret;
279         }
280
281         ret = 0;
282         for (actual = 0; actual < len; actual++) {
283                 cmd[1] = (offset / sector_size) + actual;
284
285                 ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
286                 if (ret < 0) {
287                         debug("SF: Enabling Write failed\n");
288                         break;
289                 }
290
291                 ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
292                 if (ret < 0) {
293                         debug("SF: STMicro page erase failed\n");
294                         break;
295                 }
296
297                 /* Up to 2 seconds */
298                 ret = stmicro_wait_ready(flash, 2 * CONFIG_SYS_HZ);
299                 if (ret < 0) {
300                         debug("SF: STMicro page erase timed out\n");
301                         break;
302                 }
303         }
304
305         debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
306               len * sector_size, offset);
307
308         spi_release_bus(flash->spi);
309         return ret;
310 }
311
312 struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
313 {
314         const struct stmicro_spi_flash_params *params;
315         struct stmicro_spi_flash *stm;
316         unsigned int i;
317         int ret;
318         u8 id[3];
319
320         ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
321         if (ret)
322                 return NULL;
323
324         for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) {
325                 params = &stmicro_spi_flash_table[i];
326                 if (params->idcode1 == idcode[2]) {
327                         break;
328                 }
329         }
330
331         if (i == ARRAY_SIZE(stmicro_spi_flash_table)) {
332                 debug("SF: Unsupported STMicro ID %02x\n", id[1]);
333                 return NULL;
334         }
335
336         stm = malloc(sizeof(struct stmicro_spi_flash));
337         if (!stm) {
338                 debug("SF: Failed to allocate memory\n");
339                 return NULL;
340         }
341
342         stm->params = params;
343         stm->flash.spi = spi;
344         stm->flash.name = params->name;
345
346         stm->flash.write = stmicro_write;
347         stm->flash.erase = stmicro_erase;
348         stm->flash.read = stmicro_read_fast;
349         stm->flash.size = params->page_size * params->pages_per_sector
350             * params->nr_sectors;
351
352         debug("SF: Detected %s with page size %u, total %u bytes\n",
353               params->name, params->page_size, stm->flash.size);
354
355         return &stm->flash;
356 }