treewide: replace GPLv2 long form headers with SPDX header
[coreboot.git] / src / drivers / spi / sst.c
blobb02061c06d99e64bf9f94ceca0b87a3d0d95abe7
1 /* This file is part of the coreboot project. */
2 /* SPDX-License-Identifier: GPL-2.0-or-later */
4 /*
5 * Driver for SST serial flashes
6 */
8 #include <console/console.h>
9 #include <commonlib/helpers.h>
10 #include <spi_flash.h>
11 #include <spi-generic.h>
12 #include <string.h>
14 #include "spi_flash_internal.h"
16 #define CMD_SST_WREN 0x06 /* Write Enable */
17 #define CMD_SST_WRDI 0x04 /* Write Disable */
18 #define CMD_SST_RDSR 0x05 /* Read Status Register */
19 #define CMD_SST_WRSR 0x01 /* Write Status Register */
20 #define CMD_SST_EWSR 0x50 /* Enable Write Status Register */
21 #define CMD_SST_READ 0x03 /* Read Data Bytes */
22 #define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
23 #define CMD_SST_BP 0x02 /* Byte Program */
24 #define CMD_SST_PP 0x02 /* Page Program */
25 #define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */
26 #define CMD_SST_SE 0x20 /* Sector Erase */
28 #define SST_SR_WIP (1 << 0) /* Write-in-Progress */
29 #define SST_SR_WEL (1 << 1) /* Write enable */
30 #define SST_SR_BP0 (1 << 2) /* Block Protection 0 */
31 #define SST_SR_BP1 (1 << 3) /* Block Protection 1 */
32 #define SST_SR_BP2 (1 << 4) /* Block Protection 2 */
33 #define SST_SR_AAI (1 << 6) /* Addressing mode */
34 #define SST_SR_BPL (1 << 7) /* BP bits lock */
36 static const struct spi_flash_part_id flash_table_ai[] = {
38 /* SST25VF040B */
39 .id[0] = 0x8d,
40 .nr_sectors_shift = 7,
41 },{
42 /* SST25VF080B */
43 .id[0] = 0x8e,
44 .nr_sectors_shift = 8,
45 },{
46 /* SST25VF080 */
47 .id[0] = 0x80,
48 .nr_sectors_shift = 8,
49 },{
50 /* SST25VF016B */
51 .id[0] = 0x41,
52 .nr_sectors_shift = 9,
53 },{
54 /* SST25VF032B */
55 .id[0] = 0x4a,
56 .nr_sectors_shift = 10,
57 },{
58 /* SST25WF512 */
59 .id[0] = 0x01,
60 .nr_sectors_shift = 4,
61 },{
62 /* SST25WF010 */
63 .id[0] = 0x02,
64 .nr_sectors_shift = 5,
65 },{
66 /* SST25WF020 */
67 .id[0] = 0x03,
68 .nr_sectors_shift = 6,
69 },{
70 /* SST25WF040 */
71 .id[0] = 0x04,
72 .nr_sectors_shift = 7,
73 },{
74 /* SST25WF080 */
75 .id[0] = 0x05,
76 .nr_sectors_shift = 8,
77 },{
78 /* SST25WF080B */
79 .id[0] = 0x14,
80 .nr_sectors_shift = 8,
84 static const struct spi_flash_part_id flash_table_pp256[] = {
86 /* SST25VF064C */
87 .id[0] = 0x4b,
88 .nr_sectors_shift = 11,
92 static int
93 sst_enable_writing(const struct spi_flash *flash)
95 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WREN, NULL, 0);
96 if (ret)
97 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
98 return ret;
101 static int
102 sst_enable_writing_status(const struct spi_flash *flash)
104 int ret = spi_flash_cmd(&flash->spi, CMD_SST_EWSR, NULL, 0);
105 if (ret)
106 printk(BIOS_WARNING, "SF: Enabling Write Status failed\n");
107 return ret;
110 static int
111 sst_disable_writing(const struct spi_flash *flash)
113 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WRDI, NULL, 0);
114 if (ret)
115 printk(BIOS_WARNING, "SF: Disabling Write failed\n");
116 return ret;
119 static int
120 sst_byte_write(const struct spi_flash *flash, u32 offset, const void *buf)
122 int ret;
123 u8 cmd[4] = {
124 CMD_SST_BP,
125 offset >> 16,
126 offset >> 8,
127 offset,
130 #if CONFIG(DEBUG_SPI_FLASH)
131 printk(BIOS_SPEW, "BP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
132 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf, cmd[0], offset);
133 #endif
135 ret = sst_enable_writing(flash);
136 if (ret)
137 return ret;
139 ret = spi_flash_cmd_write(&flash->spi, cmd, sizeof(cmd), buf, 1);
140 if (ret)
141 return ret;
143 return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT_MS);
146 static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len,
147 const void *buf)
149 size_t actual, cmd_len;
150 int ret = 0;
151 u8 cmd[4];
153 /* If the data is not word aligned, write out leading single byte */
154 actual = offset % 2;
155 if (actual) {
156 ret = sst_byte_write(flash, offset, buf);
157 if (ret)
158 goto done;
160 offset += actual;
162 ret = sst_enable_writing(flash);
163 if (ret)
164 goto done;
166 cmd_len = 4;
167 cmd[0] = CMD_SST_AAI_WP;
168 cmd[1] = offset >> 16;
169 cmd[2] = offset >> 8;
170 cmd[3] = offset;
172 for (; actual < len - 1; actual += 2) {
173 #if CONFIG(DEBUG_SPI_FLASH)
174 printk(BIOS_SPEW, "WP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
175 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf + actual, cmd[0],
176 offset);
177 #endif
179 ret = spi_flash_cmd_write(&flash->spi, cmd, cmd_len,
180 buf + actual, 2);
181 if (ret) {
182 printk(BIOS_WARNING, "SF: SST word program failed\n");
183 break;
186 ret = spi_flash_cmd_wait_ready(flash,
187 SPI_FLASH_PROG_TIMEOUT_MS);
188 if (ret)
189 break;
191 cmd_len = 1;
192 offset += 2;
195 if (!ret)
196 ret = sst_disable_writing(flash);
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);
202 done:
203 #if CONFIG(DEBUG_SPI_FLASH)
204 printk(BIOS_SPEW, "SF: SST: program %s %zu bytes @ 0x%lx\n",
205 ret ? "failure" : "success", len, (unsigned long)offset - actual);
206 #endif
207 return ret;
210 /* Flash powers up read-only, so clear BP# bits */
211 static int sst_unlock(const struct spi_flash *flash)
213 int ret;
214 u8 cmd, status;
216 ret = sst_enable_writing_status(flash);
217 if (ret)
218 return ret;
220 cmd = CMD_SST_WRSR;
221 status = 0;
222 ret = spi_flash_cmd_write(&flash->spi, &cmd, 1, &status, 1);
223 if (ret)
224 printk(BIOS_WARNING, "SF: Unable to set status byte\n");
226 printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(&flash->spi, CMD_SST_RDSR));
228 return ret;
231 static const struct spi_flash_ops_descriptor descai = {
232 .erase_cmd = CMD_SST_SE,
233 .status_cmd = CMD_SST_RDSR,
234 .wren_cmd = CMD_SST_WREN,
235 .ops = {
236 .read = spi_flash_cmd_read,
237 .write = sst_write_ai,
238 .erase = spi_flash_cmd_erase,
239 .status = spi_flash_cmd_status,
243 const struct spi_flash_vendor_info spi_flash_sst_ai_vi = {
244 .id = VENDOR_ID_SST,
245 .sector_size_kib_shift = 2,
246 .match_id_mask[0] = 0xff,
247 .ids = flash_table_ai,
248 .nr_part_ids = ARRAY_SIZE(flash_table_ai),
249 .desc = &descai,
250 .after_probe = sst_unlock,
253 const struct spi_flash_vendor_info spi_flash_sst_vi = {
254 .id = VENDOR_ID_SST,
255 .page_size_shift = 8,
256 .sector_size_kib_shift = 2,
257 .match_id_mask[0] = 0xff,
258 .ids = flash_table_pp256,
259 .nr_part_ids = ARRAY_SIZE(flash_table_pp256),
260 .desc = &spi_flash_pp_0x20_sector_desc,
261 .after_probe = sst_unlock,