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 /* A25L-specific commands */
24 #define CMD_A25_WREN 0x06 /* Write Enable */
25 #define CMD_A25_WRDI 0x04 /* Write Disable */
26 #define CMD_A25_RDSR 0x05 /* Read Status Register */
27 #define CMD_A25_WRSR 0x01 /* Write Status Register */
28 #define CMD_A25_READ 0x03 /* Read Data Bytes */
29 #define CMD_A25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
30 #define CMD_A25_PP 0x02 /* Page Program */
31 #define CMD_A25_SE 0x20 /* Sector (4K) Erase */
32 #define CMD_A25_BE 0xd8 /* Block (64K) Erase */
33 #define CMD_A25_CE 0xc7 /* Chip Erase */
34 #define CMD_A25_DP 0xb9 /* Deep Power-down */
35 #define CMD_A25_RES 0xab /* Release from DP, and Read Signature */
37 struct amic_spi_flash_params
{
39 /* Log2 of page size in power-of-two mode */
41 uint16_t pages_per_sector
;
42 uint16_t sectors_per_block
;
47 static const struct amic_spi_flash_params amic_spi_flash_table
[] = {
51 .pages_per_sector
= 16,
52 .sectors_per_block
= 16,
59 .pages_per_sector
= 16,
60 .sectors_per_block
= 16,
67 .pages_per_sector
= 16,
68 .sectors_per_block
= 16,
75 .pages_per_sector
= 16,
76 .sectors_per_block
= 16,
83 .pages_per_sector
= 16,
84 .sectors_per_block
= 16,
91 .pages_per_sector
= 16,
92 .sectors_per_block
= 16,
99 .pages_per_sector
= 16,
100 .sectors_per_block
= 16,
107 .pages_per_sector
= 16,
108 .sectors_per_block
= 16,
115 .pages_per_sector
= 16,
116 .sectors_per_block
= 16,
122 static int amic_write(const struct spi_flash
*flash
, u32 offset
, size_t len
,
125 unsigned long byte_addr
;
126 unsigned long page_size
;
132 page_size
= flash
->page_size
;
133 byte_addr
= offset
% page_size
;
135 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
136 chunk_len
= MIN(len
- actual
, page_size
- byte_addr
);
137 chunk_len
= spi_crop_chunk(&flash
->spi
, sizeof(cmd
), chunk_len
);
140 cmd
[1] = (offset
>> 16) & 0xff;
141 cmd
[2] = (offset
>> 8) & 0xff;
142 cmd
[3] = offset
& 0xff;
143 #if CONFIG(DEBUG_SPI_FLASH)
144 printk(BIOS_SPEW
, "PP: %p => cmd = { 0x%02x 0x%02x%02x%02x }"
145 " chunk_len = %zu\n", buf
+ actual
,
146 cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
149 ret
= spi_flash_cmd(&flash
->spi
, CMD_A25_WREN
, NULL
, 0);
151 printk(BIOS_WARNING
, "SF: Enabling Write failed\n");
155 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
),
156 buf
+ actual
, chunk_len
);
158 printk(BIOS_WARNING
, "SF: AMIC Page Program failed\n");
162 ret
= spi_flash_cmd_wait_ready(flash
,
163 SPI_FLASH_PROG_TIMEOUT_MS
);
171 #if CONFIG(DEBUG_SPI_FLASH)
172 printk(BIOS_SPEW
, "SF: AMIC: Successfully programmed %zu bytes @"
173 " 0x%lx\n", len
, (unsigned long)(offset
- len
));
181 static const struct spi_flash_ops spi_flash_ops
= {
183 .erase
= spi_flash_cmd_erase
,
186 int spi_flash_probe_amic(const struct spi_slave
*spi
, u8
*idcode
,
187 struct spi_flash
*flash
)
189 const struct amic_spi_flash_params
*params
;
192 for (i
= 0; i
< ARRAY_SIZE(amic_spi_flash_table
); i
++) {
193 params
= &amic_spi_flash_table
[i
];
194 if (params
->id
== ((idcode
[1] << 8) | idcode
[2]))
198 if (i
== ARRAY_SIZE(amic_spi_flash_table
)) {
199 printk(BIOS_WARNING
, "SF: Unsupported AMIC ID %02x%02x\n",
200 idcode
[1], idcode
[2]);
204 memcpy(&flash
->spi
, spi
, sizeof(*spi
));
205 flash
->name
= params
->name
;
207 /* Assuming power-of-two page size initially. */
208 flash
->page_size
= 1 << params
->l2_page_size
;
209 flash
->sector_size
= flash
->page_size
* params
->pages_per_sector
;
210 flash
->size
= flash
->sector_size
* params
->sectors_per_block
*
212 flash
->erase_cmd
= CMD_A25_SE
;
214 flash
->ops
= &spi_flash_ops
;