{drivers,southbridge}: Replace min() with MIN()
[coreboot.git] / src / drivers / spi / sst.c
blob6223cf98da80176c1f2f385baf44b7a0032e951b
1 /*
2 * This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 * Driver for SST serial flashes
19 #include <console/console.h>
20 #include <commonlib/helpers.h>
21 #include <spi_flash.h>
22 #include <spi-generic.h>
23 #include <string.h>
25 #include "spi_flash_internal.h"
27 #define CMD_SST_WREN 0x06 /* Write Enable */
28 #define CMD_SST_WRDI 0x04 /* Write Disable */
29 #define CMD_SST_RDSR 0x05 /* Read Status Register */
30 #define CMD_SST_WRSR 0x01 /* Write Status Register */
31 #define CMD_SST_EWSR 0x50 /* Enable Write Status Register */
32 #define CMD_SST_READ 0x03 /* Read Data Bytes */
33 #define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
34 #define CMD_SST_BP 0x02 /* Byte Program */
35 #define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */
36 #define CMD_SST_SE 0x20 /* Sector Erase */
38 #define SST_SR_WIP (1 << 0) /* Write-in-Progress */
39 #define SST_SR_WEL (1 << 1) /* Write enable */
40 #define SST_SR_BP0 (1 << 2) /* Block Protection 0 */
41 #define SST_SR_BP1 (1 << 3) /* Block Protection 1 */
42 #define SST_SR_BP2 (1 << 4) /* Block Protection 2 */
43 #define SST_SR_AAI (1 << 6) /* Addressing mode */
44 #define SST_SR_BPL (1 << 7) /* BP bits lock */
46 struct sst_spi_flash_params {
47 u8 idcode1;
48 u16 nr_sectors;
49 const char *name;
50 const struct spi_flash_ops *ops;
53 static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len,
54 const void *buf);
55 static int sst_write_256(const struct spi_flash *flash, u32 offset, size_t len,
56 const void *buf);
58 static const struct spi_flash_ops spi_flash_ops_write_ai = {
59 .write = sst_write_ai,
60 .erase = spi_flash_cmd_erase,
61 .status = spi_flash_cmd_status,
64 static const struct spi_flash_ops spi_flash_ops_write_256 = {
65 .write = sst_write_256,
66 .erase = spi_flash_cmd_erase,
67 .status = spi_flash_cmd_status,
70 #define SST_SECTOR_SIZE (4 * 1024)
71 static const struct sst_spi_flash_params sst_spi_flash_table[] = {
73 .idcode1 = 0x8d,
74 .nr_sectors = 128,
75 .name = "SST25VF040B",
76 .ops = &spi_flash_ops_write_ai,
77 },{
78 .idcode1 = 0x8e,
79 .nr_sectors = 256,
80 .name = "SST25VF080B",
81 .ops = &spi_flash_ops_write_ai,
82 },{
83 .idcode1 = 0x80,
84 .nr_sectors = 256,
85 .name = "SST25VF080",
86 .ops = &spi_flash_ops_write_ai,
87 },{
88 .idcode1 = 0x41,
89 .nr_sectors = 512,
90 .name = "SST25VF016B",
91 .ops = &spi_flash_ops_write_ai,
92 },{
93 .idcode1 = 0x4a,
94 .nr_sectors = 1024,
95 .name = "SST25VF032B",
96 .ops = &spi_flash_ops_write_ai,
97 },{
98 .idcode1 = 0x4b,
99 .nr_sectors = 2048,
100 .name = "SST25VF064C",
101 .ops = &spi_flash_ops_write_256,
103 .idcode1 = 0x01,
104 .nr_sectors = 16,
105 .name = "SST25WF512",
106 .ops = &spi_flash_ops_write_ai,
108 .idcode1 = 0x02,
109 .nr_sectors = 32,
110 .name = "SST25WF010",
111 .ops = &spi_flash_ops_write_ai,
113 .idcode1 = 0x03,
114 .nr_sectors = 64,
115 .name = "SST25WF020",
116 .ops = &spi_flash_ops_write_ai,
118 .idcode1 = 0x04,
119 .nr_sectors = 128,
120 .name = "SST25WF040",
121 .ops = &spi_flash_ops_write_ai,
123 .idcode1 = 0x05,
124 .nr_sectors = 256,
125 .name = "SST25WF080",
126 .ops = &spi_flash_ops_write_ai,
128 .idcode1 = 0x14,
129 .nr_sectors = 256,
130 .name = "SST25WF080B",
131 .ops = &spi_flash_ops_write_ai,
135 static int
136 sst_enable_writing(const struct spi_flash *flash)
138 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WREN, NULL, 0);
139 if (ret)
140 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
141 return ret;
144 static int
145 sst_enable_writing_status(const struct spi_flash *flash)
147 int ret = spi_flash_cmd(&flash->spi, CMD_SST_EWSR, NULL, 0);
148 if (ret)
149 printk(BIOS_WARNING, "SF: Enabling Write Status failed\n");
150 return ret;
153 static int
154 sst_disable_writing(const struct spi_flash *flash)
156 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WRDI, NULL, 0);
157 if (ret)
158 printk(BIOS_WARNING, "SF: Disabling Write failed\n");
159 return ret;
162 static int
163 sst_byte_write(const struct spi_flash *flash, u32 offset, const void *buf)
165 int ret;
166 u8 cmd[4] = {
167 CMD_SST_BP,
168 offset >> 16,
169 offset >> 8,
170 offset,
173 #if CONFIG(DEBUG_SPI_FLASH)
174 printk(BIOS_SPEW, "BP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
175 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf, cmd[0], offset);
176 #endif
178 ret = sst_enable_writing(flash);
179 if (ret)
180 return ret;
182 ret = spi_flash_cmd_write(&flash->spi, cmd, sizeof(cmd), buf, 1);
183 if (ret)
184 return ret;
186 return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT_MS);
189 static int sst_write_256(const struct spi_flash *flash, u32 offset, size_t len,
190 const void *buf)
192 size_t actual, chunk_len;
193 unsigned long byte_addr;
194 unsigned long page_size;
195 int ret = 0;
196 u8 cmd[4];
198 page_size = 256;
200 /* If the data is not word aligned, write out leading single byte */
201 actual = offset % 2;
202 if (actual) {
203 ret = sst_byte_write(flash, offset, buf);
204 if (ret)
205 goto done;
207 offset += actual;
209 ret = sst_enable_writing(flash);
210 if (ret)
211 goto done;
213 cmd[0] = CMD_SST_AAI_WP;
214 cmd[1] = offset >> 16;
215 cmd[2] = offset >> 8;
216 cmd[3] = offset;
218 for (actual = 0; actual < len; actual += chunk_len) {
219 byte_addr = offset % page_size;
220 chunk_len = MIN(len - actual, page_size - byte_addr);
221 chunk_len = spi_crop_chunk(&flash->spi, sizeof(cmd), chunk_len);
223 cmd[0] = CMD_SST_BP;
224 cmd[1] = (offset >> 16) & 0xff;
225 cmd[2] = (offset >> 8) & 0xff;
226 cmd[3] = offset & 0xff;
227 #if CONFIG(DEBUG_SPI_FLASH)
228 printk(BIOS_SPEW, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x }"
229 " chunk_len = %zu\n",
230 buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
231 #endif
233 ret = spi_flash_cmd(&flash->spi, CMD_SST_WREN, NULL, 0);
234 if (ret < 0) {
235 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
236 break;
239 ret = spi_flash_cmd_write(&flash->spi, cmd, sizeof(cmd),
240 buf + actual, chunk_len);
241 if (ret < 0) {
242 printk(BIOS_WARNING, "SF: SST Page Program failed\n");
243 break;
246 ret = spi_flash_cmd_wait_ready(flash,
247 SPI_FLASH_PROG_TIMEOUT_MS);
248 if (ret)
249 break;
251 offset += chunk_len;
254 done:
255 #if CONFIG(DEBUG_SPI_FLASH)
256 printk(BIOS_SPEW, "SF: SST: program %s %zu bytes @ 0x%lx\n",
257 ret ? "failure" : "success", len, (unsigned long)offset - actual);
258 #endif
259 return ret;
262 static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len,
263 const void *buf)
265 size_t actual, cmd_len;
266 int ret = 0;
267 u8 cmd[4];
269 /* If the data is not word aligned, write out leading single byte */
270 actual = offset % 2;
271 if (actual) {
272 ret = sst_byte_write(flash, offset, buf);
273 if (ret)
274 goto done;
276 offset += actual;
278 ret = sst_enable_writing(flash);
279 if (ret)
280 goto done;
282 cmd_len = 4;
283 cmd[0] = CMD_SST_AAI_WP;
284 cmd[1] = offset >> 16;
285 cmd[2] = offset >> 8;
286 cmd[3] = offset;
288 for (; actual < len - 1; actual += 2) {
289 #if CONFIG(DEBUG_SPI_FLASH)
290 printk(BIOS_SPEW, "WP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
291 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf + actual, cmd[0],
292 offset);
293 #endif
295 ret = spi_flash_cmd_write(&flash->spi, cmd, cmd_len,
296 buf + actual, 2);
297 if (ret) {
298 printk(BIOS_WARNING, "SF: SST word program failed\n");
299 break;
302 ret = spi_flash_cmd_wait_ready(flash,
303 SPI_FLASH_PROG_TIMEOUT_MS);
304 if (ret)
305 break;
307 cmd_len = 1;
308 offset += 2;
311 if (!ret)
312 ret = sst_disable_writing(flash);
314 /* If there is a single trailing byte, write it out */
315 if (!ret && actual != len)
316 ret = sst_byte_write(flash, offset, buf + actual);
318 done:
319 #if CONFIG(DEBUG_SPI_FLASH)
320 printk(BIOS_SPEW, "SF: SST: program %s %zu bytes @ 0x%lx\n",
321 ret ? "failure" : "success", len, (unsigned long)offset - actual);
322 #endif
323 return ret;
327 static int
328 sst_unlock(const struct spi_flash *flash)
330 int ret;
331 u8 cmd, status;
333 ret = sst_enable_writing_status(flash);
334 if (ret)
335 return ret;
337 cmd = CMD_SST_WRSR;
338 status = 0;
339 ret = spi_flash_cmd_write(&flash->spi, &cmd, 1, &status, 1);
340 if (ret)
341 printk(BIOS_WARNING, "SF: Unable to set status byte\n");
343 printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(&flash->spi, CMD_SST_RDSR));
345 return ret;
348 int spi_flash_probe_sst(const struct spi_slave *spi, u8 *idcode,
349 struct spi_flash *flash)
351 const struct sst_spi_flash_params *params;
352 size_t i;
354 for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) {
355 params = &sst_spi_flash_table[i];
356 if (params->idcode1 == idcode[2])
357 break;
360 if (i == ARRAY_SIZE(sst_spi_flash_table)) {
361 printk(BIOS_WARNING, "SF: Unsupported SST ID %02x\n", idcode[1]);
362 return -1;
365 memcpy(&flash->spi, spi, sizeof(*spi));
366 flash->name = params->name;
367 flash->sector_size = SST_SECTOR_SIZE;
368 flash->size = flash->sector_size * params->nr_sectors;
369 flash->erase_cmd = CMD_SST_SE;
370 flash->status_cmd = CMD_SST_RDSR;
372 flash->ops = params->ops;
374 /* Flash powers up read-only, so clear BP# bits */
375 sst_unlock(flash);
377 return 0;