2 * This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (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.
15 #include <console/console.h>
16 #include <commonlib/helpers.h>
17 #include <spi_flash.h>
18 #include <spi-generic.h>
21 #include "spi_flash_internal.h"
23 /* M25Pxx-specific commands */
24 #define CMD_M25PXX_WREN 0x06 /* Write Enable */
25 #define CMD_M25PXX_WRDI 0x04 /* Write Disable */
26 #define CMD_M25PXX_RDSR 0x05 /* Read Status Register */
27 #define CMD_M25PXX_WRSR 0x01 /* Write Status Register */
28 #define CMD_M25PXX_READ 0x03 /* Read Data Bytes */
29 #define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
30 #define CMD_M25PXX_PP 0x02 /* Page Program */
31 #define CMD_M25PXX_SSE 0x20 /* Subsector Erase */
32 #define CMD_M25PXX_SE 0xd8 /* Sector Erase */
33 #define CMD_M25PXX_BE 0xc7 /* Bulk Erase */
34 #define CMD_M25PXX_DP 0xb9 /* Deep Power-down */
35 #define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */
38 * Device ID = (memory_type << 8) + memory_capacity
40 #define STM_ID_M25P10 0x2011
41 #define STM_ID_M25P20 0x2012
42 #define STM_ID_M25P40 0x2013
43 #define STM_ID_M25P80 0x2014
44 #define STM_ID_M25P16 0x2015
45 #define STM_ID_M25P32 0x2016
46 #define STM_ID_M25P64 0x2017
47 #define STM_ID_M25P128 0x2018
48 #define STM_ID_M25PX80 0x7114
49 #define STM_ID_M25PX16 0x7115
50 #define STM_ID_M25PX32 0x7116
51 #define STM_ID_M25PX64 0x7117
52 #define STM_ID_M25PE80 0x8014
53 #define STM_ID_M25PE16 0x8015
54 #define STM_ID_M25PE32 0x8016
55 #define STM_ID_M25PE64 0x8017
56 #define STM_ID_N25Q016__3E 0xba15
57 #define STM_ID_N25Q032__3E 0xba16
58 #define STM_ID_N25Q064__3E 0xba17
59 #define STM_ID_N25Q128__3E 0xba18
60 #define STM_ID_N25Q256__3E 0xba19
61 #define STM_ID_N25Q016__1E 0xbb15
62 #define STM_ID_N25Q032__1E 0xbb16
63 #define STM_ID_N25Q064__1E 0xbb17
64 #define STM_ID_N25Q128__1E 0xbb18
65 #define STM_ID_N25Q256__1E 0xbb19
67 struct stmicro_spi_flash_params
{
76 static const struct stmicro_spi_flash_params stmicro_spi_flash_table
[] = {
78 .device_id
= STM_ID_M25P10
,
79 .op_erase
= CMD_M25PXX_SE
,
81 .pages_per_sector
= 128,
86 .device_id
= STM_ID_M25P16
,
87 .op_erase
= CMD_M25PXX_SE
,
89 .pages_per_sector
= 256,
94 .device_id
= STM_ID_M25P20
,
95 .op_erase
= CMD_M25PXX_SE
,
97 .pages_per_sector
= 256,
102 .device_id
= STM_ID_M25P32
,
103 .op_erase
= CMD_M25PXX_SE
,
105 .pages_per_sector
= 256,
110 .device_id
= STM_ID_M25P40
,
111 .op_erase
= CMD_M25PXX_SE
,
113 .pages_per_sector
= 256,
118 .device_id
= STM_ID_M25P64
,
119 .op_erase
= CMD_M25PXX_SE
,
121 .pages_per_sector
= 256,
126 .device_id
= STM_ID_M25P80
,
127 .op_erase
= CMD_M25PXX_SE
,
129 .pages_per_sector
= 256,
134 .device_id
= STM_ID_M25P128
,
135 .op_erase
= CMD_M25PXX_SE
,
137 .pages_per_sector
= 1024,
142 .device_id
= STM_ID_M25PX80
,
143 .op_erase
= CMD_M25PXX_SE
,
145 .pages_per_sector
= 256,
150 .device_id
= STM_ID_M25PX16
,
151 .op_erase
= CMD_M25PXX_SE
,
153 .pages_per_sector
= 256,
158 .device_id
= STM_ID_M25PX32
,
159 .op_erase
= CMD_M25PXX_SE
,
161 .pages_per_sector
= 256,
166 .device_id
= STM_ID_M25PX64
,
167 .op_erase
= CMD_M25PXX_SE
,
169 .pages_per_sector
= 256,
174 .device_id
= STM_ID_M25PE80
,
175 .op_erase
= CMD_M25PXX_SE
,
177 .pages_per_sector
= 256,
182 .device_id
= STM_ID_M25PE16
,
183 .op_erase
= CMD_M25PXX_SE
,
185 .pages_per_sector
= 256,
190 .device_id
= STM_ID_M25PE32
,
191 .op_erase
= CMD_M25PXX_SE
,
193 .pages_per_sector
= 256,
198 .device_id
= STM_ID_M25PE64
,
199 .op_erase
= CMD_M25PXX_SE
,
201 .pages_per_sector
= 256,
206 .device_id
= STM_ID_N25Q016__3E
,
207 .op_erase
= CMD_M25PXX_SSE
,
209 .pages_per_sector
= 16,
211 .name
= "N25Q016..3E",
214 .device_id
= STM_ID_N25Q032__3E
,
215 .op_erase
= CMD_M25PXX_SSE
,
217 .pages_per_sector
= 16,
219 .name
= "N25Q032..3E",
222 .device_id
= STM_ID_N25Q064__3E
,
223 .op_erase
= CMD_M25PXX_SSE
,
225 .pages_per_sector
= 16,
227 .name
= "N25Q064..3E",
230 .device_id
= STM_ID_N25Q128__3E
,
231 .op_erase
= CMD_M25PXX_SSE
,
233 .pages_per_sector
= 16,
235 .name
= "N25Q128..3E",
238 .device_id
= STM_ID_N25Q256__3E
,
239 .op_erase
= CMD_M25PXX_SSE
,
241 .pages_per_sector
= 16,
243 .name
= "N25Q256..3E",
246 .device_id
= STM_ID_N25Q016__1E
,
247 .op_erase
= CMD_M25PXX_SSE
,
249 .pages_per_sector
= 16,
251 .name
= "N25Q016..1E",
254 .device_id
= STM_ID_N25Q032__1E
,
255 .op_erase
= CMD_M25PXX_SSE
,
257 .pages_per_sector
= 16,
259 .name
= "N25Q032..1E",
262 .device_id
= STM_ID_N25Q064__1E
,
263 .op_erase
= CMD_M25PXX_SSE
,
265 .pages_per_sector
= 16,
267 .name
= "N25Q064..1E",
270 .device_id
= STM_ID_N25Q128__1E
,
271 .op_erase
= CMD_M25PXX_SSE
,
273 .pages_per_sector
= 16,
275 .name
= "N25Q128..1E",
278 .device_id
= STM_ID_N25Q256__1E
,
279 .op_erase
= CMD_M25PXX_SSE
,
281 .pages_per_sector
= 16,
283 .name
= "N25Q256..1E",
287 static int stmicro_write(const struct spi_flash
*flash
,
288 u32 offset
, size_t len
, const void *buf
)
290 unsigned long byte_addr
;
291 unsigned long page_size
;
297 page_size
= flash
->page_size
;
299 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
300 byte_addr
= offset
% page_size
;
301 chunk_len
= MIN(len
- actual
, page_size
- byte_addr
);
302 chunk_len
= spi_crop_chunk(&flash
->spi
, sizeof(cmd
), chunk_len
);
304 cmd
[0] = CMD_M25PXX_PP
;
305 cmd
[1] = (offset
>> 16) & 0xff;
306 cmd
[2] = (offset
>> 8) & 0xff;
307 cmd
[3] = offset
& 0xff;
308 #if CONFIG(DEBUG_SPI_FLASH)
309 printk(BIOS_SPEW
, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x }"
310 " chunk_len = %zu\n",
311 buf
+ actual
, cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
314 ret
= spi_flash_cmd(&flash
->spi
, CMD_M25PXX_WREN
, NULL
, 0);
316 printk(BIOS_WARNING
, "SF: Enabling Write failed\n");
320 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
),
321 buf
+ actual
, chunk_len
);
323 printk(BIOS_WARNING
, "SF: STMicro Page Program failed\n");
327 ret
= spi_flash_cmd_wait_ready(flash
,
328 SPI_FLASH_PROG_TIMEOUT_MS
);
335 #if CONFIG(DEBUG_SPI_FLASH)
336 printk(BIOS_SPEW
, "SF: STMicro: Successfully programmed %zu bytes @"
337 " 0x%lx\n", len
, (unsigned long)(offset
- len
));
345 static const struct spi_flash_ops spi_flash_ops
= {
346 .write
= stmicro_write
,
347 .erase
= spi_flash_cmd_erase
,
350 int spi_flash_probe_stmicro(const struct spi_slave
*spi
, u8
*idcode
,
351 struct spi_flash
*flash
)
353 const struct stmicro_spi_flash_params
*params
;
356 if (idcode
[0] == 0xff) {
357 i
= spi_flash_cmd(spi
, CMD_M25PXX_RES
, idcode
, 4);
360 if ((idcode
[3] & 0xf0) == 0x10) {
363 idcode
[2] = idcode
[3] + 1;
368 for (i
= 0; i
< ARRAY_SIZE(stmicro_spi_flash_table
); i
++) {
369 params
= &stmicro_spi_flash_table
[i
];
370 if (params
->device_id
== (idcode
[1] << 8 | idcode
[2])) {
375 if (i
== ARRAY_SIZE(stmicro_spi_flash_table
)) {
376 printk(BIOS_WARNING
, "SF: Unsupported STMicro ID %02x%02x\n",
377 idcode
[1], idcode
[2]);
381 memcpy(&flash
->spi
, spi
, sizeof(*spi
));
382 flash
->name
= params
->name
;
383 flash
->page_size
= params
->page_size
;
384 flash
->sector_size
= params
->page_size
* params
->pages_per_sector
;
385 flash
->size
= flash
->sector_size
* params
->nr_sectors
;
386 flash
->erase_cmd
= params
->op_erase
;
388 flash
->ops
= &spi_flash_ops
;