blob: 51d895635115949c193201e4350a008cc07b64bb [file] [log] [blame]
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -07001/*
2 * Copyright 2009(C) Marvell International Ltd. and its affiliates
3 * Prafulla Wadaskar <prafulla@marvell.com>
4 *
5 * Based on drivers/mtd/spi/stmicro.c
6 *
7 * Copyright 2008, Network Appliance Inc.
8 * Jason McMullan <mcmullan@netapp.com>
9 *
10 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
11 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
12 *
13 * See file CREDITS for list of people who contributed to this
14 * project.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Paul Menzela8ae1c62013-02-20 13:21:20 +010023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070024 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
29 * MA 02110-1301 USA
30 */
31
32#include <stdlib.h>
33#include <spi_flash.h>
Edward O'Callaghanc4561e22014-06-26 15:02:40 +100034
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070035#include "spi_flash_internal.h"
36
37/* MX25xx-specific commands */
38#define CMD_MX25XX_WREN 0x06 /* Write Enable */
39#define CMD_MX25XX_WRDI 0x04 /* Write Disable */
40#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */
41#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */
42#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */
43#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
44#define CMD_MX25XX_PP 0x02 /* Page Program */
45#define CMD_MX25XX_SE 0x20 /* Sector Erase */
46#define CMD_MX25XX_BE 0xD8 /* Block Erase */
47#define CMD_MX25XX_CE 0xc7 /* Chip Erase */
48#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */
49#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */
50
51#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */
52
53struct macronix_spi_flash_params {
54 u16 idcode;
55 u16 page_size;
56 u16 pages_per_sector;
57 u16 sectors_per_block;
58 u16 nr_blocks;
59 const char *name;
60};
61
62struct macronix_spi_flash {
63 struct spi_flash flash;
64 const struct macronix_spi_flash_params *params;
65};
66
67static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash
68 *flash)
69{
70 return container_of(flash, struct macronix_spi_flash, flash);
71}
72
73static const struct macronix_spi_flash_params macronix_spi_flash_table[] = {
74 {
75 .idcode = 0x2015,
76 .page_size = 256,
77 .pages_per_sector = 16,
78 .sectors_per_block = 16,
79 .nr_blocks = 32,
80 .name = "MX25L1605D",
81 },
82 {
83 .idcode = 0x2016,
84 .page_size = 256,
85 .pages_per_sector = 16,
86 .sectors_per_block = 16,
87 .nr_blocks = 64,
88 .name = "MX25L3205D",
89 },
90 {
Zheng Baoc269a9b2012-12-06 11:30:33 +080091 .idcode = 0x5e16,
92 .page_size = 256,
93 .pages_per_sector = 16,
94 .sectors_per_block = 16,
95 .nr_blocks = 64,
Dave Frodin01856062014-11-24 10:37:29 -070096 .name = "MX25L3235D", /* MX25L3225D/MX25L3235D/MX25L3236D/MX25L3237D */
97 },
98 {
99 .idcode = 0x2536,
100 .page_size = 256,
101 .pages_per_sector = 16,
102 .sectors_per_block = 16,
103 .nr_blocks = 64,
104 .name = "MX25L3239E",
Zheng Baoc269a9b2012-12-06 11:30:33 +0800105 },
106 {
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700107 .idcode = 0x2017,
108 .page_size = 256,
109 .pages_per_sector = 16,
110 .sectors_per_block = 16,
111 .nr_blocks = 128,
112 .name = "MX25L6405D",
113 },
114 {
115 .idcode = 0x2018,
116 .page_size = 256,
117 .pages_per_sector = 16,
118 .sectors_per_block = 16,
119 .nr_blocks = 256,
120 .name = "MX25L12805D",
121 },
122 {
123 .idcode = 0x2618,
124 .page_size = 256,
125 .pages_per_sector = 16,
126 .sectors_per_block = 16,
127 .nr_blocks = 256,
128 .name = "MX25L12855E",
129 },
Idwer Vollering06413ff2014-10-26 01:20:20 +0200130 {
131 .idcode = 0x2537,
132 .page_size = 256,
133 .pages_per_sector = 16,
134 .sectors_per_block = 16,
135 .nr_blocks = 128,
136 .name = "MX25U6435F",
137 },
138 {
Kyösti Mälkki3f382c72014-11-11 15:01:31 +0200139 .idcode = 0x2538,
140 .page_size = 256,
141 .pages_per_sector = 16,
142 .sectors_per_block = 16,
143 .nr_blocks = 256,
144 .name = "MX25U12835F",
145 },
146 {
Idwer Vollering06413ff2014-10-26 01:20:20 +0200147 .idcode = 0x9517,
148 .page_size = 256,
149 .pages_per_sector = 16,
150 .sectors_per_block = 16,
151 .nr_blocks = 128,
152 .name = "MX25L6495F",
153 },
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700154};
155
156static int macronix_write(struct spi_flash *flash,
157 u32 offset, size_t len, const void *buf)
158{
159 struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash);
160 unsigned long byte_addr;
161 unsigned long page_size;
162 size_t chunk_len;
163 size_t actual;
David Hendricks032c8432014-04-11 19:48:55 -0700164 int ret = 0;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700165 u8 cmd[4];
166
Kyösti Mälkki77d12802014-06-29 16:15:39 +0300167 page_size = mcx->params->page_size;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700168 byte_addr = offset % page_size;
169
Martin Roth3316cf22012-12-05 16:22:54 -0700170 flash->spi->rw = SPI_WRITE_FLAG;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700171
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700172 for (actual = 0; actual < len; actual += chunk_len) {
173 chunk_len = min(len - actual, page_size - byte_addr);
Kyösti Mälkki11104952014-06-29 16:17:33 +0300174 chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700175
176 cmd[0] = CMD_MX25XX_PP;
177 cmd[1] = (offset >> 16) & 0xff;
178 cmd[2] = (offset >> 8) & 0xff;
179 cmd[3] = offset & 0xff;
Stefan Reinauer5649b082012-05-23 11:03:29 -0700180#if CONFIG_DEBUG_SPI_FLASH
Stefan Reinauer8ea5a342012-05-14 13:52:32 -0700181 printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x }"
182 " chunk_len = %zu\n",
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700183 buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
Stefan Reinauer5649b082012-05-23 11:03:29 -0700184#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700185
186 ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0);
187 if (ret < 0) {
188 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
189 break;
190 }
191
Kyösti Mälkki11104952014-06-29 16:17:33 +0300192 ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700193 buf + actual, chunk_len);
194 if (ret < 0) {
195 printk(BIOS_WARNING, "SF: Macronix Page Program failed\n");
196 break;
197 }
198
199 ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
200 if (ret)
201 break;
202
203 offset += chunk_len;
204 byte_addr = 0;
205 }
206
Marc Jones747127d2012-12-03 22:16:29 -0700207#if CONFIG_DEBUG_SPI_FLASH
208 printk(BIOS_SPEW, "SF: Macronix: Successfully programmed %zu bytes @"
Stefan Reinauer8ea5a342012-05-14 13:52:32 -0700209 " 0x%lx\n", len, (unsigned long)(offset - len));
Marc Jones747127d2012-12-03 22:16:29 -0700210#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700211
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700212 return ret;
213}
214
215static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len)
216{
217 return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len);
218}
219
220struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode)
221{
222 const struct macronix_spi_flash_params *params;
223 struct macronix_spi_flash *mcx;
224 unsigned int i;
225 u16 id = idcode[2] | idcode[1] << 8;
226
227 for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) {
228 params = &macronix_spi_flash_table[i];
229 if (params->idcode == id)
230 break;
231 }
232
233 if (i == ARRAY_SIZE(macronix_spi_flash_table)) {
234 printk(BIOS_WARNING, "SF: Unsupported Macronix ID %04x\n", id);
235 return NULL;
236 }
237
238 mcx = malloc(sizeof(*mcx));
239 if (!mcx) {
240 printk(BIOS_WARNING, "SF: Failed to allocate memory\n");
241 return NULL;
242 }
243
244 mcx->params = params;
245 mcx->flash.spi = spi;
246 mcx->flash.name = params->name;
247
248 mcx->flash.write = macronix_write;
249 mcx->flash.erase = macronix_erase;
Duncan Laurie23b00532012-10-10 14:21:23 -0700250#if CONFIG_SPI_FLASH_NO_FAST_READ
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700251 mcx->flash.read = spi_flash_cmd_read_slow;
252#else
253 mcx->flash.read = spi_flash_cmd_read_fast;
254#endif
255 mcx->flash.sector_size = params->page_size * params->pages_per_sector;
256 mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block *
257 params->nr_blocks;
258
259 return &mcx->flash;
260}