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 /* GD25Pxx-specific commands */
24 #define CMD_GD25_WREN 0x06 /* Write Enable */
25 #define CMD_GD25_WRDI 0x04 /* Write Disable */
26 #define CMD_GD25_RDSR 0x05 /* Read Status Register */
27 #define CMD_GD25_WRSR 0x01 /* Write Status Register */
28 #define CMD_GD25_READ 0x03 /* Read Data Bytes */
29 #define CMD_GD25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
30 #define CMD_GD25_PP 0x02 /* Page Program */
31 #define CMD_GD25_SE 0x20 /* Sector (4K) Erase */
32 #define CMD_GD25_BE 0xd8 /* Block (64K) Erase */
33 #define CMD_GD25_CE 0xc7 /* Chip Erase */
34 #define CMD_GD25_DP 0xb9 /* Deep Power-down */
35 #define CMD_GD25_RES 0xab /* Release from DP, and Read Signature */
37 struct gigadevice_spi_flash_params
{
40 uint8_t _reserved_for_flags
: 3;
41 uint8_t l2_page_size_shift
: 4;
42 uint8_t pages_per_sector_shift
: 4;
43 uint8_t sectors_per_block_shift
: 4;
44 uint8_t nr_blocks_shift
;
48 static const struct gigadevice_spi_flash_params gigadevice_spi_flash_table
[] = {
51 .l2_page_size_shift
= 8,
52 .pages_per_sector_shift
= 4,
53 .sectors_per_block_shift
= 4,
59 .l2_page_size_shift
= 8,
60 .pages_per_sector_shift
= 4,
61 .sectors_per_block_shift
= 4,
65 }, /* also GD25Q80B */
68 .l2_page_size_shift
= 8,
69 .pages_per_sector_shift
= 4,
70 .sectors_per_block_shift
= 4,
74 }, /* also GD25Q16B */
77 .l2_page_size_shift
= 8,
78 .pages_per_sector_shift
= 4,
79 .sectors_per_block_shift
= 4,
83 }, /* also GD25Q32B */
86 .l2_page_size_shift
= 8,
87 .pages_per_sector_shift
= 4,
88 .sectors_per_block_shift
= 4,
92 }, /* also GD25Q64B, GD25B64C */
95 .l2_page_size_shift
= 8,
96 .pages_per_sector_shift
= 4,
97 .sectors_per_block_shift
= 4,
101 }, /* also GD25Q128B */
104 .l2_page_size_shift
= 8,
105 .pages_per_sector_shift
= 4,
106 .sectors_per_block_shift
= 4,
107 .nr_blocks_shift
= 4,
113 .l2_page_size_shift
= 8,
114 .pages_per_sector_shift
= 4,
115 .sectors_per_block_shift
= 4,
116 .nr_blocks_shift
= 5,
122 .l2_page_size_shift
= 8,
123 .pages_per_sector_shift
= 4,
124 .sectors_per_block_shift
= 4,
125 .nr_blocks_shift
= 4,
131 .l2_page_size_shift
= 8,
132 .pages_per_sector_shift
= 4,
133 .sectors_per_block_shift
= 4,
134 .nr_blocks_shift
= 5,
140 .l2_page_size_shift
= 8,
141 .pages_per_sector_shift
= 4,
142 .sectors_per_block_shift
= 4,
143 .nr_blocks_shift
= 6,
149 .l2_page_size_shift
= 8,
150 .pages_per_sector_shift
= 4,
151 .sectors_per_block_shift
= 4,
152 .nr_blocks_shift
= 7,
155 }, /* also GD25LB64C */
158 .l2_page_size_shift
= 8,
159 .pages_per_sector_shift
= 4,
160 .sectors_per_block_shift
= 4,
161 .nr_blocks_shift
= 8,
167 static int gigadevice_write(const struct spi_flash
*flash
, u32 offset
,
168 size_t len
, const void *buf
)
170 unsigned long byte_addr
;
171 unsigned long page_size
;
177 page_size
= flash
->page_size
;
179 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
180 byte_addr
= offset
% page_size
;
181 chunk_len
= MIN(len
- actual
, page_size
- byte_addr
);
182 chunk_len
= spi_crop_chunk(&flash
->spi
, sizeof(cmd
), chunk_len
);
184 ret
= spi_flash_cmd(&flash
->spi
, CMD_GD25_WREN
, NULL
, 0);
187 "SF gigadevice.c: Enabling Write failed\n");
191 cmd
[0] = CMD_GD25_PP
;
192 cmd
[1] = (offset
>> 16) & 0xff;
193 cmd
[2] = (offset
>> 8) & 0xff;
194 cmd
[3] = offset
& 0xff;
195 #if CONFIG(DEBUG_SPI_FLASH)
197 "PP gigadevice.c: %p => cmd = { 0x%02x 0x%02x%02x%02x }"
198 " chunk_len = %zu\n", buf
+ actual
,
199 cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
202 ret
= spi_flash_cmd_write(&flash
->spi
, cmd
, sizeof(cmd
),
203 buf
+ actual
, chunk_len
);
206 "SF gigadevice.c: Page Program failed\n");
210 ret
= spi_flash_cmd_wait_ready(flash
,
211 SPI_FLASH_PROG_TIMEOUT_MS
);
218 #if CONFIG(DEBUG_SPI_FLASH)
220 "SF gigadevice.c: Successfully programmed %zu bytes @ %#x\n",
221 len
, (unsigned int)(offset
- len
));
230 static const struct spi_flash_ops spi_flash_ops
= {
231 .write
= gigadevice_write
,
232 .erase
= spi_flash_cmd_erase
,
233 .status
= spi_flash_cmd_status
,
236 int spi_flash_probe_gigadevice(const struct spi_slave
*spi
, u8
*idcode
,
237 struct spi_flash
*flash
)
239 const struct gigadevice_spi_flash_params
*params
;
242 for (i
= 0; i
< ARRAY_SIZE(gigadevice_spi_flash_table
); i
++) {
243 params
= &gigadevice_spi_flash_table
[i
];
244 if (params
->id
== ((idcode
[1] << 8) | idcode
[2]))
248 if (i
== ARRAY_SIZE(gigadevice_spi_flash_table
)) {
250 "SF gigadevice.c: Unsupported ID %#02x%02x\n",
251 idcode
[1], idcode
[2]);
255 memcpy(&flash
->spi
, spi
, sizeof(*spi
));
256 flash
->name
= params
->name
;
258 /* Assuming power-of-two page size initially. */
259 flash
->page_size
= 1 << params
->l2_page_size_shift
;
260 flash
->sector_size
= flash
->page_size
*
261 (1 << params
->pages_per_sector_shift
);
262 flash
->size
= flash
->sector_size
*
263 (1 << params
->sectors_per_block_shift
) *
264 (1 << params
->nr_blocks_shift
);
265 flash
->erase_cmd
= CMD_GD25_SE
;
266 flash
->status_cmd
= CMD_GD25_RDSR
;
268 flash
->ops
= &spi_flash_ops
;