coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
sst.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /*
4  * Driver for SST serial flashes
5  */
6 
7 #include <console/console.h>
8 #include <commonlib/helpers.h>
9 #include <spi_flash.h>
10 #include <spi-generic.h>
11 
12 #include "spi_flash_internal.h"
13 
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 */
25 
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 */
33 
34 static const struct spi_flash_part_id flash_table_ai[] = {
35  {
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,
79  },
80 };
81 
82 static const struct spi_flash_part_id flash_table_pp256[] = {
83  {
84  /* SST25VF064C */
85  .id[0] = 0x4b,
86  .nr_sectors_shift = 11,
87  },
88 };
89 
90 static int
91 sst_enable_writing(const struct spi_flash *flash)
92 {
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;
97 }
98 
99 static int
101 {
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;
106 }
107 
108 static int
109 sst_disable_writing(const struct spi_flash *flash)
110 {
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;
115 }
116 
117 static int
118 sst_byte_write(const struct spi_flash *flash, u32 offset, const void *buf)
119 {
120  int ret;
121  u8 cmd[4] = {
122  CMD_SST_BP,
123  offset >> 16,
124  offset >> 8,
125  offset,
126  };
127 
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
132 
133  ret = sst_enable_writing(flash);
134  if (ret)
135  return ret;
136 
137  ret = spi_flash_cmd_write(&flash->spi, cmd, sizeof(cmd), buf, 1);
138  if (ret)
139  return ret;
140 
142 }
143 
144 static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len,
145  const void *buf)
146 {
147  size_t actual, cmd_len;
148  int ret = 0;
149  u8 cmd[4];
150 
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;
157  }
158  offset += actual;
159 
160  ret = sst_enable_writing(flash);
161  if (ret)
162  goto done;
163 
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;
169 
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
176 
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;
182  }
183 
184  ret = spi_flash_cmd_wait_ready(flash,
186  if (ret)
187  break;
188 
189  cmd_len = 1;
190  offset += 2;
191  }
192 
193  if (!ret)
194  ret = sst_disable_writing(flash);
195 
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);
199 
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;
206 }
207 
208 /* Flash powers up read-only, so clear BP# bits */
209 static int sst_unlock(const struct spi_flash *flash)
210 {
211  int ret;
212  u8 cmd, status;
213 
214  ret = sst_enable_writing_status(flash);
215  if (ret)
216  return ret;
217 
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");
223 
224  printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(&flash->spi, CMD_SST_RDSR));
225 
226  return ret;
227 }
228 
229 static const struct spi_flash_ops_descriptor descai = {
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,
238  },
239 };
240 
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,
249 };
250 
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),
259  .after_probe = sst_unlock,
260 };
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define printk(level,...)
Definition: stdlib.h:16
static size_t offset
Definition: flashconsole.c:16
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
static uint8_t * buf
Definition: uart.c:7
#define SPI_FLASH_PROG_TIMEOUT_MS
Definition: spi-generic.h:10
static int spi_w8r8(const struct spi_slave *slave, unsigned char byte)
Definition: spi-generic.h:295
#define VENDOR_ID_SST
Definition: spi-generic.h:25
int spi_flash_cmd_read(const struct spi_flash *flash, u32 offset, size_t len, void *buf)
Definition: spi_flash.c:142
int spi_flash_cmd_erase(const struct spi_flash *flash, u32 offset, size_t len)
Definition: spi_flash.c:228
const struct spi_flash_ops_descriptor spi_flash_pp_0x20_sector_desc
Definition: spi_flash.c:793
int spi_flash_cmd_wait_ready(const struct spi_flash *flash, unsigned long timeout)
Definition: spi_flash.c:221
int spi_flash_cmd(const struct spi_slave *spi, u8 cmd, void *response, size_t len)
Definition: spi_flash.c:107
int spi_flash_cmd_write(const struct spi_slave *spi, const u8 *cmd, size_t cmd_len, const void *data, size_t data_len)
Definition: spi_flash.c:122
int spi_flash_cmd_status(const struct spi_flash *flash, u8 *reg)
Definition: spi_flash.c:276
static int sst_write_ai(const struct spi_flash *flash, u32 offset, size_t len, const void *buf)
Definition: sst.c:144
#define CMD_SST_BP
Definition: sst.c:21
#define CMD_SST_EWSR
Definition: sst.c:18
static int sst_byte_write(const struct spi_flash *flash, u32 offset, const void *buf)
Definition: sst.c:118
static int sst_enable_writing_status(const struct spi_flash *flash)
Definition: sst.c:100
static const struct spi_flash_part_id flash_table_pp256[]
Definition: sst.c:82
const struct spi_flash_vendor_info spi_flash_sst_ai_vi
Definition: sst.c:241
#define CMD_SST_SE
Definition: sst.c:24
static const struct spi_flash_ops_descriptor descai
Definition: sst.c:229
static int sst_enable_writing(const struct spi_flash *flash)
Definition: sst.c:91
static int sst_disable_writing(const struct spi_flash *flash)
Definition: sst.c:109
#define CMD_SST_AAI_WP
Definition: sst.c:23
#define CMD_SST_RDSR
Definition: sst.c:16
#define CMD_SST_WRSR
Definition: sst.c:17
#define CMD_SST_WREN
Definition: sst.c:14
#define CMD_SST_WRDI
Definition: sst.c:15
static const struct spi_flash_part_id flash_table_ai[]
Definition: sst.c:34
static int sst_unlock(const struct spi_flash *flash)
Definition: sst.c:209
const struct spi_flash_vendor_info spi_flash_sst_vi
Definition: sst.c:251
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
uint8_t u8
Definition: stdint.h:45
struct spi_slave spi
Definition: spi_flash.h:84