1 /* SPDX-License-Identifier: GPL-2.0-or-later */
4 * Driver for SST serial flashes
7 #include <console/console.h>
8 #include <commonlib/helpers.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
[] = {
38 .nr_sectors_shift
= 7,
42 .nr_sectors_shift
= 8,
46 .nr_sectors_shift
= 8,
50 .nr_sectors_shift
= 9,
54 .nr_sectors_shift
= 10,
58 .nr_sectors_shift
= 4,
62 .nr_sectors_shift
= 5,
66 .nr_sectors_shift
= 6,
70 .nr_sectors_shift
= 7,
74 .nr_sectors_shift
= 8,
78 .nr_sectors_shift
= 8,
82 static const struct spi_flash_part_id flash_table_pp256
[] = {
86 .nr_sectors_shift
= 11,
91 sst_enable_writing(const struct spi_flash
*flash
)
93 int ret
= spi_flash_cmd(&flash
->spi
, CMD_SST_WREN
, NULL
, 0);
95 printk(BIOS_WARNING
, "SF: Enabling Write failed\n");
100 sst_enable_writing_status(const struct spi_flash
*flash
)
102 int ret
= spi_flash_cmd(&flash
->spi
, CMD_SST_EWSR
, NULL
, 0);
104 printk(BIOS_WARNING
, "SF: Enabling Write Status failed\n");
109 sst_disable_writing(const struct spi_flash
*flash
)
111 int ret
= spi_flash_cmd(&flash
->spi
, CMD_SST_WRDI
, NULL
, 0);
113 printk(BIOS_WARNING
, "SF: Disabling Write failed\n");
118 sst_byte_write(const struct spi_flash
*flash
, u32 offset
, const void *buf
)
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
);
133 ret
= sst_enable_writing(flash
);
137 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
), buf
, 1);
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
,
147 size_t actual
, cmd_len
;
151 /* If the data is not word aligned, write out leading single byte */
154 ret
= sst_byte_write(flash
, offset
, buf
);
160 ret
= sst_enable_writing(flash
);
165 cmd
[0] = CMD_SST_AAI_WP
;
166 cmd
[1] = offset
>> 16;
167 cmd
[2] = offset
>> 8;
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],
177 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, cmd_len
,
180 printk(BIOS_WARNING
, "SF: SST word program failed\n");
184 ret
= spi_flash_cmd_wait_ready(flash
,
185 SPI_FLASH_PROG_TIMEOUT_MS
);
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
);
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
);
208 /* Flash powers up read-only, so clear BP# bits */
209 static int sst_unlock(const struct spi_flash
*flash
)
214 ret
= sst_enable_writing_status(flash
);
220 ret
= spi_flash_cmd_write(&flash
->spi
, &cmd
, 1, &status
, 1);
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
));
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
,
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
= {
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
),
248 .after_probe
= sst_unlock
,
251 const struct spi_flash_vendor_info spi_flash_sst_vi
= {
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
,