2 * This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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 /* EN25*-specific commands */
24 #define CMD_EN25_WREN 0x06 /* Write Enable */
25 #define CMD_EN25_WRDI 0x04 /* Write Disable */
26 #define CMD_EN25_RDSR 0x05 /* Read Status Register */
27 #define CMD_EN25_WRSR 0x01 /* Write Status Register */
28 #define CMD_EN25_READ 0x03 /* Read Data Bytes */
29 #define CMD_EN25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
30 #define CMD_EN25_PP 0x02 /* Page Program */
31 #define CMD_EN25_SE 0x20 /* Sector Erase */
32 #define CMD_EN25_BE 0xd8 /* Block Erase */
33 #define CMD_EN25_DP 0xb9 /* Deep Power-down */
34 #define CMD_EN25_RES 0xab /* Release from DP, and Read Signature */
36 #define EON_ID_EN25B80 0x2014
37 #define EON_ID_EN25B16 0x2015
38 #define EON_ID_EN25B32 0x2016
39 #define EON_ID_EN25B64 0x2017
40 #define EON_ID_EN25F80 0x3114
41 #define EON_ID_EN25F16 0x3115
42 #define EON_ID_EN25F32 0x3116
43 #define EON_ID_EN25F64 0x3117
44 #define EON_ID_EN25Q80 0x3014
45 #define EON_ID_EN25Q16 0x3015 /* Same as EN25D16 */
46 #define EON_ID_EN25Q32 0x3016 /* Same as EN25Q32A and EN25Q32B */
47 #define EON_ID_EN25Q64 0x3017
48 #define EON_ID_EN25Q128 0x3018
49 #define EON_ID_EN25QH16 0x7015
50 #define EON_ID_EN25QH32 0x7016
51 #define EON_ID_EN25QH64 0x7017
52 #define EON_ID_EN25QH128 0x7018
53 #define EON_ID_EN25S80 0x3814
54 #define EON_ID_EN25S16 0x3815
55 #define EON_ID_EN25S32 0x3816
56 #define EON_ID_EN25S64 0x3817
58 struct eon_spi_flash_params
{
62 u16 sectors_per_block
;
67 static const struct eon_spi_flash_params eon_spi_flash_table
[] = {
71 .pages_per_sector
= 16,
72 .sectors_per_block
= 16,
79 .pages_per_sector
= 16,
80 .sectors_per_block
= 16,
87 .pages_per_sector
= 16,
88 .sectors_per_block
= 16,
95 .pages_per_sector
= 16,
96 .sectors_per_block
= 16,
101 .id
= EON_ID_EN25F80
,
103 .pages_per_sector
= 16,
104 .sectors_per_block
= 16,
109 .id
= EON_ID_EN25F16
,
111 .pages_per_sector
= 16,
112 .sectors_per_block
= 16,
117 .id
= EON_ID_EN25F32
,
119 .pages_per_sector
= 16,
120 .sectors_per_block
= 16,
125 .id
= EON_ID_EN25F64
,
127 .pages_per_sector
= 16,
128 .sectors_per_block
= 16,
133 .id
= EON_ID_EN25Q80
,
135 .pages_per_sector
= 16,
136 .sectors_per_block
= 16,
138 .name
= "EN25Q80(A)",
141 .id
= EON_ID_EN25Q16
,
143 .pages_per_sector
= 16,
144 .sectors_per_block
= 16,
146 .name
= "EN25Q16(D16)",
149 .id
= EON_ID_EN25Q32
,
151 .pages_per_sector
= 16,
152 .sectors_per_block
= 16,
154 .name
= "EN25Q32(A/B)",
157 .id
= EON_ID_EN25Q64
,
159 .pages_per_sector
= 16,
160 .sectors_per_block
= 16,
165 .id
= EON_ID_EN25Q128
,
167 .pages_per_sector
= 16,
168 .sectors_per_block
= 16,
173 .id
= EON_ID_EN25QH16
,
175 .pages_per_sector
= 16,
176 .sectors_per_block
= 16,
181 .id
= EON_ID_EN25QH32
,
183 .pages_per_sector
= 16,
184 .sectors_per_block
= 16,
189 .id
= EON_ID_EN25QH64
,
191 .pages_per_sector
= 16,
192 .sectors_per_block
= 16,
197 .id
= EON_ID_EN25QH128
,
199 .pages_per_sector
= 16,
200 .sectors_per_block
= 16,
205 .id
= EON_ID_EN25S80
,
207 .pages_per_sector
= 16,
208 .sectors_per_block
= 16,
213 .id
= EON_ID_EN25S16
,
215 .pages_per_sector
= 16,
216 .sectors_per_block
= 16,
221 .id
= EON_ID_EN25S32
,
223 .pages_per_sector
= 16,
224 .sectors_per_block
= 16,
229 .id
= EON_ID_EN25S64
,
231 .pages_per_sector
= 16,
232 .sectors_per_block
= 16,
238 static int eon_write(const struct spi_flash
*flash
,
239 u32 offset
, size_t len
, const void *buf
)
241 unsigned long byte_addr
;
242 unsigned long page_size
;
248 page_size
= flash
->page_size
;
250 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
251 byte_addr
= offset
% page_size
;
252 chunk_len
= MIN(len
- actual
, page_size
- byte_addr
);
253 chunk_len
= spi_crop_chunk(&flash
->spi
, sizeof(cmd
), chunk_len
);
255 ret
= spi_flash_cmd(&flash
->spi
, CMD_EN25_WREN
, NULL
, 0);
257 printk(BIOS_WARNING
, "SF: Enabling Write failed\n");
261 cmd
[0] = CMD_EN25_PP
;
262 cmd
[1] = (offset
>> 16) & 0xff;
263 cmd
[2] = (offset
>> 8) & 0xff;
264 cmd
[3] = offset
& 0xff;
266 #if CONFIG(DEBUG_SPI_FLASH)
268 "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
269 buf
+ actual
, cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
272 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
),
273 buf
+ actual
, chunk_len
);
275 printk(BIOS_WARNING
, "SF: EON Page Program failed\n");
279 ret
= spi_flash_cmd_wait_ready(flash
,
280 SPI_FLASH_PROG_TIMEOUT_MS
);
282 printk(BIOS_WARNING
, "SF: EON Page Program timeout\n");
289 #if CONFIG(DEBUG_SPI_FLASH)
290 printk(BIOS_SPEW
, "SF: EON: Successfully programmed %zu bytes @ %#x\n",
291 len
, (unsigned int)(offset
- len
));
298 static const struct spi_flash_ops spi_flash_ops
= {
300 .erase
= spi_flash_cmd_erase
,
301 .status
= spi_flash_cmd_status
,
304 int spi_flash_probe_eon(const struct spi_slave
*spi
, u8
*idcode
,
305 struct spi_flash
*flash
)
307 const struct eon_spi_flash_params
*params
;
310 for (i
= 0; i
< ARRAY_SIZE(eon_spi_flash_table
); ++i
) {
311 params
= &eon_spi_flash_table
[i
];
312 if (params
->id
== ((idcode
[1] << 8) | idcode
[2]))
316 if (i
== ARRAY_SIZE(eon_spi_flash_table
)) {
317 printk(BIOS_WARNING
, "SF: Unsupported EON ID %#02x%02x\n",
318 idcode
[1], idcode
[2]);
322 memcpy(&flash
->spi
, spi
, sizeof(*spi
));
324 flash
->name
= params
->name
;
325 flash
->page_size
= params
->page_size
;
326 flash
->sector_size
= params
->page_size
* params
->pages_per_sector
;
327 flash
->size
= flash
->sector_size
* params
->nr_sectors
;
328 flash
->erase_cmd
= CMD_EN25_SE
;
329 flash
->status_cmd
= CMD_EN25_RDSR
;
331 flash
->ops
= &spi_flash_ops
;