soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / drivers / spi / sst.c
blob887380fdeb823772303798fcf3cba2189459c9b1
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /*
4 * Driver for SST serial flashes
5 */
7 #include <console/console.h>
8 #include <commonlib/helpers.h>
9 #include <spi_flash.h>
10 #include <spi-generic.h>
12 #include "spi_flash_internal.h"
14 #define CMD_SST_WREN 0x06 /* Write Enable */
15 #define CMD_SST_WRDI 0x04 /* Write Disable */
16 #define CMD_SST_RDSR 0x05 /* Read Status Register */
17 #define CMD_SST_WRSR 0x01 /* Write Status Register */
18 #define CMD_SST_EWSR 0x50 /* Enable Write Status Register */
19 #define CMD_SST_READ 0x03 /* Read Data Bytes */
20 #define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
21 #define CMD_SST_BP 0x02 /* Byte Program */
22 #define CMD_SST_PP 0x02 /* Page Program */
23 #define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */
24 #define CMD_SST_SE 0x20 /* Sector Erase */
26 #define SST_SR_WIP (1 << 0) /* Write-in-Progress */
27 #define SST_SR_WEL (1 << 1) /* Write enable */
28 #define SST_SR_BP0 (1 << 2) /* Block Protection 0 */
29 #define SST_SR_BP1 (1 << 3) /* Block Protection 1 */
30 #define SST_SR_BP2 (1 << 4) /* Block Protection 2 */
31 #define SST_SR_AAI (1 << 6) /* Addressing mode */
32 #define SST_SR_BPL (1 << 7) /* BP bits lock */
34 static const struct spi_flash_part_id flash_table_ai[] = {
36 /* SST25VF040B */
37 .id[0] = 0x8d,
38 .nr_sectors_shift = 7,
39 },{
40 /* SST25VF080B */
41 .id[0] = 0x8e,
42 .nr_sectors_shift = 8,
43 },{
44 /* SST25VF080 */
45 .id[0] = 0x80,
46 .nr_sectors_shift = 8,
47 },{
48 /* SST25VF016B */
49 .id[0] = 0x41,
50 .nr_sectors_shift = 9,
51 },{
52 /* SST25VF032B */
53 .id[0] = 0x4a,
54 .nr_sectors_shift = 10,
55 },{
56 /* SST25WF512 */
57 .id[0] = 0x01,
58 .nr_sectors_shift = 4,
59 },{
60 /* SST25WF010 */
61 .id[0] = 0x02,
62 .nr_sectors_shift = 5,
63 },{
64 /* SST25WF020 */
65 .id[0] = 0x03,
66 .nr_sectors_shift = 6,
67 },{
68 /* SST25WF040 */
69 .id[0] = 0x04,
70 .nr_sectors_shift = 7,
71 },{
72 /* SST25WF080 */
73 .id[0] = 0x05,
74 .nr_sectors_shift = 8,
75 },{
76 /* SST25WF080B */
77 .id[0] = 0x14,
78 .nr_sectors_shift = 8,
82 static const struct spi_flash_part_id flash_table_pp256[] = {
84 /* SST25VF064C */
85 .id[0] = 0x4b,
86 .nr_sectors_shift = 11,
90 static int
91 sst_enable_writing(const struct spi_flash *flash)
93 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WREN, NULL, 0);
94 if (ret)
95 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
96 return ret;
99 static int
100 sst_enable_writing_status(const struct spi_flash *flash)
102 int ret = spi_flash_cmd(&flash->spi, CMD_SST_EWSR, NULL, 0);
103 if (ret)
104 printk(BIOS_WARNING, "SF: Enabling Write Status failed\n");
105 return ret;
108 static int
109 sst_disable_writing(const struct spi_flash *flash)
111 int ret = spi_flash_cmd(&flash->spi, CMD_SST_WRDI, NULL, 0);
112 if (ret)
113 printk(BIOS_WARNING, "SF: Disabling Write failed\n");
114 return ret;
117 static int
118 sst_byte_write(const struct spi_flash *flash, u32 offset, const void *buf)
120 int ret;
121 u8 cmd[4] = {
122 CMD_SST_BP,
123 offset >> 16,
124 offset >> 8,
125 offset,
128 #if CONFIG(DEBUG_SPI_FLASH)
129 printk(BIOS_SPEW, "BP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
130 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf, cmd[0], offset);
131 #endif
133 ret = sst_enable_writing(flash);
134 if (ret)
135 return ret;
137 ret = spi_flash_cmd_write(&flash->spi, cmd, sizeof(cmd), buf, 1);
138 if (ret)
139 return ret;
141 return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT_MS);
144 static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len,
145 const void *buf)
147 size_t actual, cmd_len;
148 int ret = 0;
149 u8 cmd[4];
151 /* If the data is not word aligned, write out leading single byte */
152 actual = offset % 2;
153 if (actual) {
154 ret = sst_byte_write(flash, offset, buf);
155 if (ret)
156 goto done;
158 offset += actual;
160 ret = sst_enable_writing(flash);
161 if (ret)
162 goto done;
164 cmd_len = 4;
165 cmd[0] = CMD_SST_AAI_WP;
166 cmd[1] = offset >> 16;
167 cmd[2] = offset >> 8;
168 cmd[3] = offset;
170 for (; actual < len - 1; actual += 2) {
171 #if CONFIG(DEBUG_SPI_FLASH)
172 printk(BIOS_SPEW, "WP[%02x]: %p => cmd = { 0x%02x 0x%06x }\n",
173 spi_w8r8(&flash->spi, CMD_SST_RDSR), buf + actual, cmd[0],
174 offset);
175 #endif
177 ret = spi_flash_cmd_write(&flash->spi, cmd, cmd_len,
178 buf + actual, 2);
179 if (ret) {
180 printk(BIOS_WARNING, "SF: SST word program failed\n");
181 break;
184 ret = spi_flash_cmd_wait_ready(flash,
185 SPI_FLASH_PROG_TIMEOUT_MS);
186 if (ret)
187 break;
189 cmd_len = 1;
190 offset += 2;
193 if (!ret)
194 ret = sst_disable_writing(flash);
196 /* If there is a single trailing byte, write it out */
197 if (!ret && actual != len)
198 ret = sst_byte_write(flash, offset, buf + actual);
200 done:
201 #if CONFIG(DEBUG_SPI_FLASH)
202 printk(BIOS_SPEW, "SF: SST: program %s %zu bytes @ 0x%lx\n",
203 ret ? "failure" : "success", len, (unsigned long)offset - actual);
204 #endif
205 return ret;
208 /* Flash powers up read-only, so clear BP# bits */
209 static int sst_unlock(const struct spi_flash *flash)
211 int ret;
212 u8 cmd, status;
214 ret = sst_enable_writing_status(flash);
215 if (ret)
216 return ret;
218 cmd = CMD_SST_WRSR;
219 status = 0;
220 ret = spi_flash_cmd_write(&flash->spi, &cmd, 1, &status, 1);
221 if (ret)
222 printk(BIOS_WARNING, "SF: Unable to set status byte\n");
224 printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(&flash->spi, CMD_SST_RDSR));
226 return ret;
229 static const struct spi_flash_ops_descriptor descai = {
230 .erase_cmd = CMD_SST_SE,
231 .status_cmd = CMD_SST_RDSR,
232 .wren_cmd = CMD_SST_WREN,
233 .ops = {
234 .read = spi_flash_cmd_read,
235 .write = sst_write_ai,
236 .erase = spi_flash_cmd_erase,
237 .status = spi_flash_cmd_status,
241 const struct spi_flash_vendor_info spi_flash_sst_ai_vi = {
242 .id = VENDOR_ID_SST,
243 .sector_size_kib_shift = 2,
244 .match_id_mask[0] = 0xff,
245 .ids = flash_table_ai,
246 .nr_part_ids = ARRAY_SIZE(flash_table_ai),
247 .desc = &descai,
248 .after_probe = sst_unlock,
251 const struct spi_flash_vendor_info spi_flash_sst_vi = {
252 .id = VENDOR_ID_SST,
253 .page_size_shift = 8,
254 .sector_size_kib_shift = 2,
255 .match_id_mask[0] = 0xff,
256 .ids = flash_table_pp256,
257 .nr_part_ids = ARRAY_SIZE(flash_table_pp256),
258 .desc = &spi_flash_pp_0x20_sector_desc,
259 .after_probe = sst_unlock,