2 * Copyright 2008, Network Appliance Inc.
3 * Author: Jason McMullan <mcmullan <at> netapp.com>
4 * Licensed under the GPL-2 or later.
11 #include "spi_flash_internal.h"
13 /* M25Pxx-specific commands */
14 #define CMD_W25_WREN 0x06 /* Write Enable */
15 #define CMD_W25_WRDI 0x04 /* Write Disable */
16 #define CMD_W25_RDSR 0x05 /* Read Status Register */
17 #define CMD_W25_WRSR 0x01 /* Write Status Register */
18 #define CMD_W25_READ 0x03 /* Read Data Bytes */
19 #define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
20 #define CMD_W25_PP 0x02 /* Page Program */
21 #define CMD_W25_SE 0x20 /* Sector (4K) Erase */
22 #define CMD_W25_BE 0xd8 /* Block (64K) Erase */
23 #define CMD_W25_CE 0xc7 /* Chip Erase */
24 #define CMD_W25_DP 0xb9 /* Deep Power-down */
25 #define CMD_W25_RES 0xab /* Release from DP, and Read Signature */
27 struct winbond_spi_flash_params
{
29 /* Log2 of page size in power-of-two mode */
31 uint16_t pages_per_sector
;
32 uint16_t sectors_per_block
;
37 /* spi_flash needs to be first so upper layers can free() it */
38 struct winbond_spi_flash
{
39 struct spi_flash flash
;
40 const struct winbond_spi_flash_params
*params
;
43 static inline struct winbond_spi_flash
*
44 to_winbond_spi_flash(struct spi_flash
*flash
)
46 return container_of(flash
, struct winbond_spi_flash
, flash
);
49 static const struct winbond_spi_flash_params winbond_spi_flash_table
[] = {
53 .pages_per_sector
= 16,
54 .sectors_per_block
= 16,
61 .pages_per_sector
= 16,
62 .sectors_per_block
= 16,
69 .pages_per_sector
= 16,
70 .sectors_per_block
= 16,
77 .pages_per_sector
= 16,
78 .sectors_per_block
= 16,
85 .pages_per_sector
= 16,
86 .sectors_per_block
= 16,
93 .pages_per_sector
= 16,
94 .sectors_per_block
= 16,
101 .pages_per_sector
= 16,
102 .sectors_per_block
= 16,
109 * Assemble the address part of a command for Winbond devices in
110 * non-power-of-two page size mode.
112 static void winbond_build_address(struct winbond_spi_flash
*stm
, u8
*cmd
, u32 offset
)
114 unsigned long page_addr
;
115 unsigned long byte_addr
;
116 unsigned long page_size
;
117 unsigned int page_shift
;
120 * The "extra" space per page is the power-of-two page size
123 page_shift
= stm
->params
->l2_page_size
;
124 page_size
= (1 << page_shift
);
125 page_addr
= offset
/ page_size
;
126 byte_addr
= offset
% page_size
;
128 cmd
[0] = page_addr
>> (16 - page_shift
);
129 cmd
[1] = page_addr
<< (page_shift
- 8) | (byte_addr
>> 8);
133 static int winbond_read_fast(struct spi_flash
*flash
,
134 u32 offset
, size_t len
, void *buf
)
136 struct winbond_spi_flash
*stm
= to_winbond_spi_flash(flash
);
139 cmd
[0] = CMD_READ_ARRAY_FAST
;
140 winbond_build_address(stm
, cmd
+ 1, offset
);
143 return spi_flash_read_common(flash
, cmd
, sizeof(cmd
), buf
, len
);
146 static int winbond_write(struct spi_flash
*flash
,
147 u32 offset
, size_t len
, const void *buf
)
149 struct winbond_spi_flash
*stm
= to_winbond_spi_flash(flash
);
150 unsigned long page_addr
;
151 unsigned long byte_addr
;
152 unsigned long page_size
;
153 unsigned int page_shift
;
159 page_shift
= stm
->params
->l2_page_size
;
160 page_size
= (1 << page_shift
);
161 page_addr
= offset
/ page_size
;
162 byte_addr
= offset
% page_size
;
164 ret
= spi_claim_bus(flash
->spi
);
166 debug("SF: Unable to claim SPI bus\n");
170 for (actual
= 0; actual
< len
; actual
+= chunk_len
) {
171 chunk_len
= min(len
- actual
, page_size
- byte_addr
);
174 cmd
[1] = page_addr
>> (16 - page_shift
);
175 cmd
[2] = page_addr
<< (page_shift
- 8) | (byte_addr
>> 8);
177 debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
179 cmd
[0], cmd
[1], cmd
[2], cmd
[3], chunk_len
);
181 ret
= spi_flash_cmd(flash
->spi
, CMD_W25_WREN
, NULL
, 0);
183 debug("SF: Enabling Write failed\n");
187 ret
= spi_flash_cmd_write(flash
->spi
, cmd
, 4,
188 buf
+ actual
, chunk_len
);
190 debug("SF: Winbond Page Program failed\n");
194 ret
= spi_flash_cmd_wait_ready(flash
, SPI_FLASH_PROG_TIMEOUT
);
202 debug("SF: Winbond: Successfully programmed %u bytes @ 0x%x\n",
207 spi_release_bus(flash
->spi
);
211 int winbond_erase(struct spi_flash
*flash
, u32 offset
, size_t len
)
213 struct winbond_spi_flash
*stm
= to_winbond_spi_flash(flash
);
214 return spi_flash_cmd_erase(flash
, CMD_W25_SE
,
215 (1 << stm
->params
->l2_page_size
) * stm
->params
->pages_per_sector
,
219 struct spi_flash
*spi_flash_probe_winbond(struct spi_slave
*spi
, u8
*idcode
)
221 const struct winbond_spi_flash_params
*params
;
223 struct winbond_spi_flash
*stm
;
226 for (i
= 0; i
< ARRAY_SIZE(winbond_spi_flash_table
); i
++) {
227 params
= &winbond_spi_flash_table
[i
];
228 if (params
->id
== ((idcode
[1] << 8) | idcode
[2]))
232 if (i
== ARRAY_SIZE(winbond_spi_flash_table
)) {
233 debug("SF: Unsupported Winbond ID %02x%02x\n",
234 idcode
[1], idcode
[2]);
238 stm
= malloc(sizeof(struct winbond_spi_flash
));
240 debug("SF: Failed to allocate memory\n");
244 stm
->params
= params
;
245 stm
->flash
.spi
= spi
;
246 stm
->flash
.name
= params
->name
;
248 /* Assuming power-of-two page size initially. */
249 page_size
= 1 << params
->l2_page_size
;
251 stm
->flash
.write
= winbond_write
;
252 stm
->flash
.erase
= winbond_erase
;
253 stm
->flash
.read
= winbond_read_fast
;
254 stm
->flash
.size
= page_size
* params
->pages_per_sector
255 * params
->sectors_per_block
258 printf("SF: Detected %s with page size %u, total ",
259 params
->name
, page_size
);
260 print_size(stm
->flash
.size
, "\n");