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 /* MX25xx-specific commands */
24 #define CMD_MX25XX_WREN 0x06 /* Write Enable */
25 #define CMD_MX25XX_WRDI 0x04 /* Write Disable */
26 #define CMD_MX25XX_RDSR 0x05 /* Read Status Register */
27 #define CMD_MX25XX_WRSR 0x01 /* Write Status Register */
28 #define CMD_MX25XX_READ 0x03 /* Read Data Bytes */
29 #define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
30 #define CMD_MX25XX_PP 0x02 /* Page Program */
31 #define CMD_MX25XX_SE 0x20 /* Sector Erase */
32 #define CMD_MX25XX_BE 0xD8 /* Block Erase */
33 #define CMD_MX25XX_CE 0xc7 /* Chip Erase */
34 #define CMD_MX25XX_DP 0xb9 /* Deep Power-down */
35 #define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */
37 #define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */
39 struct macronix_spi_flash_params
{
43 u16 sectors_per_block
;
48 static const struct macronix_spi_flash_params macronix_spi_flash_table
[] = {
52 .pages_per_sector
= 16,
53 .sectors_per_block
= 16,
60 .pages_per_sector
= 16,
61 .sectors_per_block
= 16,
68 .pages_per_sector
= 16,
69 .sectors_per_block
= 16,
76 .pages_per_sector
= 16,
77 .sectors_per_block
= 16,
84 .pages_per_sector
= 16,
85 .sectors_per_block
= 16,
87 .name
= "MX25L12805D",
92 .pages_per_sector
= 16,
93 .sectors_per_block
= 16,
95 .name
= "MX25L25635F",
100 .pages_per_sector
= 16,
101 .sectors_per_block
= 16,
103 .name
= "MX66L51235F",
108 .pages_per_sector
= 16,
109 .sectors_per_block
= 16,
111 .name
= "MX25L1635D",
116 .pages_per_sector
= 16,
117 .sectors_per_block
= 16,
119 .name
= "MX25L1635E",
124 .pages_per_sector
= 16,
125 .sectors_per_block
= 16,
127 .name
= "MX25U8032E",
132 .pages_per_sector
= 16,
133 .sectors_per_block
= 16,
135 .name
= "MX25U1635E",
140 .pages_per_sector
= 16,
141 .sectors_per_block
= 16,
143 .name
= "MX25U3235E",
148 .pages_per_sector
= 16,
149 .sectors_per_block
= 16,
151 .name
= "MX25U6435F",
156 .pages_per_sector
= 16,
157 .sectors_per_block
= 16,
159 .name
= "MX25U12835F",
164 .pages_per_sector
= 16,
165 .sectors_per_block
= 16,
167 .name
= "MX25U25635F",
172 .pages_per_sector
= 16,
173 .sectors_per_block
= 16,
175 .name
= "MX25U51245G",
180 .pages_per_sector
= 16,
181 .sectors_per_block
= 16,
183 .name
= "MX25L12855E",
188 .pages_per_sector
= 16,
189 .sectors_per_block
= 16,
191 .name
= "MX25L3235D", /* MX25L3225D/MX25L3236D/MX25L3237D */
196 .pages_per_sector
= 16,
197 .sectors_per_block
= 16,
199 .name
= "MX25L6495F",
203 static int macronix_write(const struct spi_flash
*flash
, u32 offset
, size_t len
,
206 unsigned long byte_addr
;
207 unsigned long page_size
;
213 page_size
= flash
->page_size
;
215 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
216 byte_addr
= offset
% page_size
;
217 chunk_len
= MIN(len
- actual
, page_size
- byte_addr
);
218 chunk_len
= spi_crop_chunk(&flash
->spi
, sizeof(cmd
), chunk_len
);
220 cmd
[0] = CMD_MX25XX_PP
;
221 cmd
[1] = (offset
>> 16) & 0xff;
222 cmd
[2] = (offset
>> 8) & 0xff;
223 cmd
[3] = offset
& 0xff;
224 #if CONFIG(DEBUG_SPI_FLASH)
225 printk(BIOS_SPEW
, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x }"
226 " chunk_len = %zu\n",
227 buf
+ actual
, cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
230 ret
= spi_flash_cmd(&flash
->spi
, CMD_MX25XX_WREN
, NULL
, 0);
232 printk(BIOS_WARNING
, "SF: Enabling Write failed\n");
236 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
),
237 buf
+ actual
, chunk_len
);
239 printk(BIOS_WARNING
, "SF: Macronix Page Program failed\n");
243 ret
= spi_flash_cmd_wait_ready(flash
,
244 SPI_FLASH_PROG_TIMEOUT_MS
);
251 #if CONFIG(DEBUG_SPI_FLASH)
252 printk(BIOS_SPEW
, "SF: Macronix: Successfully programmed %zu bytes @"
253 " 0x%lx\n", len
, (unsigned long)(offset
- len
));
259 static const struct spi_flash_ops spi_flash_ops
= {
260 .write
= macronix_write
,
261 .erase
= spi_flash_cmd_erase
,
262 .status
= spi_flash_cmd_status
,
265 int spi_flash_probe_macronix(const struct spi_slave
*spi
, u8
*idcode
,
266 struct spi_flash
*flash
)
268 const struct macronix_spi_flash_params
*params
;
270 u16 id
= idcode
[2] | idcode
[1] << 8;
272 for (i
= 0; i
< ARRAY_SIZE(macronix_spi_flash_table
); i
++) {
273 params
= ¯onix_spi_flash_table
[i
];
274 if (params
->idcode
== id
)
278 if (i
== ARRAY_SIZE(macronix_spi_flash_table
)) {
279 printk(BIOS_WARNING
, "SF: Unsupported Macronix ID %04x\n", id
);
283 memcpy(&flash
->spi
, spi
, sizeof(*spi
));
284 flash
->name
= params
->name
;
285 flash
->page_size
= params
->page_size
;
286 flash
->sector_size
= params
->page_size
* params
->pages_per_sector
;
287 flash
->size
= flash
->sector_size
* params
->sectors_per_block
*
289 flash
->erase_cmd
= CMD_MX25XX_SE
;
290 flash
->status_cmd
= CMD_MX25XX_RDSR
;
292 flash
->ops
= &spi_flash_ops
;