blob: aab654c641d846515617cd13c418148533d28972 [file] [log] [blame]
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -07001/*
2 * Driver for SST serial flashes
3 *
4 * (C) Copyright 2000-2002
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6 * Copyright 2008, Network Appliance Inc.
7 * Jason McMullan <mcmullan@netapp.com>
8 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
9 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
10 * Copyright (c) 2008-2009 Analog Devices Inc.
11 *
12 * Licensed under the GPL-2 or later.
13 */
14
15#include <stdlib.h>
16#include <spi_flash.h>
Edward O'Callaghanc4561e22014-06-26 15:02:40 +100017
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070018#include "spi_flash_internal.h"
19
20#define CMD_SST_WREN 0x06 /* Write Enable */
21#define CMD_SST_WRDI 0x04 /* Write Disable */
22#define CMD_SST_RDSR 0x05 /* Read Status Register */
23#define CMD_SST_WRSR 0x01 /* Write Status Register */
Zheng Baob8117b02012-11-27 18:08:53 +080024#define CMD_SST_EWSR 0x50 /* Enable Write Status Register */
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070025#define CMD_SST_READ 0x03 /* Read Data Bytes */
26#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
27#define CMD_SST_BP 0x02 /* Byte Program */
28#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */
29#define CMD_SST_SE 0x20 /* Sector Erase */
30
31#define SST_SR_WIP (1 << 0) /* Write-in-Progress */
32#define SST_SR_WEL (1 << 1) /* Write enable */
33#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */
34#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */
35#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */
36#define SST_SR_AAI (1 << 6) /* Addressing mode */
37#define SST_SR_BPL (1 << 7) /* BP bits lock */
38
39struct sst_spi_flash_params {
40 u8 idcode1;
41 u16 nr_sectors;
42 const char *name;
43};
44
45struct sst_spi_flash {
46 struct spi_flash flash;
47 const struct sst_spi_flash_params *params;
48};
49
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070050#define SST_SECTOR_SIZE (4 * 1024)
51static const struct sst_spi_flash_params sst_spi_flash_table[] = {
52 {
53 .idcode1 = 0x8d,
54 .nr_sectors = 128,
55 .name = "SST25VF040B",
56 },{
57 .idcode1 = 0x8e,
58 .nr_sectors = 256,
59 .name = "SST25VF080B",
60 },{
61 .idcode1 = 0x41,
62 .nr_sectors = 512,
63 .name = "SST25VF016B",
64 },{
65 .idcode1 = 0x4a,
66 .nr_sectors = 1024,
67 .name = "SST25VF032B",
68 },{
69 .idcode1 = 0x4b,
70 .nr_sectors = 2048,
71 .name = "SST25VF064C",
72 },{
73 .idcode1 = 0x01,
74 .nr_sectors = 16,
75 .name = "SST25WF512",
76 },{
77 .idcode1 = 0x02,
78 .nr_sectors = 32,
79 .name = "SST25WF010",
80 },{
81 .idcode1 = 0x03,
82 .nr_sectors = 64,
83 .name = "SST25WF020",
84 },{
85 .idcode1 = 0x04,
86 .nr_sectors = 128,
87 .name = "SST25WF040",
88 },
89};
90
91static int
92sst_enable_writing(struct spi_flash *flash)
93{
94 int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0);
95 if (ret)
96 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
97 return ret;
98}
99
100static int
Zheng Baob8117b02012-11-27 18:08:53 +0800101sst_enable_writing_status(struct spi_flash *flash)
102{
103 int ret = spi_flash_cmd(flash->spi, CMD_SST_EWSR, NULL, 0);
104 if (ret)
105 printk(BIOS_WARNING, "SF: Enabling Write Status failed\n");
106 return ret;
107}
108
109static int
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700110sst_disable_writing(struct spi_flash *flash)
111{
112 int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0);
113 if (ret)
114 printk(BIOS_WARNING, "SF: Disabling Write failed\n");
115 return ret;
116}
117
118static int
119sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
120{
121 int ret;
122 u8 cmd[4] = {
123 CMD_SST_BP,
124 offset >> 16,
125 offset >> 8,
126 offset,
127 };
128
Marc Jones747127d2012-12-03 22:16:29 -0700129#if CONFIG_DEBUG_SPI_FLASH
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700130 printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
131 spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset);
Marc Jones747127d2012-12-03 22:16:29 -0700132#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700133
134 ret = sst_enable_writing(flash);
135 if (ret)
136 return ret;
137
138 ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1);
139 if (ret)
140 return ret;
141
142 return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
143}
144
145static int
146sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
147{
148 size_t actual, cmd_len;
David Hendricks032c8432014-04-11 19:48:55 -0700149 int ret = 0;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700150 u8 cmd[4];
151
Martin Roth3316cf22012-12-05 16:22:54 -0700152 flash->spi->rw = SPI_WRITE_FLAG;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700153
154 /* If the data is not word aligned, write out leading single byte */
155 actual = offset % 2;
156 if (actual) {
157 ret = sst_byte_write(flash, offset, buf);
158 if (ret)
159 goto done;
160 }
161 offset += actual;
162
163 ret = sst_enable_writing(flash);
164 if (ret)
165 goto done;
166
167 cmd_len = 4;
168 cmd[0] = CMD_SST_AAI_WP;
169 cmd[1] = offset >> 16;
170 cmd[2] = offset >> 8;
171 cmd[3] = offset;
172
173 for (; actual < len - 1; actual += 2) {
Marc Jones747127d2012-12-03 22:16:29 -0700174#if CONFIG_DEBUG_SPI_FLASH
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700175 printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
176 spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0],
177 offset);
Marc Jones747127d2012-12-03 22:16:29 -0700178#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700179
180 ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len,
181 buf + actual, 2);
182 if (ret) {
183 printk(BIOS_WARNING, "SF: SST word program failed\n");
184 break;
185 }
186
187 ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
188 if (ret)
189 break;
190
191 cmd_len = 1;
192 offset += 2;
193 }
194
195 if (!ret)
196 ret = sst_disable_writing(flash);
197
198 /* If there is a single trailing byte, write it out */
199 if (!ret && actual != len)
200 ret = sst_byte_write(flash, offset, buf + actual);
201
Patrick Georgi20959ba2012-05-12 23:30:36 +0200202done:
Marc Jones747127d2012-12-03 22:16:29 -0700203#if CONFIG_DEBUG_SPI_FLASH
204 printk(BIOS_SPEW, "SF: SST: program %s %zu bytes @ 0x%lx\n",
Stefan Reinauer8ea5a342012-05-14 13:52:32 -0700205 ret ? "failure" : "success", len, (unsigned long)offset - actual);
Marc Jones747127d2012-12-03 22:16:29 -0700206#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700207 return ret;
208}
209
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700210
211static int
212sst_unlock(struct spi_flash *flash)
213{
214 int ret;
215 u8 cmd, status;
216
Zheng Baob8117b02012-11-27 18:08:53 +0800217 ret = sst_enable_writing_status(flash);
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700218 if (ret)
219 return ret;
220
221 cmd = CMD_SST_WRSR;
222 status = 0;
223 ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1);
224 if (ret)
225 printk(BIOS_WARNING, "SF: Unable to set status byte\n");
226
227 printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR));
228
229 return ret;
230}
231
232struct spi_flash *
233spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode)
234{
235 const struct sst_spi_flash_params *params;
236 struct sst_spi_flash *stm;
237 size_t i;
238
239 for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) {
240 params = &sst_spi_flash_table[i];
241 if (params->idcode1 == idcode[2])
242 break;
243 }
244
245 if (i == ARRAY_SIZE(sst_spi_flash_table)) {
246 printk(BIOS_WARNING, "SF: Unsupported SST ID %02x\n", idcode[1]);
247 return NULL;
248 }
249
250 stm = malloc(sizeof(*stm));
251 if (!stm) {
252 printk(BIOS_WARNING, "SF: Failed to allocate memory\n");
253 return NULL;
254 }
255
256 stm->params = params;
257 stm->flash.spi = spi;
258 stm->flash.name = params->name;
259
260 stm->flash.write = sst_write;
Dan Ehrenberga5aac762015-01-08 10:29:19 -0800261 stm->flash.erase = spi_flash_cmd_erase;
Duncan Lauriefb032392015-01-15 15:28:46 -0800262 stm->flash.status = spi_flash_cmd_status;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700263 stm->flash.read = spi_flash_cmd_read_fast;
264 stm->flash.sector_size = SST_SECTOR_SIZE;
265 stm->flash.size = stm->flash.sector_size * params->nr_sectors;
Dan Ehrenberga5aac762015-01-08 10:29:19 -0800266 stm->flash.erase_cmd = CMD_SST_SE;
Duncan Lauriefb032392015-01-15 15:28:46 -0800267 stm->flash.status_cmd = CMD_SST_RDSR;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700268
269 /* Flash powers up read-only, so clear BP# bits */
270 sst_unlock(&stm->flash);
271
272 return &stm->flash;
273}