1a2b7f194SVignesh R // SPDX-License-Identifier: GPL-2.0
2a2b7f194SVignesh R /*
3a2b7f194SVignesh R * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
4a2b7f194SVignesh R * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
5a2b7f194SVignesh R *
6a2b7f194SVignesh R * Copyright (C) 2005, Intec Automation Inc.
7a2b7f194SVignesh R * Copyright (C) 2014, Freescale Semiconductor, Inc.
8a2b7f194SVignesh R *
9a2b7f194SVignesh R * Synced from Linux v4.19
10a2b7f194SVignesh R */
11a2b7f194SVignesh R
12a2b7f194SVignesh R #include <common.h>
13a2b7f194SVignesh R #include <linux/err.h>
14a2b7f194SVignesh R #include <linux/errno.h>
15a2b7f194SVignesh R #include <linux/log2.h>
16a2b7f194SVignesh R #include <linux/math64.h>
17a2b7f194SVignesh R #include <linux/sizes.h>
18a2b7f194SVignesh R
19a2b7f194SVignesh R #include <linux/mtd/mtd.h>
20a2b7f194SVignesh R #include <linux/mtd/spi-nor.h>
21a2b7f194SVignesh R #include <spi-mem.h>
22a2b7f194SVignesh R #include <spi.h>
23a2b7f194SVignesh R
24f2313133SVignesh R #include "sf_internal.h"
25f2313133SVignesh R
26a2b7f194SVignesh R /* Define max times to check status register before we give up. */
27a2b7f194SVignesh R
28a2b7f194SVignesh R /*
29a2b7f194SVignesh R * For everything but full-chip erase; probably could be much smaller, but kept
30a2b7f194SVignesh R * around for safety for now
31a2b7f194SVignesh R */
32a2b7f194SVignesh R
33a2b7f194SVignesh R #define HZ CONFIG_SYS_HZ
34a2b7f194SVignesh R
35a2b7f194SVignesh R #define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ)
36a2b7f194SVignesh R
spi_nor_read_write_reg(struct spi_nor * nor,struct spi_mem_op * op,void * buf)37e57032caSVignesh R static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
38e57032caSVignesh R *op, void *buf)
39e57032caSVignesh R {
40e57032caSVignesh R if (op->data.dir == SPI_MEM_DATA_IN)
41e57032caSVignesh R op->data.buf.in = buf;
42e57032caSVignesh R else
43e57032caSVignesh R op->data.buf.out = buf;
44e57032caSVignesh R return spi_mem_exec_op(nor->spi, op);
45e57032caSVignesh R }
46e57032caSVignesh R
spi_nor_read_reg(struct spi_nor * nor,u8 code,u8 * val,int len)47a2b7f194SVignesh R static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
48a2b7f194SVignesh R {
49e57032caSVignesh R struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
50e57032caSVignesh R SPI_MEM_OP_NO_ADDR,
51e57032caSVignesh R SPI_MEM_OP_NO_DUMMY,
52e57032caSVignesh R SPI_MEM_OP_DATA_IN(len, NULL, 1));
53e57032caSVignesh R int ret;
54e57032caSVignesh R
55e57032caSVignesh R ret = spi_nor_read_write_reg(nor, &op, val);
56e57032caSVignesh R if (ret < 0)
57e57032caSVignesh R dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
58e57032caSVignesh R code);
59e57032caSVignesh R
60e57032caSVignesh R return ret;
61a2b7f194SVignesh R }
62a2b7f194SVignesh R
spi_nor_write_reg(struct spi_nor * nor,u8 opcode,u8 * buf,int len)63a2b7f194SVignesh R static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
64a2b7f194SVignesh R {
65e57032caSVignesh R struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
66e57032caSVignesh R SPI_MEM_OP_NO_ADDR,
67e57032caSVignesh R SPI_MEM_OP_NO_DUMMY,
68e57032caSVignesh R SPI_MEM_OP_DATA_OUT(len, NULL, 1));
69e57032caSVignesh R
70e57032caSVignesh R return spi_nor_read_write_reg(nor, &op, buf);
71a2b7f194SVignesh R }
72a2b7f194SVignesh R
spi_nor_read_data(struct spi_nor * nor,loff_t from,size_t len,u_char * buf)73a2b7f194SVignesh R static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
74a2b7f194SVignesh R u_char *buf)
75a2b7f194SVignesh R {
76e57032caSVignesh R struct spi_mem_op op =
77e57032caSVignesh R SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
78e57032caSVignesh R SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
79e57032caSVignesh R SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
80e57032caSVignesh R SPI_MEM_OP_DATA_IN(len, buf, 1));
81e57032caSVignesh R size_t remaining = len;
82e57032caSVignesh R int ret;
83e57032caSVignesh R
84e57032caSVignesh R /* get transfer protocols. */
85e57032caSVignesh R op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
86e57032caSVignesh R op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
87e57032caSVignesh R op.dummy.buswidth = op.addr.buswidth;
88e57032caSVignesh R op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
89e57032caSVignesh R
90e57032caSVignesh R /* convert the dummy cycles to the number of bytes */
91e57032caSVignesh R op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
92e57032caSVignesh R
93e57032caSVignesh R while (remaining) {
94e57032caSVignesh R op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
95e57032caSVignesh R ret = spi_mem_adjust_op_size(nor->spi, &op);
96e57032caSVignesh R if (ret)
97e57032caSVignesh R return ret;
98e57032caSVignesh R
99e57032caSVignesh R ret = spi_mem_exec_op(nor->spi, &op);
100e57032caSVignesh R if (ret)
101e57032caSVignesh R return ret;
102e57032caSVignesh R
103e57032caSVignesh R op.addr.val += op.data.nbytes;
104e57032caSVignesh R remaining -= op.data.nbytes;
105e57032caSVignesh R op.data.buf.in += op.data.nbytes;
106e57032caSVignesh R }
107e57032caSVignesh R
108e57032caSVignesh R return len;
109a2b7f194SVignesh R }
110a2b7f194SVignesh R
spi_nor_write_data(struct spi_nor * nor,loff_t to,size_t len,const u_char * buf)111a2b7f194SVignesh R static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
112a2b7f194SVignesh R const u_char *buf)
113a2b7f194SVignesh R {
114e57032caSVignesh R struct spi_mem_op op =
115e57032caSVignesh R SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
116e57032caSVignesh R SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
117e57032caSVignesh R SPI_MEM_OP_NO_DUMMY,
118e57032caSVignesh R SPI_MEM_OP_DATA_OUT(len, buf, 1));
119e57032caSVignesh R int ret;
120e57032caSVignesh R
121e57032caSVignesh R /* get transfer protocols. */
122e57032caSVignesh R op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
123e57032caSVignesh R op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
124e57032caSVignesh R op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
125e57032caSVignesh R
126e57032caSVignesh R if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
127e57032caSVignesh R op.addr.nbytes = 0;
128e57032caSVignesh R
129e57032caSVignesh R ret = spi_mem_adjust_op_size(nor->spi, &op);
130e57032caSVignesh R if (ret)
131e57032caSVignesh R return ret;
1320b841403SWeijie Gao op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
133e57032caSVignesh R
134e57032caSVignesh R ret = spi_mem_exec_op(nor->spi, &op);
135e57032caSVignesh R if (ret)
136e57032caSVignesh R return ret;
137e57032caSVignesh R
1380b841403SWeijie Gao return op.data.nbytes;
139a2b7f194SVignesh R }
140a2b7f194SVignesh R
141a2b7f194SVignesh R /*
142a2b7f194SVignesh R * Read the status register, returning its value in the location
143a2b7f194SVignesh R * Return the status register value.
144a2b7f194SVignesh R * Returns negative if error occurred.
145a2b7f194SVignesh R */
read_sr(struct spi_nor * nor)146a2b7f194SVignesh R static int read_sr(struct spi_nor *nor)
147a2b7f194SVignesh R {
148a2b7f194SVignesh R int ret;
149a2b7f194SVignesh R u8 val;
150a2b7f194SVignesh R
151a2b7f194SVignesh R ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
152a2b7f194SVignesh R if (ret < 0) {
153a2b7f194SVignesh R pr_debug("error %d reading SR\n", (int)ret);
154a2b7f194SVignesh R return ret;
155a2b7f194SVignesh R }
156a2b7f194SVignesh R
157a2b7f194SVignesh R return val;
158a2b7f194SVignesh R }
159a2b7f194SVignesh R
160a2b7f194SVignesh R /*
161a2b7f194SVignesh R * Read the flag status register, returning its value in the location
162a2b7f194SVignesh R * Return the status register value.
163a2b7f194SVignesh R * Returns negative if error occurred.
164a2b7f194SVignesh R */
read_fsr(struct spi_nor * nor)165a2b7f194SVignesh R static int read_fsr(struct spi_nor *nor)
166a2b7f194SVignesh R {
167a2b7f194SVignesh R int ret;
168a2b7f194SVignesh R u8 val;
169a2b7f194SVignesh R
170a2b7f194SVignesh R ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
171a2b7f194SVignesh R if (ret < 0) {
172a2b7f194SVignesh R pr_debug("error %d reading FSR\n", ret);
173a2b7f194SVignesh R return ret;
174a2b7f194SVignesh R }
175a2b7f194SVignesh R
176a2b7f194SVignesh R return val;
177a2b7f194SVignesh R }
178a2b7f194SVignesh R
179a2b7f194SVignesh R /*
180a2b7f194SVignesh R * Read configuration register, returning its value in the
181a2b7f194SVignesh R * location. Return the configuration register value.
182a2b7f194SVignesh R * Returns negative if error occurred.
183a2b7f194SVignesh R */
1841f301960SJon Lin #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) || defined(CONFIG_SPI_FLASH_NORMEM)
read_cr(struct spi_nor * nor)185a2b7f194SVignesh R static int read_cr(struct spi_nor *nor)
186a2b7f194SVignesh R {
187a2b7f194SVignesh R int ret;
188a2b7f194SVignesh R u8 val;
189a2b7f194SVignesh R
190a2b7f194SVignesh R ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1);
191a2b7f194SVignesh R if (ret < 0) {
192a2b7f194SVignesh R dev_dbg(nor->dev, "error %d reading CR\n", ret);
193a2b7f194SVignesh R return ret;
194a2b7f194SVignesh R }
195a2b7f194SVignesh R
196a2b7f194SVignesh R return val;
197a2b7f194SVignesh R }
198a2b7f194SVignesh R #endif
199a2b7f194SVignesh R
200a2b7f194SVignesh R /*
201a2b7f194SVignesh R * Write status register 1 byte
202a2b7f194SVignesh R * Returns negative if error occurred.
203a2b7f194SVignesh R */
write_sr(struct spi_nor * nor,u8 val)204a2b7f194SVignesh R static int write_sr(struct spi_nor *nor, u8 val)
205a2b7f194SVignesh R {
206a2b7f194SVignesh R nor->cmd_buf[0] = val;
207a2b7f194SVignesh R return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
208a2b7f194SVignesh R }
209a2b7f194SVignesh R
2104c6d72aaSJon Lin #if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) || defined(CONFIG_SPI_FLASH_NORMEM)
2111f301960SJon Lin /*
2121f301960SJon Lin * Write confiture register 1 byte
2131f301960SJon Lin * Returns negative if error occurred.
2141f301960SJon Lin */
write_cr(struct spi_nor * nor,u8 val)2151f301960SJon Lin static int write_cr(struct spi_nor *nor, u8 val)
2161f301960SJon Lin {
2171f301960SJon Lin nor->cmd_buf[0] = val;
2181f301960SJon Lin return nor->write_reg(nor, SPINOR_OP_WRCR, nor->cmd_buf, 1);
2191f301960SJon Lin }
2201f301960SJon Lin #endif
2211f301960SJon Lin
222a2b7f194SVignesh R /*
223a2b7f194SVignesh R * Set write enable latch with Write Enable command.
224a2b7f194SVignesh R * Returns negative if error occurred.
225a2b7f194SVignesh R */
write_enable(struct spi_nor * nor)226a2b7f194SVignesh R static int write_enable(struct spi_nor *nor)
227a2b7f194SVignesh R {
228a2b7f194SVignesh R return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
229a2b7f194SVignesh R }
230a2b7f194SVignesh R
231a2b7f194SVignesh R /*
232a2b7f194SVignesh R * Send write disable instruction to the chip.
233a2b7f194SVignesh R */
write_disable(struct spi_nor * nor)234a2b7f194SVignesh R static int write_disable(struct spi_nor *nor)
235a2b7f194SVignesh R {
236a2b7f194SVignesh R return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
237a2b7f194SVignesh R }
238a2b7f194SVignesh R
mtd_to_spi_nor(struct mtd_info * mtd)239a2b7f194SVignesh R static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
240a2b7f194SVignesh R {
241a2b7f194SVignesh R return mtd->priv;
242a2b7f194SVignesh R }
243a2b7f194SVignesh R
244dc6fa43fSVignesh R #ifndef CONFIG_SPI_FLASH_BAR
spi_nor_convert_opcode(u8 opcode,const u8 table[][2],size_t size)245cd157505SVignesh R static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
246cd157505SVignesh R {
247cd157505SVignesh R size_t i;
248cd157505SVignesh R
249cd157505SVignesh R for (i = 0; i < size; i++)
250cd157505SVignesh R if (table[i][0] == opcode)
251cd157505SVignesh R return table[i][1];
252cd157505SVignesh R
253cd157505SVignesh R /* No conversion found, keep input op code. */
254cd157505SVignesh R return opcode;
255cd157505SVignesh R }
256cd157505SVignesh R
spi_nor_convert_3to4_read(u8 opcode)257cd157505SVignesh R static u8 spi_nor_convert_3to4_read(u8 opcode)
258cd157505SVignesh R {
259cd157505SVignesh R static const u8 spi_nor_3to4_read[][2] = {
260cd157505SVignesh R { SPINOR_OP_READ, SPINOR_OP_READ_4B },
261cd157505SVignesh R { SPINOR_OP_READ_FAST, SPINOR_OP_READ_FAST_4B },
262cd157505SVignesh R { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B },
263cd157505SVignesh R { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
264cd157505SVignesh R { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
265cd157505SVignesh R { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
266305d7e6eSVignesh Raghavendra { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B },
267305d7e6eSVignesh Raghavendra { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B },
268cd157505SVignesh R
269cd157505SVignesh R { SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B },
270cd157505SVignesh R { SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B },
271cd157505SVignesh R { SPINOR_OP_READ_1_4_4_DTR, SPINOR_OP_READ_1_4_4_DTR_4B },
272cd157505SVignesh R };
273cd157505SVignesh R
274cd157505SVignesh R return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
275cd157505SVignesh R ARRAY_SIZE(spi_nor_3to4_read));
276cd157505SVignesh R }
277cd157505SVignesh R
spi_nor_convert_3to4_program(u8 opcode)278cd157505SVignesh R static u8 spi_nor_convert_3to4_program(u8 opcode)
279cd157505SVignesh R {
280cd157505SVignesh R static const u8 spi_nor_3to4_program[][2] = {
281cd157505SVignesh R { SPINOR_OP_PP, SPINOR_OP_PP_4B },
282cd157505SVignesh R { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B },
283cd157505SVignesh R { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B },
284305d7e6eSVignesh Raghavendra { SPINOR_OP_PP_1_1_8, SPINOR_OP_PP_1_1_8_4B },
285305d7e6eSVignesh Raghavendra { SPINOR_OP_PP_1_8_8, SPINOR_OP_PP_1_8_8_4B },
286cd157505SVignesh R };
287cd157505SVignesh R
288cd157505SVignesh R return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
289cd157505SVignesh R ARRAY_SIZE(spi_nor_3to4_program));
290cd157505SVignesh R }
291cd157505SVignesh R
spi_nor_convert_3to4_erase(u8 opcode)292cd157505SVignesh R static u8 spi_nor_convert_3to4_erase(u8 opcode)
293cd157505SVignesh R {
294cd157505SVignesh R static const u8 spi_nor_3to4_erase[][2] = {
295cd157505SVignesh R { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B },
296cd157505SVignesh R { SPINOR_OP_BE_32K, SPINOR_OP_BE_32K_4B },
297cd157505SVignesh R { SPINOR_OP_SE, SPINOR_OP_SE_4B },
298cd157505SVignesh R };
299cd157505SVignesh R
300cd157505SVignesh R return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
301cd157505SVignesh R ARRAY_SIZE(spi_nor_3to4_erase));
302cd157505SVignesh R }
303cd157505SVignesh R
spi_nor_set_4byte_opcodes(struct spi_nor * nor,const struct flash_info * info)304cd157505SVignesh R static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
305cd157505SVignesh R const struct flash_info *info)
306cd157505SVignesh R {
307cd157505SVignesh R /* Do some manufacturer fixups first */
308cd157505SVignesh R switch (JEDEC_MFR(info)) {
309cd157505SVignesh R case SNOR_MFR_SPANSION:
310cd157505SVignesh R /* No small sector erase for 4-byte command set */
311cd157505SVignesh R nor->erase_opcode = SPINOR_OP_SE;
312cd157505SVignesh R nor->mtd.erasesize = info->sector_size;
313cd157505SVignesh R break;
314cd157505SVignesh R
315cd157505SVignesh R default:
316cd157505SVignesh R break;
317cd157505SVignesh R }
318cd157505SVignesh R
319cd157505SVignesh R nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
320cd157505SVignesh R nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
321cd157505SVignesh R nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
322cd157505SVignesh R }
323dc6fa43fSVignesh R #endif /* !CONFIG_SPI_FLASH_BAR */
324cd157505SVignesh R
325cd157505SVignesh R /* Enable/disable 4-byte addressing mode. */
set_4byte(struct spi_nor * nor,const struct flash_info * info,int enable)326cd157505SVignesh R static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
327cd157505SVignesh R int enable)
328cd157505SVignesh R {
329cd157505SVignesh R int status;
330cd157505SVignesh R bool need_wren = false;
331cd157505SVignesh R u8 cmd;
332cd157505SVignesh R
333cd157505SVignesh R switch (JEDEC_MFR(info)) {
334cd157505SVignesh R case SNOR_MFR_ST:
335cd157505SVignesh R case SNOR_MFR_MICRON:
336cd157505SVignesh R /* Some Micron need WREN command; all will accept it */
337cd157505SVignesh R need_wren = true;
338cd157505SVignesh R case SNOR_MFR_MACRONIX:
339cd157505SVignesh R case SNOR_MFR_WINBOND:
340cd157505SVignesh R if (need_wren)
341cd157505SVignesh R write_enable(nor);
342cd157505SVignesh R
343cd157505SVignesh R cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
344cd157505SVignesh R status = nor->write_reg(nor, cmd, NULL, 0);
345cd157505SVignesh R if (need_wren)
346cd157505SVignesh R write_disable(nor);
347cd157505SVignesh R
348cd157505SVignesh R if (!status && !enable &&
349cd157505SVignesh R JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
350cd157505SVignesh R /*
351cd157505SVignesh R * On Winbond W25Q256FV, leaving 4byte mode causes
352cd157505SVignesh R * the Extended Address Register to be set to 1, so all
353cd157505SVignesh R * 3-byte-address reads come from the second 16M.
354cd157505SVignesh R * We must clear the register to enable normal behavior.
355cd157505SVignesh R */
356cd157505SVignesh R write_enable(nor);
357cd157505SVignesh R nor->cmd_buf[0] = 0;
358cd157505SVignesh R nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1);
359cd157505SVignesh R write_disable(nor);
360cd157505SVignesh R }
361cd157505SVignesh R
362cd157505SVignesh R return status;
363cd157505SVignesh R default:
364cd157505SVignesh R /* Spansion style */
365cd157505SVignesh R nor->cmd_buf[0] = enable << 7;
366cd157505SVignesh R return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
367cd157505SVignesh R }
368cd157505SVignesh R }
369cd157505SVignesh R
spi_nor_sr_ready(struct spi_nor * nor)370a2b7f194SVignesh R static int spi_nor_sr_ready(struct spi_nor *nor)
371a2b7f194SVignesh R {
372a2b7f194SVignesh R int sr = read_sr(nor);
373a2b7f194SVignesh R
374a2b7f194SVignesh R if (sr < 0)
375a2b7f194SVignesh R return sr;
376a2b7f194SVignesh R
377a2b7f194SVignesh R if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) {
378a2b7f194SVignesh R if (sr & SR_E_ERR)
379a2b7f194SVignesh R dev_dbg(nor->dev, "Erase Error occurred\n");
380a2b7f194SVignesh R else
381a2b7f194SVignesh R dev_dbg(nor->dev, "Programming Error occurred\n");
382a2b7f194SVignesh R
383a2b7f194SVignesh R nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
384a2b7f194SVignesh R return -EIO;
385a2b7f194SVignesh R }
386a2b7f194SVignesh R
387a2b7f194SVignesh R return !(sr & SR_WIP);
388a2b7f194SVignesh R }
389a2b7f194SVignesh R
spi_nor_fsr_ready(struct spi_nor * nor)390a2b7f194SVignesh R static int spi_nor_fsr_ready(struct spi_nor *nor)
391a2b7f194SVignesh R {
392a2b7f194SVignesh R int fsr = read_fsr(nor);
393a2b7f194SVignesh R
394a2b7f194SVignesh R if (fsr < 0)
395a2b7f194SVignesh R return fsr;
396a2b7f194SVignesh R
397a2b7f194SVignesh R if (fsr & (FSR_E_ERR | FSR_P_ERR)) {
398a2b7f194SVignesh R if (fsr & FSR_E_ERR)
3993f2f32bfSVignesh Raghavendra dev_err(nor->dev, "Erase operation failed.\n");
400a2b7f194SVignesh R else
4013f2f32bfSVignesh Raghavendra dev_err(nor->dev, "Program operation failed.\n");
402a2b7f194SVignesh R
403a2b7f194SVignesh R if (fsr & FSR_PT_ERR)
4043f2f32bfSVignesh Raghavendra dev_err(nor->dev,
405a2b7f194SVignesh R "Attempted to modify a protected sector.\n");
406a2b7f194SVignesh R
407a2b7f194SVignesh R nor->write_reg(nor, SPINOR_OP_CLFSR, NULL, 0);
408a2b7f194SVignesh R return -EIO;
409a2b7f194SVignesh R }
410a2b7f194SVignesh R
411a2b7f194SVignesh R return fsr & FSR_READY;
412a2b7f194SVignesh R }
413a2b7f194SVignesh R
spi_nor_ready(struct spi_nor * nor)414a2b7f194SVignesh R static int spi_nor_ready(struct spi_nor *nor)
415a2b7f194SVignesh R {
416a2b7f194SVignesh R int sr, fsr;
417a2b7f194SVignesh R
418a2b7f194SVignesh R sr = spi_nor_sr_ready(nor);
419a2b7f194SVignesh R if (sr < 0)
420a2b7f194SVignesh R return sr;
421a2b7f194SVignesh R fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
422a2b7f194SVignesh R if (fsr < 0)
423a2b7f194SVignesh R return fsr;
424a2b7f194SVignesh R return sr && fsr;
425a2b7f194SVignesh R }
426a2b7f194SVignesh R
427a2b7f194SVignesh R /*
428a2b7f194SVignesh R * Service routine to read status register until ready, or timeout occurs.
429a2b7f194SVignesh R * Returns non-zero if error.
430a2b7f194SVignesh R */
spi_nor_wait_till_ready_with_timeout(struct spi_nor * nor,unsigned long timeout)431a2b7f194SVignesh R static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
432a2b7f194SVignesh R unsigned long timeout)
433a2b7f194SVignesh R {
434a2b7f194SVignesh R unsigned long timebase;
435a2b7f194SVignesh R int ret;
436a2b7f194SVignesh R
437a2b7f194SVignesh R timebase = get_timer(0);
438a2b7f194SVignesh R
439a2b7f194SVignesh R while (get_timer(timebase) < timeout) {
440a2b7f194SVignesh R ret = spi_nor_ready(nor);
441a2b7f194SVignesh R if (ret < 0)
442a2b7f194SVignesh R return ret;
443a2b7f194SVignesh R if (ret)
444a2b7f194SVignesh R return 0;
445a2b7f194SVignesh R }
446a2b7f194SVignesh R
447a2b7f194SVignesh R dev_err(nor->dev, "flash operation timed out\n");
448a2b7f194SVignesh R
449a2b7f194SVignesh R return -ETIMEDOUT;
450a2b7f194SVignesh R }
451a2b7f194SVignesh R
spi_nor_wait_till_ready(struct spi_nor * nor)452a2b7f194SVignesh R static int spi_nor_wait_till_ready(struct spi_nor *nor)
453a2b7f194SVignesh R {
454a2b7f194SVignesh R return spi_nor_wait_till_ready_with_timeout(nor,
455a2b7f194SVignesh R DEFAULT_READY_WAIT_JIFFIES);
456a2b7f194SVignesh R }
457a2b7f194SVignesh R
458dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
459dc6fa43fSVignesh R /*
460dc6fa43fSVignesh R * This "clean_bar" is necessary in a situation when one was accessing
461dc6fa43fSVignesh R * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit.
462dc6fa43fSVignesh R *
463dc6fa43fSVignesh R * After it the BA24 bit shall be cleared to allow access to correct
464dc6fa43fSVignesh R * memory region after SW reset (by calling "reset" command).
465dc6fa43fSVignesh R *
466dc6fa43fSVignesh R * Otherwise, the BA24 bit may be left set and then after reset, the
467dc6fa43fSVignesh R * ROM would read/write/erase SPL from 16 MiB * bank_sel address.
468dc6fa43fSVignesh R */
clean_bar(struct spi_nor * nor)469dc6fa43fSVignesh R static int clean_bar(struct spi_nor *nor)
470dc6fa43fSVignesh R {
471dc6fa43fSVignesh R u8 cmd, bank_sel = 0;
472dc6fa43fSVignesh R
473dc6fa43fSVignesh R if (nor->bank_curr == 0)
474dc6fa43fSVignesh R return 0;
475dc6fa43fSVignesh R cmd = nor->bank_write_cmd;
476dc6fa43fSVignesh R nor->bank_curr = 0;
477dc6fa43fSVignesh R write_enable(nor);
478dc6fa43fSVignesh R
479dc6fa43fSVignesh R return nor->write_reg(nor, cmd, &bank_sel, 1);
480dc6fa43fSVignesh R }
481dc6fa43fSVignesh R
write_bar(struct spi_nor * nor,u32 offset)482dc6fa43fSVignesh R static int write_bar(struct spi_nor *nor, u32 offset)
483dc6fa43fSVignesh R {
484dc6fa43fSVignesh R u8 cmd, bank_sel;
485dc6fa43fSVignesh R int ret;
486dc6fa43fSVignesh R
487dc6fa43fSVignesh R bank_sel = offset / SZ_16M;
488dc6fa43fSVignesh R if (bank_sel == nor->bank_curr)
489dc6fa43fSVignesh R goto bar_end;
490dc6fa43fSVignesh R
491dc6fa43fSVignesh R cmd = nor->bank_write_cmd;
492dc6fa43fSVignesh R write_enable(nor);
493dc6fa43fSVignesh R ret = nor->write_reg(nor, cmd, &bank_sel, 1);
494dc6fa43fSVignesh R if (ret < 0) {
495dc6fa43fSVignesh R debug("SF: fail to write bank register\n");
496dc6fa43fSVignesh R return ret;
497dc6fa43fSVignesh R }
498dc6fa43fSVignesh R
499dc6fa43fSVignesh R bar_end:
500dc6fa43fSVignesh R nor->bank_curr = bank_sel;
501dc6fa43fSVignesh R return nor->bank_curr;
502dc6fa43fSVignesh R }
503dc6fa43fSVignesh R
read_bar(struct spi_nor * nor,const struct flash_info * info)504dc6fa43fSVignesh R static int read_bar(struct spi_nor *nor, const struct flash_info *info)
505dc6fa43fSVignesh R {
506dc6fa43fSVignesh R u8 curr_bank = 0;
507dc6fa43fSVignesh R int ret;
508dc6fa43fSVignesh R
509dc6fa43fSVignesh R switch (JEDEC_MFR(info)) {
510dc6fa43fSVignesh R case SNOR_MFR_SPANSION:
511dc6fa43fSVignesh R nor->bank_read_cmd = SPINOR_OP_BRRD;
512dc6fa43fSVignesh R nor->bank_write_cmd = SPINOR_OP_BRWR;
513dc6fa43fSVignesh R break;
514dc6fa43fSVignesh R default:
515dc6fa43fSVignesh R nor->bank_read_cmd = SPINOR_OP_RDEAR;
516dc6fa43fSVignesh R nor->bank_write_cmd = SPINOR_OP_WREAR;
517dc6fa43fSVignesh R }
518dc6fa43fSVignesh R
519dc6fa43fSVignesh R ret = nor->read_reg(nor, nor->bank_read_cmd,
520dc6fa43fSVignesh R &curr_bank, 1);
521dc6fa43fSVignesh R if (ret) {
522dc6fa43fSVignesh R debug("SF: fail to read bank addr register\n");
523dc6fa43fSVignesh R return ret;
524dc6fa43fSVignesh R }
525dc6fa43fSVignesh R nor->bank_curr = curr_bank;
526dc6fa43fSVignesh R
527dc6fa43fSVignesh R return 0;
528dc6fa43fSVignesh R }
529dc6fa43fSVignesh R #endif
530dc6fa43fSVignesh R
531a2b7f194SVignesh R /*
532a2b7f194SVignesh R * Initiate the erasure of a single sector
533a2b7f194SVignesh R */
spi_nor_erase_sector(struct spi_nor * nor,u32 addr)534a2b7f194SVignesh R static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
535a2b7f194SVignesh R {
536c4a1b055SMarek Vasut struct spi_mem_op op =
537c4a1b055SMarek Vasut SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
538c4a1b055SMarek Vasut SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
539c4a1b055SMarek Vasut SPI_MEM_OP_NO_DUMMY,
540c4a1b055SMarek Vasut SPI_MEM_OP_NO_DATA);
541a2b7f194SVignesh R
542a2b7f194SVignesh R if (nor->erase)
543a2b7f194SVignesh R return nor->erase(nor, addr);
544a2b7f194SVignesh R
545a2b7f194SVignesh R /*
546a2b7f194SVignesh R * Default implementation, if driver doesn't have a specialized HW
547a2b7f194SVignesh R * control
548a2b7f194SVignesh R */
549c4a1b055SMarek Vasut return spi_mem_exec_op(nor->spi, &op);
550a2b7f194SVignesh R }
551a2b7f194SVignesh R
552a2b7f194SVignesh R /*
553a2b7f194SVignesh R * Erase an address range on the nor chip. The address range may extend
554a2b7f194SVignesh R * one or more erase sectors. Return an error is there is a problem erasing.
555a2b7f194SVignesh R */
spi_nor_erase(struct mtd_info * mtd,struct erase_info * instr)556a2b7f194SVignesh R static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
557a2b7f194SVignesh R {
558a2b7f194SVignesh R struct spi_nor *nor = mtd_to_spi_nor(mtd);
559*2cf66459SJon Lin u32 addr, len, rem, target;
560a2b7f194SVignesh R int ret;
561a2b7f194SVignesh R
562a2b7f194SVignesh R dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
563a2b7f194SVignesh R (long long)instr->len);
564a2b7f194SVignesh R
565a2b7f194SVignesh R div_u64_rem(instr->len, mtd->erasesize, &rem);
566a2b7f194SVignesh R if (rem)
567a2b7f194SVignesh R return -EINVAL;
568a2b7f194SVignesh R
569a2b7f194SVignesh R addr = instr->addr;
570a2b7f194SVignesh R len = instr->len;
571a2b7f194SVignesh R
572a2b7f194SVignesh R while (len) {
573*2cf66459SJon Lin #if defined(CONFIG_SPI_FLASH_AUTO_MERGE)
574*2cf66459SJon Lin nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1;
575*2cf66459SJon Lin target = addr - nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size;
576*2cf66459SJon Lin #else
577*2cf66459SJon Lin target = addr;
578*2cf66459SJon Lin #endif
579dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
580*2cf66459SJon Lin ret = write_bar(nor, target);
581dc6fa43fSVignesh R if (ret < 0)
582dc6fa43fSVignesh R return ret;
583dc6fa43fSVignesh R #endif
584a2b7f194SVignesh R write_enable(nor);
585a2b7f194SVignesh R
586*2cf66459SJon Lin ret = spi_nor_erase_sector(nor, target);
587a2b7f194SVignesh R if (ret)
588a2b7f194SVignesh R goto erase_err;
589a2b7f194SVignesh R
590a2b7f194SVignesh R addr += mtd->erasesize;
591a2b7f194SVignesh R len -= mtd->erasesize;
592a2b7f194SVignesh R
593a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
594a2b7f194SVignesh R if (ret)
595a2b7f194SVignesh R goto erase_err;
596a2b7f194SVignesh R }
597a2b7f194SVignesh R
598dc6fa43fSVignesh R erase_err:
599dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
600dc6fa43fSVignesh R ret = clean_bar(nor);
601dc6fa43fSVignesh R #endif
602a2b7f194SVignesh R write_disable(nor);
603a2b7f194SVignesh R
604a2b7f194SVignesh R return ret;
605a2b7f194SVignesh R }
606a2b7f194SVignesh R
607a2b7f194SVignesh R #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
608a2b7f194SVignesh R /* Write status register and ensure bits in mask match written values */
write_sr_and_check(struct spi_nor * nor,u8 status_new,u8 mask)609a2b7f194SVignesh R static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
610a2b7f194SVignesh R {
611a2b7f194SVignesh R int ret;
612a2b7f194SVignesh R
613a2b7f194SVignesh R write_enable(nor);
614a2b7f194SVignesh R ret = write_sr(nor, status_new);
615a2b7f194SVignesh R if (ret)
616a2b7f194SVignesh R return ret;
617a2b7f194SVignesh R
618a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
619a2b7f194SVignesh R if (ret)
620a2b7f194SVignesh R return ret;
621a2b7f194SVignesh R
622a2b7f194SVignesh R ret = read_sr(nor);
623a2b7f194SVignesh R if (ret < 0)
624a2b7f194SVignesh R return ret;
625a2b7f194SVignesh R
626a2b7f194SVignesh R return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
627a2b7f194SVignesh R }
628a2b7f194SVignesh R
stm_get_locked_range(struct spi_nor * nor,u8 sr,loff_t * ofs,uint64_t * len)629a2b7f194SVignesh R static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
630a2b7f194SVignesh R uint64_t *len)
631a2b7f194SVignesh R {
632a2b7f194SVignesh R struct mtd_info *mtd = &nor->mtd;
633a2b7f194SVignesh R u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
634a2b7f194SVignesh R int shift = ffs(mask) - 1;
635a2b7f194SVignesh R int pow;
636a2b7f194SVignesh R
637a2b7f194SVignesh R if (!(sr & mask)) {
638a2b7f194SVignesh R /* No protection */
639a2b7f194SVignesh R *ofs = 0;
640a2b7f194SVignesh R *len = 0;
641a2b7f194SVignesh R } else {
642a2b7f194SVignesh R pow = ((sr & mask) ^ mask) >> shift;
643a2b7f194SVignesh R *len = mtd->size >> pow;
644a2b7f194SVignesh R if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
645a2b7f194SVignesh R *ofs = 0;
646a2b7f194SVignesh R else
647a2b7f194SVignesh R *ofs = mtd->size - *len;
648a2b7f194SVignesh R }
649a2b7f194SVignesh R }
650a2b7f194SVignesh R
651a2b7f194SVignesh R /*
652a2b7f194SVignesh R * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
653a2b7f194SVignesh R * @locked is false); 0 otherwise
654a2b7f194SVignesh R */
stm_check_lock_status_sr(struct spi_nor * nor,loff_t ofs,u64 len,u8 sr,bool locked)655a2b7f194SVignesh R static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, u64 len,
656a2b7f194SVignesh R u8 sr, bool locked)
657a2b7f194SVignesh R {
658a2b7f194SVignesh R loff_t lock_offs;
659a2b7f194SVignesh R uint64_t lock_len;
660a2b7f194SVignesh R
661a2b7f194SVignesh R if (!len)
662a2b7f194SVignesh R return 1;
663a2b7f194SVignesh R
664a2b7f194SVignesh R stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
665a2b7f194SVignesh R
666a2b7f194SVignesh R if (locked)
667a2b7f194SVignesh R /* Requested range is a sub-range of locked range */
668a2b7f194SVignesh R return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
669a2b7f194SVignesh R else
670a2b7f194SVignesh R /* Requested range does not overlap with locked range */
671a2b7f194SVignesh R return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
672a2b7f194SVignesh R }
673a2b7f194SVignesh R
stm_is_locked_sr(struct spi_nor * nor,loff_t ofs,uint64_t len,u8 sr)674a2b7f194SVignesh R static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
675a2b7f194SVignesh R u8 sr)
676a2b7f194SVignesh R {
677a2b7f194SVignesh R return stm_check_lock_status_sr(nor, ofs, len, sr, true);
678a2b7f194SVignesh R }
679a2b7f194SVignesh R
stm_is_unlocked_sr(struct spi_nor * nor,loff_t ofs,uint64_t len,u8 sr)680a2b7f194SVignesh R static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
681a2b7f194SVignesh R u8 sr)
682a2b7f194SVignesh R {
683a2b7f194SVignesh R return stm_check_lock_status_sr(nor, ofs, len, sr, false);
684a2b7f194SVignesh R }
685a2b7f194SVignesh R
686a2b7f194SVignesh R /*
687a2b7f194SVignesh R * Lock a region of the flash. Compatible with ST Micro and similar flash.
688a2b7f194SVignesh R * Supports the block protection bits BP{0,1,2} in the status register
689a2b7f194SVignesh R * (SR). Does not support these features found in newer SR bitfields:
690a2b7f194SVignesh R * - SEC: sector/block protect - only handle SEC=0 (block protect)
691a2b7f194SVignesh R * - CMP: complement protect - only support CMP=0 (range is not complemented)
692a2b7f194SVignesh R *
693a2b7f194SVignesh R * Support for the following is provided conditionally for some flash:
694a2b7f194SVignesh R * - TB: top/bottom protect
695a2b7f194SVignesh R *
696a2b7f194SVignesh R * Sample table portion for 8MB flash (Winbond w25q64fw):
697a2b7f194SVignesh R *
698a2b7f194SVignesh R * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion
699a2b7f194SVignesh R * --------------------------------------------------------------------------
700a2b7f194SVignesh R * X | X | 0 | 0 | 0 | NONE | NONE
701a2b7f194SVignesh R * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64
702a2b7f194SVignesh R * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32
703a2b7f194SVignesh R * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16
704a2b7f194SVignesh R * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8
705a2b7f194SVignesh R * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4
706a2b7f194SVignesh R * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2
707a2b7f194SVignesh R * X | X | 1 | 1 | 1 | 8 MB | ALL
708a2b7f194SVignesh R * ------|-------|-------|-------|-------|---------------|-------------------
709a2b7f194SVignesh R * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64
710a2b7f194SVignesh R * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32
711a2b7f194SVignesh R * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16
712a2b7f194SVignesh R * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8
713a2b7f194SVignesh R * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4
714a2b7f194SVignesh R * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2
715a2b7f194SVignesh R *
716a2b7f194SVignesh R * Returns negative on errors, 0 on success.
717a2b7f194SVignesh R */
stm_lock(struct spi_nor * nor,loff_t ofs,uint64_t len)718a2b7f194SVignesh R static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
719a2b7f194SVignesh R {
720a2b7f194SVignesh R struct mtd_info *mtd = &nor->mtd;
721a2b7f194SVignesh R int status_old, status_new;
722a2b7f194SVignesh R u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
723a2b7f194SVignesh R u8 shift = ffs(mask) - 1, pow, val;
724a2b7f194SVignesh R loff_t lock_len;
725a2b7f194SVignesh R bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
726a2b7f194SVignesh R bool use_top;
727a2b7f194SVignesh R
728a2b7f194SVignesh R status_old = read_sr(nor);
729a2b7f194SVignesh R if (status_old < 0)
730a2b7f194SVignesh R return status_old;
731a2b7f194SVignesh R
732a2b7f194SVignesh R /* If nothing in our range is unlocked, we don't need to do anything */
733a2b7f194SVignesh R if (stm_is_locked_sr(nor, ofs, len, status_old))
734a2b7f194SVignesh R return 0;
735a2b7f194SVignesh R
736a2b7f194SVignesh R /* If anything below us is unlocked, we can't use 'bottom' protection */
737a2b7f194SVignesh R if (!stm_is_locked_sr(nor, 0, ofs, status_old))
738a2b7f194SVignesh R can_be_bottom = false;
739a2b7f194SVignesh R
740a2b7f194SVignesh R /* If anything above us is unlocked, we can't use 'top' protection */
741a2b7f194SVignesh R if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
742a2b7f194SVignesh R status_old))
743a2b7f194SVignesh R can_be_top = false;
744a2b7f194SVignesh R
745a2b7f194SVignesh R if (!can_be_bottom && !can_be_top)
746a2b7f194SVignesh R return -EINVAL;
747a2b7f194SVignesh R
748a2b7f194SVignesh R /* Prefer top, if both are valid */
749a2b7f194SVignesh R use_top = can_be_top;
750a2b7f194SVignesh R
751a2b7f194SVignesh R /* lock_len: length of region that should end up locked */
752a2b7f194SVignesh R if (use_top)
753a2b7f194SVignesh R lock_len = mtd->size - ofs;
754a2b7f194SVignesh R else
755a2b7f194SVignesh R lock_len = ofs + len;
756a2b7f194SVignesh R
757a2b7f194SVignesh R /*
758a2b7f194SVignesh R * Need smallest pow such that:
759a2b7f194SVignesh R *
760a2b7f194SVignesh R * 1 / (2^pow) <= (len / size)
761a2b7f194SVignesh R *
762a2b7f194SVignesh R * so (assuming power-of-2 size) we do:
763a2b7f194SVignesh R *
764a2b7f194SVignesh R * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
765a2b7f194SVignesh R */
766a2b7f194SVignesh R pow = ilog2(mtd->size) - ilog2(lock_len);
767a2b7f194SVignesh R val = mask - (pow << shift);
768a2b7f194SVignesh R if (val & ~mask)
769a2b7f194SVignesh R return -EINVAL;
770a2b7f194SVignesh R /* Don't "lock" with no region! */
771a2b7f194SVignesh R if (!(val & mask))
772a2b7f194SVignesh R return -EINVAL;
773a2b7f194SVignesh R
774a2b7f194SVignesh R status_new = (status_old & ~mask & ~SR_TB) | val;
775a2b7f194SVignesh R
776a2b7f194SVignesh R /* Disallow further writes if WP pin is asserted */
777a2b7f194SVignesh R status_new |= SR_SRWD;
778a2b7f194SVignesh R
779a2b7f194SVignesh R if (!use_top)
780a2b7f194SVignesh R status_new |= SR_TB;
781a2b7f194SVignesh R
782a2b7f194SVignesh R /* Don't bother if they're the same */
783a2b7f194SVignesh R if (status_new == status_old)
784a2b7f194SVignesh R return 0;
785a2b7f194SVignesh R
786a2b7f194SVignesh R /* Only modify protection if it will not unlock other areas */
787a2b7f194SVignesh R if ((status_new & mask) < (status_old & mask))
788a2b7f194SVignesh R return -EINVAL;
789a2b7f194SVignesh R
790a2b7f194SVignesh R return write_sr_and_check(nor, status_new, mask);
791a2b7f194SVignesh R }
792a2b7f194SVignesh R
793a2b7f194SVignesh R /*
794a2b7f194SVignesh R * Unlock a region of the flash. See stm_lock() for more info
795a2b7f194SVignesh R *
796a2b7f194SVignesh R * Returns negative on errors, 0 on success.
797a2b7f194SVignesh R */
stm_unlock(struct spi_nor * nor,loff_t ofs,uint64_t len)798a2b7f194SVignesh R static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
799a2b7f194SVignesh R {
800a2b7f194SVignesh R struct mtd_info *mtd = &nor->mtd;
801a2b7f194SVignesh R int status_old, status_new;
802a2b7f194SVignesh R u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
803a2b7f194SVignesh R u8 shift = ffs(mask) - 1, pow, val;
804a2b7f194SVignesh R loff_t lock_len;
805a2b7f194SVignesh R bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
806a2b7f194SVignesh R bool use_top;
807a2b7f194SVignesh R
808a2b7f194SVignesh R status_old = read_sr(nor);
809a2b7f194SVignesh R if (status_old < 0)
810a2b7f194SVignesh R return status_old;
811a2b7f194SVignesh R
812a2b7f194SVignesh R /* If nothing in our range is locked, we don't need to do anything */
813a2b7f194SVignesh R if (stm_is_unlocked_sr(nor, ofs, len, status_old))
814a2b7f194SVignesh R return 0;
815a2b7f194SVignesh R
816a2b7f194SVignesh R /* If anything below us is locked, we can't use 'top' protection */
817a2b7f194SVignesh R if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
818a2b7f194SVignesh R can_be_top = false;
819a2b7f194SVignesh R
820a2b7f194SVignesh R /* If anything above us is locked, we can't use 'bottom' protection */
821a2b7f194SVignesh R if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
822a2b7f194SVignesh R status_old))
823a2b7f194SVignesh R can_be_bottom = false;
824a2b7f194SVignesh R
825a2b7f194SVignesh R if (!can_be_bottom && !can_be_top)
826a2b7f194SVignesh R return -EINVAL;
827a2b7f194SVignesh R
828a2b7f194SVignesh R /* Prefer top, if both are valid */
829a2b7f194SVignesh R use_top = can_be_top;
830a2b7f194SVignesh R
831a2b7f194SVignesh R /* lock_len: length of region that should remain locked */
832a2b7f194SVignesh R if (use_top)
833a2b7f194SVignesh R lock_len = mtd->size - (ofs + len);
834a2b7f194SVignesh R else
835a2b7f194SVignesh R lock_len = ofs;
836a2b7f194SVignesh R
837a2b7f194SVignesh R /*
838a2b7f194SVignesh R * Need largest pow such that:
839a2b7f194SVignesh R *
840a2b7f194SVignesh R * 1 / (2^pow) >= (len / size)
841a2b7f194SVignesh R *
842a2b7f194SVignesh R * so (assuming power-of-2 size) we do:
843a2b7f194SVignesh R *
844a2b7f194SVignesh R * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
845a2b7f194SVignesh R */
846a2b7f194SVignesh R pow = ilog2(mtd->size) - order_base_2(lock_len);
847a2b7f194SVignesh R if (lock_len == 0) {
848a2b7f194SVignesh R val = 0; /* fully unlocked */
849a2b7f194SVignesh R } else {
850a2b7f194SVignesh R val = mask - (pow << shift);
851a2b7f194SVignesh R /* Some power-of-two sizes are not supported */
852a2b7f194SVignesh R if (val & ~mask)
853a2b7f194SVignesh R return -EINVAL;
854a2b7f194SVignesh R }
855a2b7f194SVignesh R
856a2b7f194SVignesh R status_new = (status_old & ~mask & ~SR_TB) | val;
857a2b7f194SVignesh R
858a2b7f194SVignesh R /* Don't protect status register if we're fully unlocked */
859a2b7f194SVignesh R if (lock_len == 0)
860a2b7f194SVignesh R status_new &= ~SR_SRWD;
861a2b7f194SVignesh R
862a2b7f194SVignesh R if (!use_top)
863a2b7f194SVignesh R status_new |= SR_TB;
864a2b7f194SVignesh R
865a2b7f194SVignesh R /* Don't bother if they're the same */
866a2b7f194SVignesh R if (status_new == status_old)
867a2b7f194SVignesh R return 0;
868a2b7f194SVignesh R
869a2b7f194SVignesh R /* Only modify protection if it will not lock other areas */
870a2b7f194SVignesh R if ((status_new & mask) > (status_old & mask))
871a2b7f194SVignesh R return -EINVAL;
872a2b7f194SVignesh R
873a2b7f194SVignesh R return write_sr_and_check(nor, status_new, mask);
874a2b7f194SVignesh R }
875a2b7f194SVignesh R
876a2b7f194SVignesh R /*
877a2b7f194SVignesh R * Check if a region of the flash is (completely) locked. See stm_lock() for
878a2b7f194SVignesh R * more info.
879a2b7f194SVignesh R *
880a2b7f194SVignesh R * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
881a2b7f194SVignesh R * negative on errors.
882a2b7f194SVignesh R */
stm_is_locked(struct spi_nor * nor,loff_t ofs,uint64_t len)883a2b7f194SVignesh R static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
884a2b7f194SVignesh R {
885a2b7f194SVignesh R int status;
886a2b7f194SVignesh R
887a2b7f194SVignesh R status = read_sr(nor);
888a2b7f194SVignesh R if (status < 0)
889a2b7f194SVignesh R return status;
890a2b7f194SVignesh R
891a2b7f194SVignesh R return stm_is_locked_sr(nor, ofs, len, status);
892a2b7f194SVignesh R }
893a2b7f194SVignesh R #endif /* CONFIG_SPI_FLASH_STMICRO */
894a2b7f194SVignesh R
spi_nor_read_id(struct spi_nor * nor)895a2b7f194SVignesh R static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
896a2b7f194SVignesh R {
897a2b7f194SVignesh R int tmp;
898a2b7f194SVignesh R u8 id[SPI_NOR_MAX_ID_LEN];
899a2b7f194SVignesh R const struct flash_info *info;
900a2b7f194SVignesh R
901a2b7f194SVignesh R tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
902a2b7f194SVignesh R if (tmp < 0) {
903a2b7f194SVignesh R dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
904a2b7f194SVignesh R return ERR_PTR(tmp);
905a2b7f194SVignesh R }
906a2b7f194SVignesh R
907da748245SVignesh R info = spi_nor_ids;
908da748245SVignesh R for (; info->name; info++) {
909a2b7f194SVignesh R if (info->id_len) {
910a2b7f194SVignesh R if (!memcmp(info->id, id, info->id_len))
911da748245SVignesh R return info;
912a2b7f194SVignesh R }
913a2b7f194SVignesh R }
914da748245SVignesh R
915a2b7f194SVignesh R dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
916a2b7f194SVignesh R id[0], id[1], id[2]);
917a2b7f194SVignesh R return ERR_PTR(-ENODEV);
918a2b7f194SVignesh R }
919a2b7f194SVignesh R
spi_nor_read(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)920a2b7f194SVignesh R static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
921a2b7f194SVignesh R size_t *retlen, u_char *buf)
922a2b7f194SVignesh R {
923a2b7f194SVignesh R struct spi_nor *nor = mtd_to_spi_nor(mtd);
924a2b7f194SVignesh R int ret;
925a2b7f194SVignesh R
926a2b7f194SVignesh R dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
927a2b7f194SVignesh R
928a2b7f194SVignesh R while (len) {
929a2b7f194SVignesh R loff_t addr = from;
930dc6fa43fSVignesh R size_t read_len = len;
931a2b7f194SVignesh R
932*2cf66459SJon Lin #if defined(CONFIG_SPI_FLASH_AUTO_MERGE)
933*2cf66459SJon Lin if (addr < nor->auto_merge_single_chip_size && (addr + len) > nor->auto_merge_single_chip_size)
934*2cf66459SJon Lin read_len = nor->auto_merge_single_chip_size - addr;
935*2cf66459SJon Lin nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1;
936*2cf66459SJon Lin addr -= nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size;
937*2cf66459SJon Lin #endif
938*2cf66459SJon Lin
939dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
940dc6fa43fSVignesh R u32 remain_len;
941dc6fa43fSVignesh R
942dc6fa43fSVignesh R ret = write_bar(nor, addr);
943dc6fa43fSVignesh R if (ret < 0)
944dc6fa43fSVignesh R return log_ret(ret);
945dc6fa43fSVignesh R remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr;
946dc6fa43fSVignesh R
947dc6fa43fSVignesh R if (len < remain_len)
948dc6fa43fSVignesh R read_len = len;
949dc6fa43fSVignesh R else
950dc6fa43fSVignesh R read_len = remain_len;
951dc6fa43fSVignesh R #endif
952dc6fa43fSVignesh R
953dc6fa43fSVignesh R ret = nor->read(nor, addr, read_len, buf);
954a2b7f194SVignesh R if (ret == 0) {
955a2b7f194SVignesh R /* We shouldn't see 0-length reads */
956a2b7f194SVignesh R ret = -EIO;
957a2b7f194SVignesh R goto read_err;
958a2b7f194SVignesh R }
959a2b7f194SVignesh R if (ret < 0)
960a2b7f194SVignesh R goto read_err;
961a2b7f194SVignesh R
962a2b7f194SVignesh R *retlen += ret;
963a2b7f194SVignesh R buf += ret;
964a2b7f194SVignesh R from += ret;
965a2b7f194SVignesh R len -= ret;
966a2b7f194SVignesh R }
967a2b7f194SVignesh R ret = 0;
968a2b7f194SVignesh R
969a2b7f194SVignesh R read_err:
970dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
971dc6fa43fSVignesh R ret = clean_bar(nor);
972dc6fa43fSVignesh R #endif
973a2b7f194SVignesh R return ret;
974a2b7f194SVignesh R }
975a2b7f194SVignesh R
976a2b7f194SVignesh R #ifdef CONFIG_SPI_FLASH_SST
9774b522e90SEugeniy Paltsev /*
9784b522e90SEugeniy Paltsev * sst26 flash series has its own block protection implementation:
9794b522e90SEugeniy Paltsev * 4x - 8 KByte blocks - read & write protection bits - upper addresses
9804b522e90SEugeniy Paltsev * 1x - 32 KByte blocks - write protection bits
9814b522e90SEugeniy Paltsev * rest - 64 KByte blocks - write protection bits
9824b522e90SEugeniy Paltsev * 1x - 32 KByte blocks - write protection bits
9834b522e90SEugeniy Paltsev * 4x - 8 KByte blocks - read & write protection bits - lower addresses
9844b522e90SEugeniy Paltsev *
9854b522e90SEugeniy Paltsev * We'll support only per 64k lock/unlock so lower and upper 64 KByte region
9864b522e90SEugeniy Paltsev * will be treated as single block.
9874b522e90SEugeniy Paltsev */
9884b522e90SEugeniy Paltsev #define SST26_BPR_8K_NUM 4
9894b522e90SEugeniy Paltsev #define SST26_MAX_BPR_REG_LEN (18 + 1)
9904b522e90SEugeniy Paltsev #define SST26_BOUND_REG_SIZE ((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
9914b522e90SEugeniy Paltsev
9924b522e90SEugeniy Paltsev enum lock_ctl {
9934b522e90SEugeniy Paltsev SST26_CTL_LOCK,
9944b522e90SEugeniy Paltsev SST26_CTL_UNLOCK,
9954b522e90SEugeniy Paltsev SST26_CTL_CHECK
9964b522e90SEugeniy Paltsev };
9974b522e90SEugeniy Paltsev
sst26_process_bpr(u32 bpr_size,u8 * cmd,u32 bit,enum lock_ctl ctl)9984b522e90SEugeniy Paltsev static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
9994b522e90SEugeniy Paltsev {
10004b522e90SEugeniy Paltsev switch (ctl) {
10014b522e90SEugeniy Paltsev case SST26_CTL_LOCK:
10024b522e90SEugeniy Paltsev cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8);
10034b522e90SEugeniy Paltsev break;
10044b522e90SEugeniy Paltsev case SST26_CTL_UNLOCK:
10054b522e90SEugeniy Paltsev cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8);
10064b522e90SEugeniy Paltsev break;
10074b522e90SEugeniy Paltsev case SST26_CTL_CHECK:
10084b522e90SEugeniy Paltsev return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8));
10094b522e90SEugeniy Paltsev }
10104b522e90SEugeniy Paltsev
10114b522e90SEugeniy Paltsev return false;
10124b522e90SEugeniy Paltsev }
10134b522e90SEugeniy Paltsev
10144b522e90SEugeniy Paltsev /*
10154b522e90SEugeniy Paltsev * Lock, unlock or check lock status of the flash region of the flash (depending
10164b522e90SEugeniy Paltsev * on the lock_ctl value)
10174b522e90SEugeniy Paltsev */
sst26_lock_ctl(struct spi_nor * nor,loff_t ofs,uint64_t len,enum lock_ctl ctl)10184b522e90SEugeniy Paltsev static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lock_ctl ctl)
10194b522e90SEugeniy Paltsev {
10204b522e90SEugeniy Paltsev struct mtd_info *mtd = &nor->mtd;
10214b522e90SEugeniy Paltsev u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
10224b522e90SEugeniy Paltsev bool lower_64k = false, upper_64k = false;
10234b522e90SEugeniy Paltsev u8 bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
10244b522e90SEugeniy Paltsev int ret;
10254b522e90SEugeniy Paltsev
10264b522e90SEugeniy Paltsev /* Check length and offset for 64k alignment */
10274b522e90SEugeniy Paltsev if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1))) {
10284b522e90SEugeniy Paltsev dev_err(nor->dev, "length or offset is not 64KiB allighned\n");
10294b522e90SEugeniy Paltsev return -EINVAL;
10304b522e90SEugeniy Paltsev }
10314b522e90SEugeniy Paltsev
10324b522e90SEugeniy Paltsev if (ofs + len > mtd->size) {
10334b522e90SEugeniy Paltsev dev_err(nor->dev, "range is more than device size: %#llx + %#llx > %#llx\n",
10344b522e90SEugeniy Paltsev ofs, len, mtd->size);
10354b522e90SEugeniy Paltsev return -EINVAL;
10364b522e90SEugeniy Paltsev }
10374b522e90SEugeniy Paltsev
10384b522e90SEugeniy Paltsev /* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
10394b522e90SEugeniy Paltsev if (mtd->size != SZ_2M &&
10404b522e90SEugeniy Paltsev mtd->size != SZ_4M &&
10414b522e90SEugeniy Paltsev mtd->size != SZ_8M)
10424b522e90SEugeniy Paltsev return -EINVAL;
10434b522e90SEugeniy Paltsev
10444b522e90SEugeniy Paltsev bpr_size = 2 + (mtd->size / SZ_64K / 8);
10454b522e90SEugeniy Paltsev
10464b522e90SEugeniy Paltsev ret = nor->read_reg(nor, SPINOR_OP_READ_BPR, bpr_buff, bpr_size);
10474b522e90SEugeniy Paltsev if (ret < 0) {
10484b522e90SEugeniy Paltsev dev_err(nor->dev, "fail to read block-protection register\n");
10494b522e90SEugeniy Paltsev return ret;
10504b522e90SEugeniy Paltsev }
10514b522e90SEugeniy Paltsev
10524b522e90SEugeniy Paltsev rptr_64k = min_t(u32, ofs + len, mtd->size - SST26_BOUND_REG_SIZE);
10534b522e90SEugeniy Paltsev lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
10544b522e90SEugeniy Paltsev
10554b522e90SEugeniy Paltsev upper_64k = ((ofs + len) > (mtd->size - SST26_BOUND_REG_SIZE));
10564b522e90SEugeniy Paltsev lower_64k = (ofs < SST26_BOUND_REG_SIZE);
10574b522e90SEugeniy Paltsev
10584b522e90SEugeniy Paltsev /* Lower bits in block-protection register are about 64k region */
10594b522e90SEugeniy Paltsev bpr_ptr = lptr_64k / SZ_64K - 1;
10604b522e90SEugeniy Paltsev
10614b522e90SEugeniy Paltsev /* Process 64K blocks region */
10624b522e90SEugeniy Paltsev while (lptr_64k < rptr_64k) {
10634b522e90SEugeniy Paltsev if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
10644b522e90SEugeniy Paltsev return EACCES;
10654b522e90SEugeniy Paltsev
10664b522e90SEugeniy Paltsev bpr_ptr++;
10674b522e90SEugeniy Paltsev lptr_64k += SZ_64K;
10684b522e90SEugeniy Paltsev }
10694b522e90SEugeniy Paltsev
10704b522e90SEugeniy Paltsev /* 32K and 8K region bits in BPR are after 64k region bits */
10714b522e90SEugeniy Paltsev bpr_ptr = (mtd->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K;
10724b522e90SEugeniy Paltsev
10734b522e90SEugeniy Paltsev /* Process lower 32K block region */
10744b522e90SEugeniy Paltsev if (lower_64k)
10754b522e90SEugeniy Paltsev if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
10764b522e90SEugeniy Paltsev return EACCES;
10774b522e90SEugeniy Paltsev
10784b522e90SEugeniy Paltsev bpr_ptr++;
10794b522e90SEugeniy Paltsev
10804b522e90SEugeniy Paltsev /* Process upper 32K block region */
10814b522e90SEugeniy Paltsev if (upper_64k)
10824b522e90SEugeniy Paltsev if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
10834b522e90SEugeniy Paltsev return EACCES;
10844b522e90SEugeniy Paltsev
10854b522e90SEugeniy Paltsev bpr_ptr++;
10864b522e90SEugeniy Paltsev
10874b522e90SEugeniy Paltsev /* Process lower 8K block regions */
10884b522e90SEugeniy Paltsev for (i = 0; i < SST26_BPR_8K_NUM; i++) {
10894b522e90SEugeniy Paltsev if (lower_64k)
10904b522e90SEugeniy Paltsev if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
10914b522e90SEugeniy Paltsev return EACCES;
10924b522e90SEugeniy Paltsev
10934b522e90SEugeniy Paltsev /* In 8K area BPR has both read and write protection bits */
10944b522e90SEugeniy Paltsev bpr_ptr += 2;
10954b522e90SEugeniy Paltsev }
10964b522e90SEugeniy Paltsev
10974b522e90SEugeniy Paltsev /* Process upper 8K block regions */
10984b522e90SEugeniy Paltsev for (i = 0; i < SST26_BPR_8K_NUM; i++) {
10994b522e90SEugeniy Paltsev if (upper_64k)
11004b522e90SEugeniy Paltsev if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
11014b522e90SEugeniy Paltsev return EACCES;
11024b522e90SEugeniy Paltsev
11034b522e90SEugeniy Paltsev /* In 8K area BPR has both read and write protection bits */
11044b522e90SEugeniy Paltsev bpr_ptr += 2;
11054b522e90SEugeniy Paltsev }
11064b522e90SEugeniy Paltsev
11074b522e90SEugeniy Paltsev /* If we check region status we don't need to write BPR back */
11084b522e90SEugeniy Paltsev if (ctl == SST26_CTL_CHECK)
11094b522e90SEugeniy Paltsev return 0;
11104b522e90SEugeniy Paltsev
11114b522e90SEugeniy Paltsev ret = nor->write_reg(nor, SPINOR_OP_WRITE_BPR, bpr_buff, bpr_size);
11124b522e90SEugeniy Paltsev if (ret < 0) {
11134b522e90SEugeniy Paltsev dev_err(nor->dev, "fail to write block-protection register\n");
11144b522e90SEugeniy Paltsev return ret;
11154b522e90SEugeniy Paltsev }
11164b522e90SEugeniy Paltsev
11174b522e90SEugeniy Paltsev return 0;
11184b522e90SEugeniy Paltsev }
11194b522e90SEugeniy Paltsev
sst26_unlock(struct spi_nor * nor,loff_t ofs,uint64_t len)11204b522e90SEugeniy Paltsev static int sst26_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
11214b522e90SEugeniy Paltsev {
11224b522e90SEugeniy Paltsev return sst26_lock_ctl(nor, ofs, len, SST26_CTL_UNLOCK);
11234b522e90SEugeniy Paltsev }
11244b522e90SEugeniy Paltsev
sst26_lock(struct spi_nor * nor,loff_t ofs,uint64_t len)11254b522e90SEugeniy Paltsev static int sst26_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
11264b522e90SEugeniy Paltsev {
11274b522e90SEugeniy Paltsev return sst26_lock_ctl(nor, ofs, len, SST26_CTL_LOCK);
11284b522e90SEugeniy Paltsev }
11294b522e90SEugeniy Paltsev
11304b522e90SEugeniy Paltsev /*
11314b522e90SEugeniy Paltsev * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
11324b522e90SEugeniy Paltsev * and negative on errors.
11334b522e90SEugeniy Paltsev */
sst26_is_locked(struct spi_nor * nor,loff_t ofs,uint64_t len)11344b522e90SEugeniy Paltsev static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
11354b522e90SEugeniy Paltsev {
11364b522e90SEugeniy Paltsev /*
11374b522e90SEugeniy Paltsev * is_locked function is used for check before reading or erasing flash
11384b522e90SEugeniy Paltsev * region, so offset and length might be not 64k allighned, so adjust
11394b522e90SEugeniy Paltsev * them to be 64k allighned as sst26_lock_ctl works only with 64k
11404b522e90SEugeniy Paltsev * allighned regions.
11414b522e90SEugeniy Paltsev */
11424b522e90SEugeniy Paltsev ofs -= ofs & (SZ_64K - 1);
11434b522e90SEugeniy Paltsev len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
11444b522e90SEugeniy Paltsev
11454b522e90SEugeniy Paltsev return sst26_lock_ctl(nor, ofs, len, SST26_CTL_CHECK);
11464b522e90SEugeniy Paltsev }
11474b522e90SEugeniy Paltsev
sst_write_byteprogram(struct spi_nor * nor,loff_t to,size_t len,size_t * retlen,const u_char * buf)1148dc6fa43fSVignesh R static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len,
1149dc6fa43fSVignesh R size_t *retlen, const u_char *buf)
1150dc6fa43fSVignesh R {
1151dc6fa43fSVignesh R size_t actual;
1152dc6fa43fSVignesh R int ret = 0;
1153dc6fa43fSVignesh R
1154dc6fa43fSVignesh R for (actual = 0; actual < len; actual++) {
1155dc6fa43fSVignesh R nor->program_opcode = SPINOR_OP_BP;
1156dc6fa43fSVignesh R
1157dc6fa43fSVignesh R write_enable(nor);
1158dc6fa43fSVignesh R /* write one byte. */
1159dc6fa43fSVignesh R ret = nor->write(nor, to, 1, buf + actual);
1160dc6fa43fSVignesh R if (ret < 0)
1161dc6fa43fSVignesh R goto sst_write_err;
1162dc6fa43fSVignesh R ret = spi_nor_wait_till_ready(nor);
1163dc6fa43fSVignesh R if (ret)
1164dc6fa43fSVignesh R goto sst_write_err;
1165dc6fa43fSVignesh R to++;
1166dc6fa43fSVignesh R }
1167dc6fa43fSVignesh R
1168dc6fa43fSVignesh R sst_write_err:
1169dc6fa43fSVignesh R write_disable(nor);
1170dc6fa43fSVignesh R return ret;
1171dc6fa43fSVignesh R }
1172dc6fa43fSVignesh R
sst_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)1173a2b7f194SVignesh R static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
1174a2b7f194SVignesh R size_t *retlen, const u_char *buf)
1175a2b7f194SVignesh R {
1176a2b7f194SVignesh R struct spi_nor *nor = mtd_to_spi_nor(mtd);
1177dc6fa43fSVignesh R struct spi_slave *spi = nor->spi;
1178a2b7f194SVignesh R size_t actual;
1179a2b7f194SVignesh R int ret;
1180a2b7f194SVignesh R
1181a2b7f194SVignesh R dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
1182dc6fa43fSVignesh R if (spi->mode & SPI_TX_BYTE)
1183dc6fa43fSVignesh R return sst_write_byteprogram(nor, to, len, retlen, buf);
1184a2b7f194SVignesh R
1185a2b7f194SVignesh R write_enable(nor);
1186a2b7f194SVignesh R
1187a2b7f194SVignesh R nor->sst_write_second = false;
1188a2b7f194SVignesh R
1189a2b7f194SVignesh R actual = to % 2;
1190a2b7f194SVignesh R /* Start write from odd address. */
1191a2b7f194SVignesh R if (actual) {
1192a2b7f194SVignesh R nor->program_opcode = SPINOR_OP_BP;
1193a2b7f194SVignesh R
1194a2b7f194SVignesh R /* write one byte. */
1195a2b7f194SVignesh R ret = nor->write(nor, to, 1, buf);
1196a2b7f194SVignesh R if (ret < 0)
1197a2b7f194SVignesh R goto sst_write_err;
1198a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1199a2b7f194SVignesh R if (ret)
1200a2b7f194SVignesh R goto sst_write_err;
1201a2b7f194SVignesh R }
1202a2b7f194SVignesh R to += actual;
1203a2b7f194SVignesh R
1204a2b7f194SVignesh R /* Write out most of the data here. */
1205a2b7f194SVignesh R for (; actual < len - 1; actual += 2) {
1206a2b7f194SVignesh R nor->program_opcode = SPINOR_OP_AAI_WP;
1207a2b7f194SVignesh R
1208a2b7f194SVignesh R /* write two bytes. */
1209a2b7f194SVignesh R ret = nor->write(nor, to, 2, buf + actual);
1210a2b7f194SVignesh R if (ret < 0)
1211a2b7f194SVignesh R goto sst_write_err;
1212a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1213a2b7f194SVignesh R if (ret)
1214a2b7f194SVignesh R goto sst_write_err;
1215a2b7f194SVignesh R to += 2;
1216a2b7f194SVignesh R nor->sst_write_second = true;
1217a2b7f194SVignesh R }
1218a2b7f194SVignesh R nor->sst_write_second = false;
1219a2b7f194SVignesh R
1220a2b7f194SVignesh R write_disable(nor);
1221a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1222a2b7f194SVignesh R if (ret)
1223a2b7f194SVignesh R goto sst_write_err;
1224a2b7f194SVignesh R
1225a2b7f194SVignesh R /* Write out trailing byte if it exists. */
1226a2b7f194SVignesh R if (actual != len) {
1227a2b7f194SVignesh R write_enable(nor);
1228a2b7f194SVignesh R
1229a2b7f194SVignesh R nor->program_opcode = SPINOR_OP_BP;
1230a2b7f194SVignesh R ret = nor->write(nor, to, 1, buf + actual);
1231a2b7f194SVignesh R if (ret < 0)
1232a2b7f194SVignesh R goto sst_write_err;
1233a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1234a2b7f194SVignesh R if (ret)
1235a2b7f194SVignesh R goto sst_write_err;
1236a2b7f194SVignesh R write_disable(nor);
1237a2b7f194SVignesh R actual += 1;
1238a2b7f194SVignesh R }
1239a2b7f194SVignesh R sst_write_err:
1240a2b7f194SVignesh R *retlen += actual;
1241a2b7f194SVignesh R return ret;
1242a2b7f194SVignesh R }
1243a2b7f194SVignesh R #endif
1244a2b7f194SVignesh R /*
1245a2b7f194SVignesh R * Write an address range to the nor chip. Data must be written in
1246a2b7f194SVignesh R * FLASH_PAGESIZE chunks. The address range may be any size provided
1247a2b7f194SVignesh R * it is within the physical boundaries.
1248a2b7f194SVignesh R */
spi_nor_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)1249a2b7f194SVignesh R static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
1250a2b7f194SVignesh R size_t *retlen, const u_char *buf)
1251a2b7f194SVignesh R {
1252a2b7f194SVignesh R struct spi_nor *nor = mtd_to_spi_nor(mtd);
1253a2b7f194SVignesh R size_t page_offset, page_remain, i;
1254a2b7f194SVignesh R ssize_t ret;
1255a2b7f194SVignesh R
1256a2b7f194SVignesh R dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
1257a2b7f194SVignesh R
1258a2b7f194SVignesh R for (i = 0; i < len; ) {
1259a2b7f194SVignesh R ssize_t written;
1260a2b7f194SVignesh R loff_t addr = to + i;
1261a2b7f194SVignesh R
1262*2cf66459SJon Lin #if defined(CONFIG_SPI_FLASH_AUTO_MERGE)
1263*2cf66459SJon Lin nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1;
1264*2cf66459SJon Lin addr -= nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size;
1265*2cf66459SJon Lin #endif
1266*2cf66459SJon Lin
1267a2b7f194SVignesh R /*
1268a2b7f194SVignesh R * If page_size is a power of two, the offset can be quickly
1269a2b7f194SVignesh R * calculated with an AND operation. On the other cases we
1270a2b7f194SVignesh R * need to do a modulus operation (more expensive).
1271a2b7f194SVignesh R * Power of two numbers have only one bit set and we can use
1272a2b7f194SVignesh R * the instruction hweight32 to detect if we need to do a
1273a2b7f194SVignesh R * modulus (do_div()) or not.
1274a2b7f194SVignesh R */
1275a2b7f194SVignesh R if (hweight32(nor->page_size) == 1) {
1276a2b7f194SVignesh R page_offset = addr & (nor->page_size - 1);
1277a2b7f194SVignesh R } else {
1278a2b7f194SVignesh R u64 aux = addr;
1279a2b7f194SVignesh R
1280a2b7f194SVignesh R page_offset = do_div(aux, nor->page_size);
1281a2b7f194SVignesh R }
1282a2b7f194SVignesh R /* the size of data remaining on the first page */
1283a2b7f194SVignesh R page_remain = min_t(size_t,
1284a2b7f194SVignesh R nor->page_size - page_offset, len - i);
1285a2b7f194SVignesh R
1286dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
1287dc6fa43fSVignesh R ret = write_bar(nor, addr);
1288dc6fa43fSVignesh R if (ret < 0)
1289dc6fa43fSVignesh R return ret;
1290dc6fa43fSVignesh R #endif
1291a2b7f194SVignesh R write_enable(nor);
1292a2b7f194SVignesh R ret = nor->write(nor, addr, page_remain, buf + i);
1293a2b7f194SVignesh R if (ret < 0)
1294a2b7f194SVignesh R goto write_err;
1295a2b7f194SVignesh R written = ret;
1296a2b7f194SVignesh R
1297a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1298a2b7f194SVignesh R if (ret)
1299a2b7f194SVignesh R goto write_err;
1300a2b7f194SVignesh R *retlen += written;
1301a2b7f194SVignesh R i += written;
1302a2b7f194SVignesh R }
1303a2b7f194SVignesh R
1304a2b7f194SVignesh R write_err:
1305dc6fa43fSVignesh R #ifdef CONFIG_SPI_FLASH_BAR
1306dc6fa43fSVignesh R ret = clean_bar(nor);
1307dc6fa43fSVignesh R #endif
1308a2b7f194SVignesh R return ret;
1309a2b7f194SVignesh R }
1310a2b7f194SVignesh R
1311a2b7f194SVignesh R #ifdef CONFIG_SPI_FLASH_MACRONIX
1312a2b7f194SVignesh R /**
1313a2b7f194SVignesh R * macronix_quad_enable() - set QE bit in Status Register.
1314a2b7f194SVignesh R * @nor: pointer to a 'struct spi_nor'
1315a2b7f194SVignesh R *
1316a2b7f194SVignesh R * Set the Quad Enable (QE) bit in the Status Register.
1317a2b7f194SVignesh R *
1318a2b7f194SVignesh R * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
1319a2b7f194SVignesh R *
1320a2b7f194SVignesh R * Return: 0 on success, -errno otherwise.
1321a2b7f194SVignesh R */
macronix_quad_enable(struct spi_nor * nor)1322a2b7f194SVignesh R static int macronix_quad_enable(struct spi_nor *nor)
1323a2b7f194SVignesh R {
1324a2b7f194SVignesh R int ret, val;
1325a2b7f194SVignesh R
1326a2b7f194SVignesh R val = read_sr(nor);
1327a2b7f194SVignesh R if (val < 0)
1328a2b7f194SVignesh R return val;
1329a2b7f194SVignesh R if (val & SR_QUAD_EN_MX)
1330a2b7f194SVignesh R return 0;
1331a2b7f194SVignesh R
1332a2b7f194SVignesh R write_enable(nor);
1333a2b7f194SVignesh R
1334a2b7f194SVignesh R write_sr(nor, val | SR_QUAD_EN_MX);
1335a2b7f194SVignesh R
1336a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1337a2b7f194SVignesh R if (ret)
1338a2b7f194SVignesh R return ret;
1339a2b7f194SVignesh R
1340a2b7f194SVignesh R ret = read_sr(nor);
1341a2b7f194SVignesh R if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
1342a2b7f194SVignesh R dev_err(nor->dev, "Macronix Quad bit not set\n");
1343a2b7f194SVignesh R return -EINVAL;
1344a2b7f194SVignesh R }
1345a2b7f194SVignesh R
1346a2b7f194SVignesh R return 0;
1347a2b7f194SVignesh R }
1348a2b7f194SVignesh R #endif
1349a2b7f194SVignesh R
1350a2b7f194SVignesh R #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
1351a2b7f194SVignesh R /*
1352a2b7f194SVignesh R * Write status Register and configuration register with 2 bytes
1353a2b7f194SVignesh R * The first byte will be written to the status register, while the
1354a2b7f194SVignesh R * second byte will be written to the configuration register.
1355a2b7f194SVignesh R * Return negative if error occurred.
1356a2b7f194SVignesh R */
write_sr_cr(struct spi_nor * nor,u8 * sr_cr)1357a2b7f194SVignesh R static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
1358a2b7f194SVignesh R {
1359a2b7f194SVignesh R int ret;
1360a2b7f194SVignesh R
1361a2b7f194SVignesh R write_enable(nor);
1362a2b7f194SVignesh R
1363a2b7f194SVignesh R ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
1364a2b7f194SVignesh R if (ret < 0) {
1365a2b7f194SVignesh R dev_dbg(nor->dev,
1366a2b7f194SVignesh R "error while writing configuration register\n");
1367a2b7f194SVignesh R return -EINVAL;
1368a2b7f194SVignesh R }
1369a2b7f194SVignesh R
1370a2b7f194SVignesh R ret = spi_nor_wait_till_ready(nor);
1371a2b7f194SVignesh R if (ret) {
1372a2b7f194SVignesh R dev_dbg(nor->dev,
1373a2b7f194SVignesh R "timeout while writing configuration register\n");
1374a2b7f194SVignesh R return ret;
1375a2b7f194SVignesh R }
1376a2b7f194SVignesh R
1377a2b7f194SVignesh R return 0;
1378a2b7f194SVignesh R }
1379a2b7f194SVignesh R
1380a2b7f194SVignesh R /**
1381a2b7f194SVignesh R * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
1382a2b7f194SVignesh R * @nor: pointer to a 'struct spi_nor'
1383a2b7f194SVignesh R *
1384a2b7f194SVignesh R * Set the Quad Enable (QE) bit in the Configuration Register.
1385a2b7f194SVignesh R * This function should be used with QSPI memories supporting the Read
1386a2b7f194SVignesh R * Configuration Register (35h) instruction.
1387a2b7f194SVignesh R *
1388a2b7f194SVignesh R * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
1389a2b7f194SVignesh R * memories.
1390a2b7f194SVignesh R *
1391a2b7f194SVignesh R * Return: 0 on success, -errno otherwise.
1392a2b7f194SVignesh R */
spansion_read_cr_quad_enable(struct spi_nor * nor)1393a2b7f194SVignesh R static int spansion_read_cr_quad_enable(struct spi_nor *nor)
1394a2b7f194SVignesh R {
1395a2b7f194SVignesh R u8 sr_cr[2];
1396a2b7f194SVignesh R int ret;
1397a2b7f194SVignesh R
1398a2b7f194SVignesh R /* Check current Quad Enable bit value. */
1399a2b7f194SVignesh R ret = read_cr(nor);
1400a2b7f194SVignesh R if (ret < 0) {
1401a2b7f194SVignesh R dev_dbg(dev, "error while reading configuration register\n");
1402a2b7f194SVignesh R return -EINVAL;
1403a2b7f194SVignesh R }
1404a2b7f194SVignesh R
1405a2b7f194SVignesh R if (ret & CR_QUAD_EN_SPAN)
1406a2b7f194SVignesh R return 0;
1407a2b7f194SVignesh R
1408a2b7f194SVignesh R sr_cr[1] = ret | CR_QUAD_EN_SPAN;
1409a2b7f194SVignesh R
1410a2b7f194SVignesh R /* Keep the current value of the Status Register. */
1411a2b7f194SVignesh R ret = read_sr(nor);
1412a2b7f194SVignesh R if (ret < 0) {
1413a2b7f194SVignesh R dev_dbg(dev, "error while reading status register\n");
1414a2b7f194SVignesh R return -EINVAL;
1415a2b7f194SVignesh R }
1416a2b7f194SVignesh R sr_cr[0] = ret;
1417a2b7f194SVignesh R
1418a2b7f194SVignesh R ret = write_sr_cr(nor, sr_cr);
1419a2b7f194SVignesh R if (ret)
1420a2b7f194SVignesh R return ret;
1421a2b7f194SVignesh R
1422a2b7f194SVignesh R /* Read back and check it. */
1423a2b7f194SVignesh R ret = read_cr(nor);
1424a2b7f194SVignesh R if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
1425a2b7f194SVignesh R dev_dbg(nor->dev, "Spansion Quad bit not set\n");
1426a2b7f194SVignesh R return -EINVAL;
1427a2b7f194SVignesh R }
1428a2b7f194SVignesh R
1429a2b7f194SVignesh R return 0;
1430a2b7f194SVignesh R }
14312359fc6fSVignesh R
14322359fc6fSVignesh R #if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
14332359fc6fSVignesh R /**
14342359fc6fSVignesh R * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register.
14352359fc6fSVignesh R * @nor: pointer to a 'struct spi_nor'
14362359fc6fSVignesh R *
14372359fc6fSVignesh R * Set the Quad Enable (QE) bit in the Configuration Register.
14382359fc6fSVignesh R * This function should be used with QSPI memories not supporting the Read
14392359fc6fSVignesh R * Configuration Register (35h) instruction.
14402359fc6fSVignesh R *
14412359fc6fSVignesh R * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
14422359fc6fSVignesh R * memories.
14432359fc6fSVignesh R *
14442359fc6fSVignesh R * Return: 0 on success, -errno otherwise.
14452359fc6fSVignesh R */
spansion_no_read_cr_quad_enable(struct spi_nor * nor)14462359fc6fSVignesh R static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
14472359fc6fSVignesh R {
14482359fc6fSVignesh R u8 sr_cr[2];
14492359fc6fSVignesh R int ret;
14502359fc6fSVignesh R
14512359fc6fSVignesh R /* Keep the current value of the Status Register. */
14522359fc6fSVignesh R ret = read_sr(nor);
14532359fc6fSVignesh R if (ret < 0) {
14542359fc6fSVignesh R dev_dbg(nor->dev, "error while reading status register\n");
14552359fc6fSVignesh R return -EINVAL;
14562359fc6fSVignesh R }
14572359fc6fSVignesh R sr_cr[0] = ret;
14582359fc6fSVignesh R sr_cr[1] = CR_QUAD_EN_SPAN;
14592359fc6fSVignesh R
14602359fc6fSVignesh R return write_sr_cr(nor, sr_cr);
14612359fc6fSVignesh R }
14622359fc6fSVignesh R
14632359fc6fSVignesh R #endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */
1464a2b7f194SVignesh R #endif /* CONFIG_SPI_FLASH_SPANSION */
1465a2b7f194SVignesh R
14661f301960SJon Lin #ifdef CONFIG_SPI_FLASH_NORMEM
14671f301960SJon Lin /**
14681f301960SJon Lin * normem_quad_enable() - set QE bit in Status Register.
14691f301960SJon Lin * @nor: pointer to a 'struct spi_nor'
14701f301960SJon Lin *
14711f301960SJon Lin * Set the Quad Enable (QE) bit in the Status Register.
14721f301960SJon Lin *
14731f301960SJon Lin * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
14741f301960SJon Lin *
14751f301960SJon Lin * Return: 0 on success, -errno otherwise.
14761f301960SJon Lin */
normem_quad_enable(struct spi_nor * nor)14771f301960SJon Lin static int normem_quad_enable(struct spi_nor *nor)
14781f301960SJon Lin {
14791f301960SJon Lin int ret, val;
14801f301960SJon Lin
14811f301960SJon Lin val = read_cr(nor);
14821f301960SJon Lin if (val < 0)
14831f301960SJon Lin return val;
14841f301960SJon Lin if (val & SR_QUAD_EN_NORMEM)
14851f301960SJon Lin return 0;
14861f301960SJon Lin
14871f301960SJon Lin write_enable(nor);
14881f301960SJon Lin
14891f301960SJon Lin write_cr(nor, val | SR_QUAD_EN_NORMEM);
14901f301960SJon Lin
14911f301960SJon Lin ret = spi_nor_wait_till_ready(nor);
14921f301960SJon Lin if (ret)
14931f301960SJon Lin return ret;
14941f301960SJon Lin
14951f301960SJon Lin ret = read_cr(nor);
14961f301960SJon Lin if (!(ret > 0 && (ret & SR_QUAD_EN_NORMEM))) {
14971f301960SJon Lin dev_err(nor->dev, "NORMEM Quad bit not set\n");
14981f301960SJon Lin return -EINVAL;
14991f301960SJon Lin }
15001f301960SJon Lin
15011f301960SJon Lin return 0;
15021f301960SJon Lin }
15031f301960SJon Lin #endif
15041f301960SJon Lin
1505a2b7f194SVignesh R struct spi_nor_read_command {
1506a2b7f194SVignesh R u8 num_mode_clocks;
1507a2b7f194SVignesh R u8 num_wait_states;
1508a2b7f194SVignesh R u8 opcode;
1509a2b7f194SVignesh R enum spi_nor_protocol proto;
1510a2b7f194SVignesh R };
1511a2b7f194SVignesh R
1512a2b7f194SVignesh R struct spi_nor_pp_command {
1513a2b7f194SVignesh R u8 opcode;
1514a2b7f194SVignesh R enum spi_nor_protocol proto;
1515a2b7f194SVignesh R };
1516a2b7f194SVignesh R
1517a2b7f194SVignesh R enum spi_nor_read_command_index {
1518a2b7f194SVignesh R SNOR_CMD_READ,
1519a2b7f194SVignesh R SNOR_CMD_READ_FAST,
1520a2b7f194SVignesh R SNOR_CMD_READ_1_1_1_DTR,
1521a2b7f194SVignesh R
1522a2b7f194SVignesh R /* Dual SPI */
1523a2b7f194SVignesh R SNOR_CMD_READ_1_1_2,
1524a2b7f194SVignesh R SNOR_CMD_READ_1_2_2,
1525a2b7f194SVignesh R SNOR_CMD_READ_2_2_2,
1526a2b7f194SVignesh R SNOR_CMD_READ_1_2_2_DTR,
1527a2b7f194SVignesh R
1528a2b7f194SVignesh R /* Quad SPI */
1529a2b7f194SVignesh R SNOR_CMD_READ_1_1_4,
1530a2b7f194SVignesh R SNOR_CMD_READ_1_4_4,
1531a2b7f194SVignesh R SNOR_CMD_READ_4_4_4,
1532a2b7f194SVignesh R SNOR_CMD_READ_1_4_4_DTR,
1533a2b7f194SVignesh R
1534a2b7f194SVignesh R /* Octo SPI */
1535a2b7f194SVignesh R SNOR_CMD_READ_1_1_8,
1536a2b7f194SVignesh R SNOR_CMD_READ_1_8_8,
1537a2b7f194SVignesh R SNOR_CMD_READ_8_8_8,
1538a2b7f194SVignesh R SNOR_CMD_READ_1_8_8_DTR,
1539a2b7f194SVignesh R
1540a2b7f194SVignesh R SNOR_CMD_READ_MAX
1541a2b7f194SVignesh R };
1542a2b7f194SVignesh R
1543a2b7f194SVignesh R enum spi_nor_pp_command_index {
1544a2b7f194SVignesh R SNOR_CMD_PP,
1545a2b7f194SVignesh R
1546a2b7f194SVignesh R /* Quad SPI */
1547a2b7f194SVignesh R SNOR_CMD_PP_1_1_4,
1548a2b7f194SVignesh R SNOR_CMD_PP_1_4_4,
1549a2b7f194SVignesh R SNOR_CMD_PP_4_4_4,
1550a2b7f194SVignesh R
1551a2b7f194SVignesh R /* Octo SPI */
1552a2b7f194SVignesh R SNOR_CMD_PP_1_1_8,
1553a2b7f194SVignesh R SNOR_CMD_PP_1_8_8,
1554a2b7f194SVignesh R SNOR_CMD_PP_8_8_8,
1555a2b7f194SVignesh R
1556a2b7f194SVignesh R SNOR_CMD_PP_MAX
1557a2b7f194SVignesh R };
1558a2b7f194SVignesh R
1559a2b7f194SVignesh R struct spi_nor_flash_parameter {
1560a2b7f194SVignesh R u64 size;
1561a2b7f194SVignesh R u32 page_size;
1562a2b7f194SVignesh R
1563a2b7f194SVignesh R struct spi_nor_hwcaps hwcaps;
1564a2b7f194SVignesh R struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
1565a2b7f194SVignesh R struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX];
1566a2b7f194SVignesh R
1567a2b7f194SVignesh R int (*quad_enable)(struct spi_nor *nor);
1568a2b7f194SVignesh R };
1569a2b7f194SVignesh R
1570a2b7f194SVignesh R static void
spi_nor_set_read_settings(struct spi_nor_read_command * read,u8 num_mode_clocks,u8 num_wait_states,u8 opcode,enum spi_nor_protocol proto)1571a2b7f194SVignesh R spi_nor_set_read_settings(struct spi_nor_read_command *read,
1572a2b7f194SVignesh R u8 num_mode_clocks,
1573a2b7f194SVignesh R u8 num_wait_states,
1574a2b7f194SVignesh R u8 opcode,
1575a2b7f194SVignesh R enum spi_nor_protocol proto)
1576a2b7f194SVignesh R {
1577a2b7f194SVignesh R read->num_mode_clocks = num_mode_clocks;
1578a2b7f194SVignesh R read->num_wait_states = num_wait_states;
1579a2b7f194SVignesh R read->opcode = opcode;
1580a2b7f194SVignesh R read->proto = proto;
1581a2b7f194SVignesh R }
1582a2b7f194SVignesh R
1583a2b7f194SVignesh R static void
spi_nor_set_pp_settings(struct spi_nor_pp_command * pp,u8 opcode,enum spi_nor_protocol proto)1584a2b7f194SVignesh R spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
1585a2b7f194SVignesh R u8 opcode,
1586a2b7f194SVignesh R enum spi_nor_protocol proto)
1587a2b7f194SVignesh R {
1588a2b7f194SVignesh R pp->opcode = opcode;
1589a2b7f194SVignesh R pp->proto = proto;
1590a2b7f194SVignesh R }
1591a2b7f194SVignesh R
15922359fc6fSVignesh R #if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
15932359fc6fSVignesh R /*
15942359fc6fSVignesh R * Serial Flash Discoverable Parameters (SFDP) parsing.
15952359fc6fSVignesh R */
15962359fc6fSVignesh R
15972359fc6fSVignesh R /**
15982359fc6fSVignesh R * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
15992359fc6fSVignesh R * @nor: pointer to a 'struct spi_nor'
16002359fc6fSVignesh R * @addr: offset in the SFDP area to start reading data from
16012359fc6fSVignesh R * @len: number of bytes to read
16022359fc6fSVignesh R * @buf: buffer where the SFDP data are copied into (dma-safe memory)
16032359fc6fSVignesh R *
16042359fc6fSVignesh R * Whatever the actual numbers of bytes for address and dummy cycles are
16052359fc6fSVignesh R * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always
16062359fc6fSVignesh R * followed by a 3-byte address and 8 dummy clock cycles.
16072359fc6fSVignesh R *
16082359fc6fSVignesh R * Return: 0 on success, -errno otherwise.
16092359fc6fSVignesh R */
spi_nor_read_sfdp(struct spi_nor * nor,u32 addr,size_t len,void * buf)16102359fc6fSVignesh R static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
16112359fc6fSVignesh R size_t len, void *buf)
16122359fc6fSVignesh R {
16132359fc6fSVignesh R u8 addr_width, read_opcode, read_dummy;
16142359fc6fSVignesh R int ret;
16152359fc6fSVignesh R
16162359fc6fSVignesh R read_opcode = nor->read_opcode;
16172359fc6fSVignesh R addr_width = nor->addr_width;
16182359fc6fSVignesh R read_dummy = nor->read_dummy;
16192359fc6fSVignesh R
16202359fc6fSVignesh R nor->read_opcode = SPINOR_OP_RDSFDP;
16212359fc6fSVignesh R nor->addr_width = 3;
16222359fc6fSVignesh R nor->read_dummy = 8;
16232359fc6fSVignesh R
16242359fc6fSVignesh R while (len) {
16252359fc6fSVignesh R ret = nor->read(nor, addr, len, (u8 *)buf);
16262359fc6fSVignesh R if (!ret || ret > len) {
16272359fc6fSVignesh R ret = -EIO;
16282359fc6fSVignesh R goto read_err;
16292359fc6fSVignesh R }
16302359fc6fSVignesh R if (ret < 0)
16312359fc6fSVignesh R goto read_err;
16322359fc6fSVignesh R
16332359fc6fSVignesh R buf += ret;
16342359fc6fSVignesh R addr += ret;
16352359fc6fSVignesh R len -= ret;
16362359fc6fSVignesh R }
16372359fc6fSVignesh R ret = 0;
16382359fc6fSVignesh R
16392359fc6fSVignesh R read_err:
16402359fc6fSVignesh R nor->read_opcode = read_opcode;
16412359fc6fSVignesh R nor->addr_width = addr_width;
16422359fc6fSVignesh R nor->read_dummy = read_dummy;
16432359fc6fSVignesh R
16442359fc6fSVignesh R return ret;
16452359fc6fSVignesh R }
16462359fc6fSVignesh R
16472359fc6fSVignesh R struct sfdp_parameter_header {
16482359fc6fSVignesh R u8 id_lsb;
16492359fc6fSVignesh R u8 minor;
16502359fc6fSVignesh R u8 major;
16512359fc6fSVignesh R u8 length; /* in double words */
16522359fc6fSVignesh R u8 parameter_table_pointer[3]; /* byte address */
16532359fc6fSVignesh R u8 id_msb;
16542359fc6fSVignesh R };
16552359fc6fSVignesh R
16562359fc6fSVignesh R #define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb)
16572359fc6fSVignesh R #define SFDP_PARAM_HEADER_PTP(p) \
16582359fc6fSVignesh R (((p)->parameter_table_pointer[2] << 16) | \
16592359fc6fSVignesh R ((p)->parameter_table_pointer[1] << 8) | \
16602359fc6fSVignesh R ((p)->parameter_table_pointer[0] << 0))
16612359fc6fSVignesh R
16622359fc6fSVignesh R #define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
16632359fc6fSVignesh R #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
16642359fc6fSVignesh R
16652359fc6fSVignesh R #define SFDP_SIGNATURE 0x50444653U
16662359fc6fSVignesh R #define SFDP_JESD216_MAJOR 1
16672359fc6fSVignesh R #define SFDP_JESD216_MINOR 0
16682359fc6fSVignesh R #define SFDP_JESD216A_MINOR 5
16692359fc6fSVignesh R #define SFDP_JESD216B_MINOR 6
16702359fc6fSVignesh R
16712359fc6fSVignesh R struct sfdp_header {
16722359fc6fSVignesh R u32 signature; /* Ox50444653U <=> "SFDP" */
16732359fc6fSVignesh R u8 minor;
16742359fc6fSVignesh R u8 major;
16752359fc6fSVignesh R u8 nph; /* 0-base number of parameter headers */
16762359fc6fSVignesh R u8 unused;
16772359fc6fSVignesh R
16782359fc6fSVignesh R /* Basic Flash Parameter Table. */
16792359fc6fSVignesh R struct sfdp_parameter_header bfpt_header;
16802359fc6fSVignesh R };
16812359fc6fSVignesh R
16822359fc6fSVignesh R /* Basic Flash Parameter Table */
16832359fc6fSVignesh R
16842359fc6fSVignesh R /*
16852359fc6fSVignesh R * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
16862359fc6fSVignesh R * They are indexed from 1 but C arrays are indexed from 0.
16872359fc6fSVignesh R */
16882359fc6fSVignesh R #define BFPT_DWORD(i) ((i) - 1)
16892359fc6fSVignesh R #define BFPT_DWORD_MAX 16
16902359fc6fSVignesh R
16912359fc6fSVignesh R /* The first version of JESB216 defined only 9 DWORDs. */
16922359fc6fSVignesh R #define BFPT_DWORD_MAX_JESD216 9
16932359fc6fSVignesh R
16942359fc6fSVignesh R /* 1st DWORD. */
16952359fc6fSVignesh R #define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16)
16962359fc6fSVignesh R #define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17)
16972359fc6fSVignesh R #define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17)
16982359fc6fSVignesh R #define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17)
16992359fc6fSVignesh R #define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17)
17002359fc6fSVignesh R #define BFPT_DWORD1_DTR BIT(19)
17012359fc6fSVignesh R #define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20)
17022359fc6fSVignesh R #define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21)
17032359fc6fSVignesh R #define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22)
17042359fc6fSVignesh R
17052359fc6fSVignesh R /* 5th DWORD. */
17062359fc6fSVignesh R #define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0)
17072359fc6fSVignesh R #define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4)
17082359fc6fSVignesh R
17092359fc6fSVignesh R /* 11th DWORD. */
17102359fc6fSVignesh R #define BFPT_DWORD11_PAGE_SIZE_SHIFT 4
17112359fc6fSVignesh R #define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4)
17122359fc6fSVignesh R
17132359fc6fSVignesh R /* 15th DWORD. */
17142359fc6fSVignesh R
17152359fc6fSVignesh R /*
17164c6d72aaSJon Lin * (from JESD216 rev F)
17172359fc6fSVignesh R * Quad Enable Requirements (QER):
17182359fc6fSVignesh R * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
17192359fc6fSVignesh R * reads based on instruction. DQ3/HOLD# functions are hold during
17202359fc6fSVignesh R * instruction phase.
17212359fc6fSVignesh R * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
17222359fc6fSVignesh R * two data bytes where bit 1 of the second byte is one.
17232359fc6fSVignesh R * [...]
17242359fc6fSVignesh R * Writing only one byte to the status register has the side-effect of
17252359fc6fSVignesh R * clearing status register 2, including the QE bit. The 100b code is
17262359fc6fSVignesh R * used if writing one byte to the status register does not modify
17272359fc6fSVignesh R * status register 2.
17282359fc6fSVignesh R * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
17292359fc6fSVignesh R * one data byte where bit 6 is one.
17302359fc6fSVignesh R * [...]
17312359fc6fSVignesh R * - 011b: QE is bit 7 of status register 2. It is set via Write status
17322359fc6fSVignesh R * register 2 instruction 3Eh with one data byte where bit 7 is one.
17332359fc6fSVignesh R * [...]
17342359fc6fSVignesh R * The status register 2 is read using instruction 3Fh.
17352359fc6fSVignesh R * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
17362359fc6fSVignesh R * two data bytes where bit 1 of the second byte is one.
17372359fc6fSVignesh R * [...]
17382359fc6fSVignesh R * In contrast to the 001b code, writing one byte to the status
17392359fc6fSVignesh R * register does not modify status register 2.
17402359fc6fSVignesh R * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
17412359fc6fSVignesh R * Read Status instruction 05h. Status register2 is read using
17422359fc6fSVignesh R * instruction 35h. QE is set via Writ Status instruction 01h with
17432359fc6fSVignesh R * two data bytes where bit 1 of the second byte is one.
17442359fc6fSVignesh R * [...]
17454c6d72aaSJon Lin * - 110b: QE is bit 1 of the status register 2. Status register 1 is read using
17464c6d72aaSJon Lin * Read Status instruction 05h. Status register 2 is read using instruction
17474c6d72aaSJon Lin * 35h, and status register 3 is read using instruction 15h. QE is set via
17484c6d72aaSJon Lin * Write Status Register instruction 31h with one data byte where bit 1 is
17494c6d72aaSJon Lin * one. It is cleared via Write Status Register instruction 31h with one
17504c6d72aaSJon Lin * data byte where bit 1 is zero.
17512359fc6fSVignesh R */
17522359fc6fSVignesh R #define BFPT_DWORD15_QER_MASK GENMASK(22, 20)
17532359fc6fSVignesh R #define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */
17542359fc6fSVignesh R #define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20)
17552359fc6fSVignesh R #define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */
17562359fc6fSVignesh R #define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20)
17572359fc6fSVignesh R #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
17582359fc6fSVignesh R #define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
17594c6d72aaSJon Lin #define BFPT_DWORD15_QER_SR2_BIT1_WR (0x6UL << 20)
17602359fc6fSVignesh R
17612359fc6fSVignesh R struct sfdp_bfpt {
17622359fc6fSVignesh R u32 dwords[BFPT_DWORD_MAX];
17632359fc6fSVignesh R };
17642359fc6fSVignesh R
17652359fc6fSVignesh R /* Fast Read settings. */
17662359fc6fSVignesh R
17672359fc6fSVignesh R static void
spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command * read,u16 half,enum spi_nor_protocol proto)17682359fc6fSVignesh R spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read,
17692359fc6fSVignesh R u16 half,
17702359fc6fSVignesh R enum spi_nor_protocol proto)
17712359fc6fSVignesh R {
17722359fc6fSVignesh R read->num_mode_clocks = (half >> 5) & 0x07;
17732359fc6fSVignesh R read->num_wait_states = (half >> 0) & 0x1f;
17742359fc6fSVignesh R read->opcode = (half >> 8) & 0xff;
17752359fc6fSVignesh R read->proto = proto;
17762359fc6fSVignesh R }
17772359fc6fSVignesh R
17782359fc6fSVignesh R struct sfdp_bfpt_read {
17792359fc6fSVignesh R /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */
17802359fc6fSVignesh R u32 hwcaps;
17812359fc6fSVignesh R
17822359fc6fSVignesh R /*
17832359fc6fSVignesh R * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us
17842359fc6fSVignesh R * whether the Fast Read x-y-z command is supported.
17852359fc6fSVignesh R */
17862359fc6fSVignesh R u32 supported_dword;
17872359fc6fSVignesh R u32 supported_bit;
17882359fc6fSVignesh R
17892359fc6fSVignesh R /*
17902359fc6fSVignesh R * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD
17912359fc6fSVignesh R * encodes the op code, the number of mode clocks and the number of wait
17922359fc6fSVignesh R * states to be used by Fast Read x-y-z command.
17932359fc6fSVignesh R */
17942359fc6fSVignesh R u32 settings_dword;
17952359fc6fSVignesh R u32 settings_shift;
17962359fc6fSVignesh R
17972359fc6fSVignesh R /* The SPI protocol for this Fast Read x-y-z command. */
17982359fc6fSVignesh R enum spi_nor_protocol proto;
17992359fc6fSVignesh R };
18002359fc6fSVignesh R
18012359fc6fSVignesh R static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = {
18022359fc6fSVignesh R /* Fast Read 1-1-2 */
18032359fc6fSVignesh R {
18042359fc6fSVignesh R SNOR_HWCAPS_READ_1_1_2,
18052359fc6fSVignesh R BFPT_DWORD(1), BIT(16), /* Supported bit */
18062359fc6fSVignesh R BFPT_DWORD(4), 0, /* Settings */
18072359fc6fSVignesh R SNOR_PROTO_1_1_2,
18082359fc6fSVignesh R },
18092359fc6fSVignesh R
18102359fc6fSVignesh R /* Fast Read 1-2-2 */
18112359fc6fSVignesh R {
18122359fc6fSVignesh R SNOR_HWCAPS_READ_1_2_2,
18132359fc6fSVignesh R BFPT_DWORD(1), BIT(20), /* Supported bit */
18142359fc6fSVignesh R BFPT_DWORD(4), 16, /* Settings */
18152359fc6fSVignesh R SNOR_PROTO_1_2_2,
18162359fc6fSVignesh R },
18172359fc6fSVignesh R
18182359fc6fSVignesh R /* Fast Read 2-2-2 */
18192359fc6fSVignesh R {
18202359fc6fSVignesh R SNOR_HWCAPS_READ_2_2_2,
18212359fc6fSVignesh R BFPT_DWORD(5), BIT(0), /* Supported bit */
18222359fc6fSVignesh R BFPT_DWORD(6), 16, /* Settings */
18232359fc6fSVignesh R SNOR_PROTO_2_2_2,
18242359fc6fSVignesh R },
18252359fc6fSVignesh R
18262359fc6fSVignesh R /* Fast Read 1-1-4 */
18272359fc6fSVignesh R {
18282359fc6fSVignesh R SNOR_HWCAPS_READ_1_1_4,
18292359fc6fSVignesh R BFPT_DWORD(1), BIT(22), /* Supported bit */
18302359fc6fSVignesh R BFPT_DWORD(3), 16, /* Settings */
18312359fc6fSVignesh R SNOR_PROTO_1_1_4,
18322359fc6fSVignesh R },
18332359fc6fSVignesh R
18342359fc6fSVignesh R /* Fast Read 1-4-4 */
18352359fc6fSVignesh R {
18362359fc6fSVignesh R SNOR_HWCAPS_READ_1_4_4,
18372359fc6fSVignesh R BFPT_DWORD(1), BIT(21), /* Supported bit */
18382359fc6fSVignesh R BFPT_DWORD(3), 0, /* Settings */
18392359fc6fSVignesh R SNOR_PROTO_1_4_4,
18402359fc6fSVignesh R },
18412359fc6fSVignesh R
18422359fc6fSVignesh R /* Fast Read 4-4-4 */
18432359fc6fSVignesh R {
18442359fc6fSVignesh R SNOR_HWCAPS_READ_4_4_4,
18452359fc6fSVignesh R BFPT_DWORD(5), BIT(4), /* Supported bit */
18462359fc6fSVignesh R BFPT_DWORD(7), 16, /* Settings */
18472359fc6fSVignesh R SNOR_PROTO_4_4_4,
18482359fc6fSVignesh R },
18492359fc6fSVignesh R };
18502359fc6fSVignesh R
18512359fc6fSVignesh R struct sfdp_bfpt_erase {
18522359fc6fSVignesh R /*
18532359fc6fSVignesh R * The half-word at offset <shift> in DWORD <dwoard> encodes the
18542359fc6fSVignesh R * op code and erase sector size to be used by Sector Erase commands.
18552359fc6fSVignesh R */
18562359fc6fSVignesh R u32 dword;
18572359fc6fSVignesh R u32 shift;
18582359fc6fSVignesh R };
18592359fc6fSVignesh R
18602359fc6fSVignesh R static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
18612359fc6fSVignesh R /* Erase Type 1 in DWORD8 bits[15:0] */
18622359fc6fSVignesh R {BFPT_DWORD(8), 0},
18632359fc6fSVignesh R
18642359fc6fSVignesh R /* Erase Type 2 in DWORD8 bits[31:16] */
18652359fc6fSVignesh R {BFPT_DWORD(8), 16},
18662359fc6fSVignesh R
18672359fc6fSVignesh R /* Erase Type 3 in DWORD9 bits[15:0] */
18682359fc6fSVignesh R {BFPT_DWORD(9), 0},
18692359fc6fSVignesh R
18702359fc6fSVignesh R /* Erase Type 4 in DWORD9 bits[31:16] */
18712359fc6fSVignesh R {BFPT_DWORD(9), 16},
18722359fc6fSVignesh R };
18732359fc6fSVignesh R
18742359fc6fSVignesh R static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
18752359fc6fSVignesh R
18762359fc6fSVignesh R /**
18774c6d72aaSJon Lin * spi_nor_wr_quad_enable() - set QE bit in Configuration Register with 31H.
18784c6d72aaSJon Lin * @nor: pointer to a 'struct spi_nor'
18794c6d72aaSJon Lin *
18804c6d72aaSJon Lin * Set the Quad Enable (QE) bit in the Configuration Register.
18814c6d72aaSJon Lin * This function should be used with QSPI memories not supporting the Read
18824c6d72aaSJon Lin * Configuration Register (35h) instruction.
18834c6d72aaSJon Lin *
18844c6d72aaSJon Lin * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
18854c6d72aaSJon Lin * memories.
18864c6d72aaSJon Lin *
18874c6d72aaSJon Lin * Return: 0 on success, -errno otherwise.
18884c6d72aaSJon Lin */
spi_nor_wr_quad_enable(struct spi_nor * nor)18894c6d72aaSJon Lin static int spi_nor_wr_quad_enable(struct spi_nor *nor)
18904c6d72aaSJon Lin {
18914c6d72aaSJon Lin int ret, val;
18924c6d72aaSJon Lin
18934c6d72aaSJon Lin val = read_cr(nor);
18944c6d72aaSJon Lin if (val < 0)
18954c6d72aaSJon Lin return val;
18964c6d72aaSJon Lin if (val & CR_QUAD_EN_SPAN)
18974c6d72aaSJon Lin return 0;
18984c6d72aaSJon Lin
18994c6d72aaSJon Lin write_enable(nor);
19004c6d72aaSJon Lin
19014c6d72aaSJon Lin write_cr(nor, val | CR_QUAD_EN_SPAN);
19024c6d72aaSJon Lin
19034c6d72aaSJon Lin ret = spi_nor_wait_till_ready(nor);
19044c6d72aaSJon Lin if (ret)
19054c6d72aaSJon Lin return ret;
19064c6d72aaSJon Lin
19074c6d72aaSJon Lin ret = read_cr(nor);
19084c6d72aaSJon Lin if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
19094c6d72aaSJon Lin dev_err(nor->dev, "Configure register Quad bit not set, ret=%x\n", ret);
19104c6d72aaSJon Lin return -EINVAL;
19114c6d72aaSJon Lin }
19124c6d72aaSJon Lin
19134c6d72aaSJon Lin return 0;
19144c6d72aaSJon Lin }
19154c6d72aaSJon Lin
19164c6d72aaSJon Lin /**
19172359fc6fSVignesh R * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
19182359fc6fSVignesh R * @nor: pointer to a 'struct spi_nor'
19192359fc6fSVignesh R * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing
19202359fc6fSVignesh R * the Basic Flash Parameter Table length and version
19212359fc6fSVignesh R * @params: pointer to the 'struct spi_nor_flash_parameter' to be
19222359fc6fSVignesh R * filled
19232359fc6fSVignesh R *
19242359fc6fSVignesh R * The Basic Flash Parameter Table is the main and only mandatory table as
19252359fc6fSVignesh R * defined by the SFDP (JESD216) specification.
19262359fc6fSVignesh R * It provides us with the total size (memory density) of the data array and
19272359fc6fSVignesh R * the number of address bytes for Fast Read, Page Program and Sector Erase
19282359fc6fSVignesh R * commands.
19292359fc6fSVignesh R * For Fast READ commands, it also gives the number of mode clock cycles and
19302359fc6fSVignesh R * wait states (regrouped in the number of dummy clock cycles) for each
19312359fc6fSVignesh R * supported instruction op code.
19322359fc6fSVignesh R * For Page Program, the page size is now available since JESD216 rev A, however
19332359fc6fSVignesh R * the supported instruction op codes are still not provided.
19342359fc6fSVignesh R * For Sector Erase commands, this table stores the supported instruction op
19352359fc6fSVignesh R * codes and the associated sector sizes.
19362359fc6fSVignesh R * Finally, the Quad Enable Requirements (QER) are also available since JESD216
19372359fc6fSVignesh R * rev A. The QER bits encode the manufacturer dependent procedure to be
19382359fc6fSVignesh R * executed to set the Quad Enable (QE) bit in some internal register of the
19392359fc6fSVignesh R * Quad SPI memory. Indeed the QE bit, when it exists, must be set before
19402359fc6fSVignesh R * sending any Quad SPI command to the memory. Actually, setting the QE bit
19412359fc6fSVignesh R * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2
19422359fc6fSVignesh R * and IO3 hence enabling 4 (Quad) I/O lines.
19432359fc6fSVignesh R *
19442359fc6fSVignesh R * Return: 0 on success, -errno otherwise.
19452359fc6fSVignesh R */
spi_nor_parse_bfpt(struct spi_nor * nor,const struct sfdp_parameter_header * bfpt_header,struct spi_nor_flash_parameter * params)19462359fc6fSVignesh R static int spi_nor_parse_bfpt(struct spi_nor *nor,
19472359fc6fSVignesh R const struct sfdp_parameter_header *bfpt_header,
19482359fc6fSVignesh R struct spi_nor_flash_parameter *params)
19492359fc6fSVignesh R {
19502359fc6fSVignesh R struct mtd_info *mtd = &nor->mtd;
19512359fc6fSVignesh R struct sfdp_bfpt bfpt;
19522359fc6fSVignesh R size_t len;
19532359fc6fSVignesh R int i, cmd, err;
19542359fc6fSVignesh R u32 addr;
19552359fc6fSVignesh R u16 half;
19562359fc6fSVignesh R
19572359fc6fSVignesh R /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
19582359fc6fSVignesh R if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
19592359fc6fSVignesh R return -EINVAL;
19602359fc6fSVignesh R
19612359fc6fSVignesh R /* Read the Basic Flash Parameter Table. */
19622359fc6fSVignesh R len = min_t(size_t, sizeof(bfpt),
19632359fc6fSVignesh R bfpt_header->length * sizeof(u32));
19642359fc6fSVignesh R addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
19652359fc6fSVignesh R memset(&bfpt, 0, sizeof(bfpt));
19662359fc6fSVignesh R err = spi_nor_read_sfdp(nor, addr, len, &bfpt);
19672359fc6fSVignesh R if (err < 0)
19682359fc6fSVignesh R return err;
19692359fc6fSVignesh R
19702359fc6fSVignesh R /* Fix endianness of the BFPT DWORDs. */
19712359fc6fSVignesh R for (i = 0; i < BFPT_DWORD_MAX; i++)
19722359fc6fSVignesh R bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]);
19732359fc6fSVignesh R
19742359fc6fSVignesh R /* Number of address bytes. */
19752359fc6fSVignesh R switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
19762359fc6fSVignesh R case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
19772359fc6fSVignesh R nor->addr_width = 3;
19782359fc6fSVignesh R break;
19792359fc6fSVignesh R
19802359fc6fSVignesh R case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY:
19812359fc6fSVignesh R nor->addr_width = 4;
19822359fc6fSVignesh R break;
19832359fc6fSVignesh R
19842359fc6fSVignesh R default:
19852359fc6fSVignesh R break;
19862359fc6fSVignesh R }
19872359fc6fSVignesh R
19882359fc6fSVignesh R /* Flash Memory Density (in bits). */
19892359fc6fSVignesh R params->size = bfpt.dwords[BFPT_DWORD(2)];
19902359fc6fSVignesh R if (params->size & BIT(31)) {
19912359fc6fSVignesh R params->size &= ~BIT(31);
19922359fc6fSVignesh R
19932359fc6fSVignesh R /*
19942359fc6fSVignesh R * Prevent overflows on params->size. Anyway, a NOR of 2^64
19952359fc6fSVignesh R * bits is unlikely to exist so this error probably means
19962359fc6fSVignesh R * the BFPT we are reading is corrupted/wrong.
19972359fc6fSVignesh R */
19982359fc6fSVignesh R if (params->size > 63)
19992359fc6fSVignesh R return -EINVAL;
20002359fc6fSVignesh R
20012359fc6fSVignesh R params->size = 1ULL << params->size;
20022359fc6fSVignesh R } else {
20032359fc6fSVignesh R params->size++;
20042359fc6fSVignesh R }
20052359fc6fSVignesh R params->size >>= 3; /* Convert to bytes. */
20062359fc6fSVignesh R
20072359fc6fSVignesh R /* Fast Read settings. */
20082359fc6fSVignesh R for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) {
20092359fc6fSVignesh R const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i];
20102359fc6fSVignesh R struct spi_nor_read_command *read;
20112359fc6fSVignesh R
20122359fc6fSVignesh R if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) {
20132359fc6fSVignesh R params->hwcaps.mask &= ~rd->hwcaps;
20142359fc6fSVignesh R continue;
20152359fc6fSVignesh R }
20162359fc6fSVignesh R
20172359fc6fSVignesh R params->hwcaps.mask |= rd->hwcaps;
20182359fc6fSVignesh R cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps);
20192359fc6fSVignesh R read = ¶ms->reads[cmd];
20202359fc6fSVignesh R half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift;
20212359fc6fSVignesh R spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
20222359fc6fSVignesh R }
20232359fc6fSVignesh R
20242359fc6fSVignesh R /* Sector Erase settings. */
20252359fc6fSVignesh R for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) {
20262359fc6fSVignesh R const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i];
20272359fc6fSVignesh R u32 erasesize;
20282359fc6fSVignesh R u8 opcode;
20292359fc6fSVignesh R
20302359fc6fSVignesh R half = bfpt.dwords[er->dword] >> er->shift;
20312359fc6fSVignesh R erasesize = half & 0xff;
20322359fc6fSVignesh R
20332359fc6fSVignesh R /* erasesize == 0 means this Erase Type is not supported. */
20342359fc6fSVignesh R if (!erasesize)
20352359fc6fSVignesh R continue;
20362359fc6fSVignesh R
20372359fc6fSVignesh R erasesize = 1U << erasesize;
20382359fc6fSVignesh R opcode = (half >> 8) & 0xff;
2039ec971092SVignesh Raghavendra #ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
20402359fc6fSVignesh R if (erasesize == SZ_4K) {
20412359fc6fSVignesh R nor->erase_opcode = opcode;
20422359fc6fSVignesh R mtd->erasesize = erasesize;
20432359fc6fSVignesh R break;
20442359fc6fSVignesh R }
20452359fc6fSVignesh R #endif
20462359fc6fSVignesh R if (!mtd->erasesize || mtd->erasesize < erasesize) {
20472359fc6fSVignesh R nor->erase_opcode = opcode;
20482359fc6fSVignesh R mtd->erasesize = erasesize;
20492359fc6fSVignesh R }
20502359fc6fSVignesh R }
20512359fc6fSVignesh R
20522359fc6fSVignesh R /* Stop here if not JESD216 rev A or later. */
20532359fc6fSVignesh R if (bfpt_header->length < BFPT_DWORD_MAX)
20542359fc6fSVignesh R return 0;
20552359fc6fSVignesh R
20562359fc6fSVignesh R /* Page size: this field specifies 'N' so the page size = 2^N bytes. */
20572359fc6fSVignesh R params->page_size = bfpt.dwords[BFPT_DWORD(11)];
20582359fc6fSVignesh R params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK;
20592359fc6fSVignesh R params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT;
20602359fc6fSVignesh R params->page_size = 1U << params->page_size;
20612359fc6fSVignesh R
20622359fc6fSVignesh R /* Quad Enable Requirements. */
20632359fc6fSVignesh R switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
20642359fc6fSVignesh R case BFPT_DWORD15_QER_NONE:
20652359fc6fSVignesh R params->quad_enable = NULL;
20662359fc6fSVignesh R break;
20672359fc6fSVignesh R #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
20682359fc6fSVignesh R case BFPT_DWORD15_QER_SR2_BIT1_BUGGY:
20692359fc6fSVignesh R case BFPT_DWORD15_QER_SR2_BIT1_NO_RD:
20702359fc6fSVignesh R params->quad_enable = spansion_no_read_cr_quad_enable;
20712359fc6fSVignesh R break;
20722359fc6fSVignesh R #endif
20732359fc6fSVignesh R #ifdef CONFIG_SPI_FLASH_MACRONIX
20742359fc6fSVignesh R case BFPT_DWORD15_QER_SR1_BIT6:
20752359fc6fSVignesh R params->quad_enable = macronix_quad_enable;
20762359fc6fSVignesh R break;
20772359fc6fSVignesh R #endif
20782359fc6fSVignesh R #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
20792359fc6fSVignesh R case BFPT_DWORD15_QER_SR2_BIT1:
20802359fc6fSVignesh R params->quad_enable = spansion_read_cr_quad_enable;
20812359fc6fSVignesh R break;
20822359fc6fSVignesh R #endif
20834c6d72aaSJon Lin case BFPT_DWORD15_QER_SR2_BIT1_WR:
20844c6d72aaSJon Lin params->quad_enable = spi_nor_wr_quad_enable;
20854c6d72aaSJon Lin break;
20862359fc6fSVignesh R default:
20872359fc6fSVignesh R return -EINVAL;
20882359fc6fSVignesh R }
20892359fc6fSVignesh R
20902359fc6fSVignesh R return 0;
20912359fc6fSVignesh R }
20922359fc6fSVignesh R
20932359fc6fSVignesh R /**
20942359fc6fSVignesh R * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
20952359fc6fSVignesh R * @nor: pointer to a 'struct spi_nor'
20962359fc6fSVignesh R * @params: pointer to the 'struct spi_nor_flash_parameter' to be
20972359fc6fSVignesh R * filled
20982359fc6fSVignesh R *
20992359fc6fSVignesh R * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216
21002359fc6fSVignesh R * specification. This is a standard which tends to supported by almost all
21012359fc6fSVignesh R * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at
21022359fc6fSVignesh R * runtime the main parameters needed to perform basic SPI flash operations such
21032359fc6fSVignesh R * as Fast Read, Page Program or Sector Erase commands.
21042359fc6fSVignesh R *
21052359fc6fSVignesh R * Return: 0 on success, -errno otherwise.
21062359fc6fSVignesh R */
spi_nor_parse_sfdp(struct spi_nor * nor,struct spi_nor_flash_parameter * params)21072359fc6fSVignesh R static int spi_nor_parse_sfdp(struct spi_nor *nor,
21082359fc6fSVignesh R struct spi_nor_flash_parameter *params)
21092359fc6fSVignesh R {
21102359fc6fSVignesh R const struct sfdp_parameter_header *param_header, *bfpt_header;
21112359fc6fSVignesh R struct sfdp_parameter_header *param_headers = NULL;
21122359fc6fSVignesh R struct sfdp_header header;
21132359fc6fSVignesh R size_t psize;
21142359fc6fSVignesh R int i, err;
21152359fc6fSVignesh R
21162359fc6fSVignesh R /* Get the SFDP header. */
21172359fc6fSVignesh R err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
21182359fc6fSVignesh R if (err < 0)
21192359fc6fSVignesh R return err;
21202359fc6fSVignesh R
21212359fc6fSVignesh R /* Check the SFDP header version. */
21222359fc6fSVignesh R if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
21232359fc6fSVignesh R header.major != SFDP_JESD216_MAJOR)
21242359fc6fSVignesh R return -EINVAL;
21252359fc6fSVignesh R
21262359fc6fSVignesh R /*
21272359fc6fSVignesh R * Verify that the first and only mandatory parameter header is a
21282359fc6fSVignesh R * Basic Flash Parameter Table header as specified in JESD216.
21292359fc6fSVignesh R */
21302359fc6fSVignesh R bfpt_header = &header.bfpt_header;
21312359fc6fSVignesh R if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID ||
21322359fc6fSVignesh R bfpt_header->major != SFDP_JESD216_MAJOR)
21332359fc6fSVignesh R return -EINVAL;
21342359fc6fSVignesh R
21352359fc6fSVignesh R /*
21362359fc6fSVignesh R * Allocate memory then read all parameter headers with a single
21372359fc6fSVignesh R * Read SFDP command. These parameter headers will actually be parsed
21382359fc6fSVignesh R * twice: a first time to get the latest revision of the basic flash
21392359fc6fSVignesh R * parameter table, then a second time to handle the supported optional
21402359fc6fSVignesh R * tables.
21412359fc6fSVignesh R * Hence we read the parameter headers once for all to reduce the
21422359fc6fSVignesh R * processing time. Also we use kmalloc() instead of devm_kmalloc()
21432359fc6fSVignesh R * because we don't need to keep these parameter headers: the allocated
21442359fc6fSVignesh R * memory is always released with kfree() before exiting this function.
21452359fc6fSVignesh R */
21462359fc6fSVignesh R if (header.nph) {
21472359fc6fSVignesh R psize = header.nph * sizeof(*param_headers);
21482359fc6fSVignesh R
21492359fc6fSVignesh R param_headers = kmalloc(psize, GFP_KERNEL);
21502359fc6fSVignesh R if (!param_headers)
21512359fc6fSVignesh R return -ENOMEM;
21522359fc6fSVignesh R
21532359fc6fSVignesh R err = spi_nor_read_sfdp(nor, sizeof(header),
21542359fc6fSVignesh R psize, param_headers);
21552359fc6fSVignesh R if (err < 0) {
21562359fc6fSVignesh R dev_err(dev, "failed to read SFDP parameter headers\n");
21572359fc6fSVignesh R goto exit;
21582359fc6fSVignesh R }
21592359fc6fSVignesh R }
21602359fc6fSVignesh R
21612359fc6fSVignesh R /*
21622359fc6fSVignesh R * Check other parameter headers to get the latest revision of
21632359fc6fSVignesh R * the basic flash parameter table.
21642359fc6fSVignesh R */
21652359fc6fSVignesh R for (i = 0; i < header.nph; i++) {
21662359fc6fSVignesh R param_header = ¶m_headers[i];
21672359fc6fSVignesh R
21682359fc6fSVignesh R if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID &&
21692359fc6fSVignesh R param_header->major == SFDP_JESD216_MAJOR &&
21702359fc6fSVignesh R (param_header->minor > bfpt_header->minor ||
21712359fc6fSVignesh R (param_header->minor == bfpt_header->minor &&
21722359fc6fSVignesh R param_header->length > bfpt_header->length)))
21732359fc6fSVignesh R bfpt_header = param_header;
21742359fc6fSVignesh R }
21752359fc6fSVignesh R
21762359fc6fSVignesh R err = spi_nor_parse_bfpt(nor, bfpt_header, params);
21772359fc6fSVignesh R if (err)
21782359fc6fSVignesh R goto exit;
21792359fc6fSVignesh R
21802359fc6fSVignesh R /* Parse other parameter headers. */
21812359fc6fSVignesh R for (i = 0; i < header.nph; i++) {
21822359fc6fSVignesh R param_header = ¶m_headers[i];
21832359fc6fSVignesh R
21842359fc6fSVignesh R switch (SFDP_PARAM_HEADER_ID(param_header)) {
21852359fc6fSVignesh R case SFDP_SECTOR_MAP_ID:
21862359fc6fSVignesh R dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
21872359fc6fSVignesh R break;
21882359fc6fSVignesh R
21892359fc6fSVignesh R default:
21902359fc6fSVignesh R break;
21912359fc6fSVignesh R }
21922359fc6fSVignesh R
21932359fc6fSVignesh R if (err)
21942359fc6fSVignesh R goto exit;
21952359fc6fSVignesh R }
21962359fc6fSVignesh R
21972359fc6fSVignesh R exit:
21982359fc6fSVignesh R kfree(param_headers);
21992359fc6fSVignesh R return err;
22002359fc6fSVignesh R }
22012359fc6fSVignesh R #else
spi_nor_parse_sfdp(struct spi_nor * nor,struct spi_nor_flash_parameter * params)22022359fc6fSVignesh R static int spi_nor_parse_sfdp(struct spi_nor *nor,
22032359fc6fSVignesh R struct spi_nor_flash_parameter *params)
22042359fc6fSVignesh R {
22052359fc6fSVignesh R return -EINVAL;
22062359fc6fSVignesh R }
22072359fc6fSVignesh R #endif /* SPI_FLASH_SFDP_SUPPORT */
22082359fc6fSVignesh R
spi_nor_init_params(struct spi_nor * nor,const struct flash_info * info,struct spi_nor_flash_parameter * params)2209a2b7f194SVignesh R static int spi_nor_init_params(struct spi_nor *nor,
2210a2b7f194SVignesh R const struct flash_info *info,
2211a2b7f194SVignesh R struct spi_nor_flash_parameter *params)
2212a2b7f194SVignesh R {
2213a2b7f194SVignesh R /* Set legacy flash parameters as default. */
2214a2b7f194SVignesh R memset(params, 0, sizeof(*params));
2215a2b7f194SVignesh R
2216a2b7f194SVignesh R /* Set SPI NOR sizes. */
2217a2b7f194SVignesh R params->size = info->sector_size * info->n_sectors;
2218a2b7f194SVignesh R params->page_size = info->page_size;
2219a2b7f194SVignesh R
2220a2b7f194SVignesh R /* (Fast) Read settings. */
2221a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_READ;
2222a2b7f194SVignesh R spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ],
2223a2b7f194SVignesh R 0, 0, SPINOR_OP_READ,
2224a2b7f194SVignesh R SNOR_PROTO_1_1_1);
2225a2b7f194SVignesh R
2226a2b7f194SVignesh R if (!(info->flags & SPI_NOR_NO_FR)) {
2227a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
2228a2b7f194SVignesh R spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST],
2229a2b7f194SVignesh R 0, 8, SPINOR_OP_READ_FAST,
2230a2b7f194SVignesh R SNOR_PROTO_1_1_1);
2231a2b7f194SVignesh R }
2232a2b7f194SVignesh R
2233a2b7f194SVignesh R if (info->flags & SPI_NOR_DUAL_READ) {
2234a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
2235a2b7f194SVignesh R spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2],
2236a2b7f194SVignesh R 0, 8, SPINOR_OP_READ_1_1_2,
2237a2b7f194SVignesh R SNOR_PROTO_1_1_2);
2238a2b7f194SVignesh R }
2239a2b7f194SVignesh R
2240a2b7f194SVignesh R if (info->flags & SPI_NOR_QUAD_READ) {
2241a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
2242a2b7f194SVignesh R spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4],
2243a2b7f194SVignesh R 0, 8, SPINOR_OP_READ_1_1_4,
2244a2b7f194SVignesh R SNOR_PROTO_1_1_4);
2245a2b7f194SVignesh R }
2246a2b7f194SVignesh R
2247305d7e6eSVignesh Raghavendra if (info->flags & SPI_NOR_OCTAL_READ) {
2248305d7e6eSVignesh Raghavendra params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
2249305d7e6eSVignesh Raghavendra spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8],
2250305d7e6eSVignesh Raghavendra 0, 8, SPINOR_OP_READ_1_1_8,
2251305d7e6eSVignesh Raghavendra SNOR_PROTO_1_1_8);
2252305d7e6eSVignesh Raghavendra }
2253305d7e6eSVignesh Raghavendra
2254a2b7f194SVignesh R /* Page Program settings. */
2255a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_PP;
2256a2b7f194SVignesh R spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP],
2257a2b7f194SVignesh R SPINOR_OP_PP, SNOR_PROTO_1_1_1);
2258a2b7f194SVignesh R
2259a2b7f194SVignesh R if (info->flags & SPI_NOR_QUAD_READ) {
2260a2b7f194SVignesh R params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
2261a2b7f194SVignesh R spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4],
2262a2b7f194SVignesh R SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4);
2263a2b7f194SVignesh R }
2264a2b7f194SVignesh R
2265a2b7f194SVignesh R /* Select the procedure to set the Quad Enable bit. */
2266a2b7f194SVignesh R if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
2267a2b7f194SVignesh R SNOR_HWCAPS_PP_QUAD)) {
2268a2b7f194SVignesh R switch (JEDEC_MFR(info)) {
2269a2b7f194SVignesh R #ifdef CONFIG_SPI_FLASH_MACRONIX
2270a2b7f194SVignesh R case SNOR_MFR_MACRONIX:
2271a2b7f194SVignesh R params->quad_enable = macronix_quad_enable;
2272a2b7f194SVignesh R break;
2273a2b7f194SVignesh R #endif
2274a2b7f194SVignesh R case SNOR_MFR_ST:
2275a2b7f194SVignesh R case SNOR_MFR_MICRON:
2276a2b7f194SVignesh R break;
22771f301960SJon Lin #ifdef CONFIG_SPI_FLASH_NORMEM
22781f301960SJon Lin case SNOR_MFR_NORMEM:
22791f301960SJon Lin params->quad_enable = normem_quad_enable;
22801f301960SJon Lin break;
22811f301960SJon Lin #endif
2282a2b7f194SVignesh R default:
2283a2b7f194SVignesh R #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
2284a2b7f194SVignesh R /* Kept only for backward compatibility purpose. */
2285a2b7f194SVignesh R params->quad_enable = spansion_read_cr_quad_enable;
2286a2b7f194SVignesh R #endif
2287a2b7f194SVignesh R break;
2288a2b7f194SVignesh R }
2289a2b7f194SVignesh R }
22902359fc6fSVignesh R
22912359fc6fSVignesh R /* Override the parameters with data read from SFDP tables. */
22922359fc6fSVignesh R nor->addr_width = 0;
22932359fc6fSVignesh R nor->mtd.erasesize = 0;
22942359fc6fSVignesh R if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
22952359fc6fSVignesh R !(info->flags & SPI_NOR_SKIP_SFDP)) {
22962359fc6fSVignesh R struct spi_nor_flash_parameter sfdp_params;
22972359fc6fSVignesh R
22982359fc6fSVignesh R memcpy(&sfdp_params, params, sizeof(sfdp_params));
22992359fc6fSVignesh R if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
23002359fc6fSVignesh R nor->addr_width = 0;
23012359fc6fSVignesh R nor->mtd.erasesize = 0;
23022359fc6fSVignesh R } else {
23032359fc6fSVignesh R memcpy(params, &sfdp_params, sizeof(*params));
23042359fc6fSVignesh R }
23052359fc6fSVignesh R }
23062359fc6fSVignesh R
23072359fc6fSVignesh R return 0;
2308a2b7f194SVignesh R }
2309a2b7f194SVignesh R
spi_nor_hwcaps2cmd(u32 hwcaps,const int table[][2],size_t size)2310a2b7f194SVignesh R static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
2311a2b7f194SVignesh R {
2312a2b7f194SVignesh R size_t i;
2313a2b7f194SVignesh R
2314a2b7f194SVignesh R for (i = 0; i < size; i++)
2315a2b7f194SVignesh R if (table[i][0] == (int)hwcaps)
2316a2b7f194SVignesh R return table[i][1];
2317a2b7f194SVignesh R
2318a2b7f194SVignesh R return -EINVAL;
2319a2b7f194SVignesh R }
2320a2b7f194SVignesh R
spi_nor_hwcaps_read2cmd(u32 hwcaps)2321a2b7f194SVignesh R static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
2322a2b7f194SVignesh R {
2323a2b7f194SVignesh R static const int hwcaps_read2cmd[][2] = {
2324a2b7f194SVignesh R { SNOR_HWCAPS_READ, SNOR_CMD_READ },
2325a2b7f194SVignesh R { SNOR_HWCAPS_READ_FAST, SNOR_CMD_READ_FAST },
2326a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_1_1_DTR, SNOR_CMD_READ_1_1_1_DTR },
2327a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_1_2, SNOR_CMD_READ_1_1_2 },
2328a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_2_2, SNOR_CMD_READ_1_2_2 },
2329a2b7f194SVignesh R { SNOR_HWCAPS_READ_2_2_2, SNOR_CMD_READ_2_2_2 },
2330a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_2_2_DTR, SNOR_CMD_READ_1_2_2_DTR },
2331a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_1_4, SNOR_CMD_READ_1_1_4 },
2332a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_4_4, SNOR_CMD_READ_1_4_4 },
2333a2b7f194SVignesh R { SNOR_HWCAPS_READ_4_4_4, SNOR_CMD_READ_4_4_4 },
2334a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_4_4_DTR, SNOR_CMD_READ_1_4_4_DTR },
2335a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_1_8, SNOR_CMD_READ_1_1_8 },
2336a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_8_8, SNOR_CMD_READ_1_8_8 },
2337a2b7f194SVignesh R { SNOR_HWCAPS_READ_8_8_8, SNOR_CMD_READ_8_8_8 },
2338a2b7f194SVignesh R { SNOR_HWCAPS_READ_1_8_8_DTR, SNOR_CMD_READ_1_8_8_DTR },
2339a2b7f194SVignesh R };
2340a2b7f194SVignesh R
2341a2b7f194SVignesh R return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
2342a2b7f194SVignesh R ARRAY_SIZE(hwcaps_read2cmd));
2343a2b7f194SVignesh R }
2344a2b7f194SVignesh R
spi_nor_hwcaps_pp2cmd(u32 hwcaps)2345a2b7f194SVignesh R static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
2346a2b7f194SVignesh R {
2347a2b7f194SVignesh R static const int hwcaps_pp2cmd[][2] = {
2348a2b7f194SVignesh R { SNOR_HWCAPS_PP, SNOR_CMD_PP },
2349a2b7f194SVignesh R { SNOR_HWCAPS_PP_1_1_4, SNOR_CMD_PP_1_1_4 },
2350a2b7f194SVignesh R { SNOR_HWCAPS_PP_1_4_4, SNOR_CMD_PP_1_4_4 },
2351a2b7f194SVignesh R { SNOR_HWCAPS_PP_4_4_4, SNOR_CMD_PP_4_4_4 },
2352a2b7f194SVignesh R { SNOR_HWCAPS_PP_1_1_8, SNOR_CMD_PP_1_1_8 },
2353a2b7f194SVignesh R { SNOR_HWCAPS_PP_1_8_8, SNOR_CMD_PP_1_8_8 },
2354a2b7f194SVignesh R { SNOR_HWCAPS_PP_8_8_8, SNOR_CMD_PP_8_8_8 },
2355a2b7f194SVignesh R };
2356a2b7f194SVignesh R
2357a2b7f194SVignesh R return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
2358a2b7f194SVignesh R ARRAY_SIZE(hwcaps_pp2cmd));
2359a2b7f194SVignesh R }
2360a2b7f194SVignesh R
spi_nor_select_read(struct spi_nor * nor,const struct spi_nor_flash_parameter * params,u32 shared_hwcaps)2361a2b7f194SVignesh R static int spi_nor_select_read(struct spi_nor *nor,
2362a2b7f194SVignesh R const struct spi_nor_flash_parameter *params,
2363a2b7f194SVignesh R u32 shared_hwcaps)
2364a2b7f194SVignesh R {
2365a2b7f194SVignesh R int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_READ_MASK) - 1;
2366a2b7f194SVignesh R const struct spi_nor_read_command *read;
2367a2b7f194SVignesh R
2368a2b7f194SVignesh R if (best_match < 0)
2369a2b7f194SVignesh R return -EINVAL;
2370a2b7f194SVignesh R
2371a2b7f194SVignesh R cmd = spi_nor_hwcaps_read2cmd(BIT(best_match));
2372a2b7f194SVignesh R if (cmd < 0)
2373a2b7f194SVignesh R return -EINVAL;
2374a2b7f194SVignesh R
2375a2b7f194SVignesh R read = ¶ms->reads[cmd];
2376a2b7f194SVignesh R nor->read_opcode = read->opcode;
2377a2b7f194SVignesh R nor->read_proto = read->proto;
2378a2b7f194SVignesh R
2379a2b7f194SVignesh R /*
2380a2b7f194SVignesh R * In the spi-nor framework, we don't need to make the difference
2381a2b7f194SVignesh R * between mode clock cycles and wait state clock cycles.
2382a2b7f194SVignesh R * Indeed, the value of the mode clock cycles is used by a QSPI
2383a2b7f194SVignesh R * flash memory to know whether it should enter or leave its 0-4-4
2384a2b7f194SVignesh R * (Continuous Read / XIP) mode.
2385a2b7f194SVignesh R * eXecution In Place is out of the scope of the mtd sub-system.
2386a2b7f194SVignesh R * Hence we choose to merge both mode and wait state clock cycles
2387a2b7f194SVignesh R * into the so called dummy clock cycles.
2388a2b7f194SVignesh R */
2389a2b7f194SVignesh R nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
2390a2b7f194SVignesh R return 0;
2391a2b7f194SVignesh R }
2392a2b7f194SVignesh R
spi_nor_select_pp(struct spi_nor * nor,const struct spi_nor_flash_parameter * params,u32 shared_hwcaps)2393a2b7f194SVignesh R static int spi_nor_select_pp(struct spi_nor *nor,
2394a2b7f194SVignesh R const struct spi_nor_flash_parameter *params,
2395a2b7f194SVignesh R u32 shared_hwcaps)
2396a2b7f194SVignesh R {
2397a2b7f194SVignesh R int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_PP_MASK) - 1;
2398a2b7f194SVignesh R const struct spi_nor_pp_command *pp;
2399a2b7f194SVignesh R
2400a2b7f194SVignesh R if (best_match < 0)
2401a2b7f194SVignesh R return -EINVAL;
2402a2b7f194SVignesh R
2403a2b7f194SVignesh R cmd = spi_nor_hwcaps_pp2cmd(BIT(best_match));
2404a2b7f194SVignesh R if (cmd < 0)
2405a2b7f194SVignesh R return -EINVAL;
2406a2b7f194SVignesh R
2407a2b7f194SVignesh R pp = ¶ms->page_programs[cmd];
2408a2b7f194SVignesh R nor->program_opcode = pp->opcode;
2409a2b7f194SVignesh R nor->write_proto = pp->proto;
2410a2b7f194SVignesh R return 0;
2411a2b7f194SVignesh R }
2412a2b7f194SVignesh R
spi_nor_select_erase(struct spi_nor * nor,const struct flash_info * info)2413a2b7f194SVignesh R static int spi_nor_select_erase(struct spi_nor *nor,
2414a2b7f194SVignesh R const struct flash_info *info)
2415a2b7f194SVignesh R {
2416a2b7f194SVignesh R struct mtd_info *mtd = &nor->mtd;
2417a2b7f194SVignesh R
24182359fc6fSVignesh R /* Do nothing if already configured from SFDP. */
24192359fc6fSVignesh R if (mtd->erasesize)
24202359fc6fSVignesh R return 0;
24212359fc6fSVignesh R
2422a2b7f194SVignesh R #ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
2423a2b7f194SVignesh R /* prefer "small sector" erase if possible */
2424a2b7f194SVignesh R if (info->flags & SECT_4K) {
2425a2b7f194SVignesh R nor->erase_opcode = SPINOR_OP_BE_4K;
2426a2b7f194SVignesh R mtd->erasesize = 4096;
2427a2b7f194SVignesh R } else if (info->flags & SECT_4K_PMC) {
2428a2b7f194SVignesh R nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
2429a2b7f194SVignesh R mtd->erasesize = 4096;
2430a2b7f194SVignesh R } else
2431a2b7f194SVignesh R #endif
2432a2b7f194SVignesh R {
2433a2b7f194SVignesh R nor->erase_opcode = SPINOR_OP_SE;
2434a2b7f194SVignesh R mtd->erasesize = info->sector_size;
2435a2b7f194SVignesh R }
2436a2b7f194SVignesh R return 0;
2437a2b7f194SVignesh R }
2438a2b7f194SVignesh R
spi_nor_setup(struct spi_nor * nor,const struct flash_info * info,const struct spi_nor_flash_parameter * params,const struct spi_nor_hwcaps * hwcaps)2439a2b7f194SVignesh R static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
2440a2b7f194SVignesh R const struct spi_nor_flash_parameter *params,
2441a2b7f194SVignesh R const struct spi_nor_hwcaps *hwcaps)
2442a2b7f194SVignesh R {
2443a2b7f194SVignesh R u32 ignored_mask, shared_mask;
2444a2b7f194SVignesh R bool enable_quad_io;
2445a2b7f194SVignesh R int err;
2446a2b7f194SVignesh R
2447a2b7f194SVignesh R /*
2448a2b7f194SVignesh R * Keep only the hardware capabilities supported by both the SPI
2449a2b7f194SVignesh R * controller and the SPI flash memory.
2450a2b7f194SVignesh R */
2451a2b7f194SVignesh R shared_mask = hwcaps->mask & params->hwcaps.mask;
2452a2b7f194SVignesh R
2453a2b7f194SVignesh R /* SPI n-n-n protocols are not supported yet. */
2454a2b7f194SVignesh R ignored_mask = (SNOR_HWCAPS_READ_2_2_2 |
2455a2b7f194SVignesh R SNOR_HWCAPS_READ_4_4_4 |
2456a2b7f194SVignesh R SNOR_HWCAPS_READ_8_8_8 |
2457a2b7f194SVignesh R SNOR_HWCAPS_PP_4_4_4 |
2458a2b7f194SVignesh R SNOR_HWCAPS_PP_8_8_8);
2459a2b7f194SVignesh R if (shared_mask & ignored_mask) {
2460a2b7f194SVignesh R dev_dbg(nor->dev,
2461a2b7f194SVignesh R "SPI n-n-n protocols are not supported yet.\n");
2462a2b7f194SVignesh R shared_mask &= ~ignored_mask;
2463a2b7f194SVignesh R }
2464a2b7f194SVignesh R
2465a2b7f194SVignesh R /* Select the (Fast) Read command. */
2466a2b7f194SVignesh R err = spi_nor_select_read(nor, params, shared_mask);
2467a2b7f194SVignesh R if (err) {
2468a2b7f194SVignesh R dev_dbg(nor->dev,
2469a2b7f194SVignesh R "can't select read settings supported by both the SPI controller and memory.\n");
2470a2b7f194SVignesh R return err;
2471a2b7f194SVignesh R }
2472a2b7f194SVignesh R
2473a2b7f194SVignesh R /* Select the Page Program command. */
2474a2b7f194SVignesh R err = spi_nor_select_pp(nor, params, shared_mask);
2475a2b7f194SVignesh R if (err) {
2476a2b7f194SVignesh R dev_dbg(nor->dev,
2477a2b7f194SVignesh R "can't select write settings supported by both the SPI controller and memory.\n");
2478a2b7f194SVignesh R return err;
2479a2b7f194SVignesh R }
2480a2b7f194SVignesh R
2481a2b7f194SVignesh R /* Select the Sector Erase command. */
2482a2b7f194SVignesh R err = spi_nor_select_erase(nor, info);
2483a2b7f194SVignesh R if (err) {
2484a2b7f194SVignesh R dev_dbg(nor->dev,
2485a2b7f194SVignesh R "can't select erase settings supported by both the SPI controller and memory.\n");
2486a2b7f194SVignesh R return err;
2487a2b7f194SVignesh R }
2488a2b7f194SVignesh R
2489a2b7f194SVignesh R /* Enable Quad I/O if needed. */
2490a2b7f194SVignesh R enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
2491a2b7f194SVignesh R spi_nor_get_protocol_width(nor->write_proto) == 4);
2492a2b7f194SVignesh R if (enable_quad_io && params->quad_enable)
2493a2b7f194SVignesh R nor->quad_enable = params->quad_enable;
2494a2b7f194SVignesh R else
2495a2b7f194SVignesh R nor->quad_enable = NULL;
2496a2b7f194SVignesh R
2497a2b7f194SVignesh R return 0;
2498a2b7f194SVignesh R }
2499a2b7f194SVignesh R
spi_nor_init(struct spi_nor * nor)2500a2b7f194SVignesh R static int spi_nor_init(struct spi_nor *nor)
2501a2b7f194SVignesh R {
2502a2b7f194SVignesh R int err;
2503a2b7f194SVignesh R
2504a2b7f194SVignesh R /*
2505a2b7f194SVignesh R * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
2506a2b7f194SVignesh R * with the software protection bits set
2507a2b7f194SVignesh R */
2508a2b7f194SVignesh R if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
2509a2b7f194SVignesh R JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
2510a2b7f194SVignesh R JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
2511a2b7f194SVignesh R nor->info->flags & SPI_NOR_HAS_LOCK) {
2512a2b7f194SVignesh R write_enable(nor);
2513a2b7f194SVignesh R write_sr(nor, 0);
2514a2b7f194SVignesh R spi_nor_wait_till_ready(nor);
2515a2b7f194SVignesh R }
2516a2b7f194SVignesh R
2517a2b7f194SVignesh R if (nor->quad_enable) {
2518a2b7f194SVignesh R err = nor->quad_enable(nor);
2519a2b7f194SVignesh R if (err) {
2520a2b7f194SVignesh R dev_dbg(nor->dev, "quad mode not supported\n");
2521a2b7f194SVignesh R return err;
2522a2b7f194SVignesh R }
2523a2b7f194SVignesh R }
2524a2b7f194SVignesh R
2525cd157505SVignesh R if (nor->addr_width == 4 &&
2526cd157505SVignesh R (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
2527cd157505SVignesh R !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
2528cd157505SVignesh R /*
2529cd157505SVignesh R * If the RESET# pin isn't hooked up properly, or the system
2530cd157505SVignesh R * otherwise doesn't perform a reset command in the boot
2531cd157505SVignesh R * sequence, it's impossible to 100% protect against unexpected
2532cd157505SVignesh R * reboots (e.g., crashes). Warn the user (or hopefully, system
2533cd157505SVignesh R * designer) that this is bad.
2534cd157505SVignesh R */
2535cd157505SVignesh R if (nor->flags & SNOR_F_BROKEN_RESET)
2536cd157505SVignesh R printf("enabling reset hack; may not recover from unexpected reboots\n");
2537cd157505SVignesh R set_4byte(nor, nor->info, 1);
2538cd157505SVignesh R }
2539cd157505SVignesh R
2540a2b7f194SVignesh R return 0;
2541a2b7f194SVignesh R }
2542a2b7f194SVignesh R
spi_nor_scan(struct spi_nor * nor)2543a2b7f194SVignesh R int spi_nor_scan(struct spi_nor *nor)
2544a2b7f194SVignesh R {
2545a2b7f194SVignesh R struct spi_nor_flash_parameter params;
2546a2b7f194SVignesh R const struct flash_info *info = NULL;
2547a2b7f194SVignesh R struct mtd_info *mtd = &nor->mtd;
2548a2b7f194SVignesh R struct spi_nor_hwcaps hwcaps = {
2549a2b7f194SVignesh R .mask = SNOR_HWCAPS_READ |
2550a2b7f194SVignesh R SNOR_HWCAPS_READ_FAST |
2551a2b7f194SVignesh R SNOR_HWCAPS_PP,
2552a2b7f194SVignesh R };
2553a2b7f194SVignesh R struct spi_slave *spi = nor->spi;
2554a2b7f194SVignesh R int ret;
2555a2b7f194SVignesh R
2556a2b7f194SVignesh R /* Reset SPI protocol for all commands. */
2557a2b7f194SVignesh R nor->reg_proto = SNOR_PROTO_1_1_1;
2558a2b7f194SVignesh R nor->read_proto = SNOR_PROTO_1_1_1;
2559a2b7f194SVignesh R nor->write_proto = SNOR_PROTO_1_1_1;
2560a2b7f194SVignesh R nor->read = spi_nor_read_data;
2561a2b7f194SVignesh R nor->write = spi_nor_write_data;
2562a2b7f194SVignesh R nor->read_reg = spi_nor_read_reg;
2563a2b7f194SVignesh R nor->write_reg = spi_nor_write_reg;
2564a2b7f194SVignesh R
2565305d7e6eSVignesh Raghavendra if (spi->mode & SPI_RX_OCTAL) {
2566305d7e6eSVignesh Raghavendra hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
2567305d7e6eSVignesh Raghavendra
2568305d7e6eSVignesh Raghavendra if (spi->mode & SPI_TX_OCTAL)
2569305d7e6eSVignesh Raghavendra hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
2570305d7e6eSVignesh Raghavendra SNOR_HWCAPS_PP_1_1_8 |
2571305d7e6eSVignesh Raghavendra SNOR_HWCAPS_PP_1_8_8);
2572305d7e6eSVignesh Raghavendra } else if (spi->mode & SPI_RX_QUAD) {
2573a2b7f194SVignesh R hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
2574a2b7f194SVignesh R
2575a2b7f194SVignesh R if (spi->mode & SPI_TX_QUAD)
2576a2b7f194SVignesh R hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
2577a2b7f194SVignesh R SNOR_HWCAPS_PP_1_1_4 |
2578a2b7f194SVignesh R SNOR_HWCAPS_PP_1_4_4);
2579a2b7f194SVignesh R } else if (spi->mode & SPI_RX_DUAL) {
2580a2b7f194SVignesh R hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
2581a2b7f194SVignesh R
2582a2b7f194SVignesh R if (spi->mode & SPI_TX_DUAL)
2583a2b7f194SVignesh R hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
2584a2b7f194SVignesh R }
2585a2b7f194SVignesh R
2586a2b7f194SVignesh R info = spi_nor_read_id(nor);
2587a2b7f194SVignesh R if (IS_ERR_OR_NULL(info))
2588a2b7f194SVignesh R return -ENOENT;
25892359fc6fSVignesh R /* Parse the Serial Flash Discoverable Parameters table. */
2590a2b7f194SVignesh R ret = spi_nor_init_params(nor, info, ¶ms);
2591a2b7f194SVignesh R if (ret)
2592a2b7f194SVignesh R return ret;
2593a2b7f194SVignesh R
2594a2b7f194SVignesh R if (!mtd->name)
2595a2b7f194SVignesh R mtd->name = info->name;
2596a2b7f194SVignesh R mtd->priv = nor;
2597a2b7f194SVignesh R mtd->type = MTD_NORFLASH;
2598a2b7f194SVignesh R mtd->writesize = 1;
2599a2b7f194SVignesh R mtd->flags = MTD_CAP_NORFLASH;
2600a2b7f194SVignesh R mtd->size = params.size;
2601a2b7f194SVignesh R mtd->_erase = spi_nor_erase;
2602a2b7f194SVignesh R mtd->_read = spi_nor_read;
2603a2b7f194SVignesh R
2604a2b7f194SVignesh R #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
2605a2b7f194SVignesh R /* NOR protection support for STmicro/Micron chips and similar */
2606a2b7f194SVignesh R if (JEDEC_MFR(info) == SNOR_MFR_ST ||
2607a2b7f194SVignesh R JEDEC_MFR(info) == SNOR_MFR_MICRON ||
2608a2b7f194SVignesh R JEDEC_MFR(info) == SNOR_MFR_SST ||
2609a2b7f194SVignesh R info->flags & SPI_NOR_HAS_LOCK) {
2610a2b7f194SVignesh R nor->flash_lock = stm_lock;
2611a2b7f194SVignesh R nor->flash_unlock = stm_unlock;
2612a2b7f194SVignesh R nor->flash_is_locked = stm_is_locked;
2613a2b7f194SVignesh R }
2614a2b7f194SVignesh R #endif
2615a2b7f194SVignesh R
2616a2b7f194SVignesh R #ifdef CONFIG_SPI_FLASH_SST
26174b522e90SEugeniy Paltsev /*
26184b522e90SEugeniy Paltsev * sst26 series block protection implementation differs from other
26194b522e90SEugeniy Paltsev * series.
26204b522e90SEugeniy Paltsev */
26214b522e90SEugeniy Paltsev if (info->flags & SPI_NOR_HAS_SST26LOCK) {
26224b522e90SEugeniy Paltsev nor->flash_lock = sst26_lock;
26234b522e90SEugeniy Paltsev nor->flash_unlock = sst26_unlock;
26244b522e90SEugeniy Paltsev nor->flash_is_locked = sst26_is_locked;
26254b522e90SEugeniy Paltsev }
26264b522e90SEugeniy Paltsev
2627a2b7f194SVignesh R /* sst nor chips use AAI word program */
2628a2b7f194SVignesh R if (info->flags & SST_WRITE)
2629a2b7f194SVignesh R mtd->_write = sst_write;
2630a2b7f194SVignesh R else
2631a2b7f194SVignesh R #endif
2632a2b7f194SVignesh R mtd->_write = spi_nor_write;
2633a2b7f194SVignesh R
2634a2b7f194SVignesh R if (info->flags & USE_FSR)
2635a2b7f194SVignesh R nor->flags |= SNOR_F_USE_FSR;
2636a2b7f194SVignesh R if (info->flags & SPI_NOR_HAS_TB)
2637a2b7f194SVignesh R nor->flags |= SNOR_F_HAS_SR_TB;
2638a2b7f194SVignesh R if (info->flags & NO_CHIP_ERASE)
2639a2b7f194SVignesh R nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
2640a2b7f194SVignesh R if (info->flags & USE_CLSR)
2641a2b7f194SVignesh R nor->flags |= SNOR_F_USE_CLSR;
2642a2b7f194SVignesh R
2643a2b7f194SVignesh R if (info->flags & SPI_NOR_NO_ERASE)
2644a2b7f194SVignesh R mtd->flags |= MTD_NO_ERASE;
2645a2b7f194SVignesh R
2646a2b7f194SVignesh R nor->page_size = params.page_size;
2647a2b7f194SVignesh R mtd->writebufsize = nor->page_size;
2648a2b7f194SVignesh R
2649a2b7f194SVignesh R /* Some devices cannot do fast-read, no matter what DT tells us */
2650a2b7f194SVignesh R if ((info->flags & SPI_NOR_NO_FR) || (spi->mode & SPI_RX_SLOW))
2651a2b7f194SVignesh R params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
2652a2b7f194SVignesh R
2653a2b7f194SVignesh R /*
2654a2b7f194SVignesh R * Configure the SPI memory:
2655a2b7f194SVignesh R * - select op codes for (Fast) Read, Page Program and Sector Erase.
2656a2b7f194SVignesh R * - set the number of dummy cycles (mode cycles + wait states).
2657a2b7f194SVignesh R * - set the SPI protocols for register and memory accesses.
2658a2b7f194SVignesh R * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
2659a2b7f194SVignesh R */
2660a2b7f194SVignesh R ret = spi_nor_setup(nor, info, ¶ms, &hwcaps);
2661a2b7f194SVignesh R if (ret)
2662a2b7f194SVignesh R return ret;
2663a2b7f194SVignesh R
26642359fc6fSVignesh R if (nor->addr_width) {
26652359fc6fSVignesh R /* already configured from SFDP */
26662359fc6fSVignesh R } else if (info->addr_width) {
2667a2b7f194SVignesh R nor->addr_width = info->addr_width;
2668dc6fa43fSVignesh R } else if (mtd->size > SZ_16M) {
2669dc6fa43fSVignesh R #ifndef CONFIG_SPI_FLASH_BAR
2670cd157505SVignesh R /* enable 4-byte addressing if the device exceeds 16MiB */
2671cd157505SVignesh R nor->addr_width = 4;
2672cd157505SVignesh R if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
2673cd157505SVignesh R info->flags & SPI_NOR_4B_OPCODES)
2674cd157505SVignesh R spi_nor_set_4byte_opcodes(nor, info);
2675dc6fa43fSVignesh R #else
2676dc6fa43fSVignesh R /* Configure the BAR - discover bank cmds and read current bank */
2677dc6fa43fSVignesh R nor->addr_width = 3;
2678dc6fa43fSVignesh R ret = read_bar(nor, info);
2679dc6fa43fSVignesh R if (ret < 0)
2680dc6fa43fSVignesh R return ret;
2681dc6fa43fSVignesh R #endif
2682a2b7f194SVignesh R } else {
2683a2b7f194SVignesh R nor->addr_width = 3;
2684a2b7f194SVignesh R }
2685a2b7f194SVignesh R
2686a2b7f194SVignesh R if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
2687a2b7f194SVignesh R dev_dbg(dev, "address width is too large: %u\n",
2688a2b7f194SVignesh R nor->addr_width);
2689a2b7f194SVignesh R return -EINVAL;
2690a2b7f194SVignesh R }
2691a2b7f194SVignesh R
2692a2b7f194SVignesh R /* Send all the required SPI flash commands to initialize device */
2693a2b7f194SVignesh R nor->info = info;
2694a2b7f194SVignesh R ret = spi_nor_init(nor);
2695a2b7f194SVignesh R if (ret)
2696a2b7f194SVignesh R return ret;
2697a2b7f194SVignesh R
2698a2b7f194SVignesh R nor->name = mtd->name;
2699a2b7f194SVignesh R nor->size = mtd->size;
2700a2b7f194SVignesh R nor->erase_size = mtd->erasesize;
2701a2b7f194SVignesh R nor->sector_size = mtd->erasesize;
2702a2b7f194SVignesh R
2703a2b7f194SVignesh R #ifndef CONFIG_SPL_BUILD
2704c4160f28SJon Lin printf("JEDEC id bytes: %02x, %02x, %02x\n", info->id[0], info->id[1], info->id[2]);
2705a2b7f194SVignesh R printf("SF: Detected %s with page size ", nor->name);
2706a2b7f194SVignesh R print_size(nor->page_size, ", erase size ");
2707a2b7f194SVignesh R print_size(nor->erase_size, ", total ");
2708a2b7f194SVignesh R print_size(nor->size, "");
2709a2b7f194SVignesh R puts("\n");
2710a2b7f194SVignesh R #endif
2711a2b7f194SVignesh R
2712*2cf66459SJon Lin #if defined(CONFIG_SPI_FLASH_AUTO_MERGE)
2713*2cf66459SJon Lin nor->auto_merge_single_chip_size = nor->size;
2714*2cf66459SJon Lin nor->spi->auto_merge_cs_cur = 1;
2715*2cf66459SJon Lin if (IS_ERR(spi_nor_read_id(nor))) {
2716*2cf66459SJon Lin printf("spinor enable auto_merge, but only cs0 valid\n");
2717*2cf66459SJon Lin return 0;
2718*2cf66459SJon Lin }
2719*2cf66459SJon Lin ret = spi_nor_init(nor);
2720*2cf66459SJon Lin if (!ret) {
2721*2cf66459SJon Lin mtd->size = mtd->size * 2;
2722*2cf66459SJon Lin nor->size = nor->size * 2;
2723*2cf66459SJon Lin printf("spinor enable auto_merge\n");
2724*2cf66459SJon Lin }
2725*2cf66459SJon Lin #endif
2726*2cf66459SJon Lin
2727a2b7f194SVignesh R return 0;
2728a2b7f194SVignesh R }
2729dc6fa43fSVignesh R
2730dc6fa43fSVignesh R /* U-Boot specific functions, need to extend MTD to support these */
spi_flash_cmd_get_sw_write_prot(struct spi_nor * nor)2731dc6fa43fSVignesh R int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
2732dc6fa43fSVignesh R {
2733dc6fa43fSVignesh R int sr = read_sr(nor);
2734dc6fa43fSVignesh R
2735dc6fa43fSVignesh R if (sr < 0)
2736dc6fa43fSVignesh R return sr;
2737dc6fa43fSVignesh R
2738dc6fa43fSVignesh R return (sr >> 2) & 7;
2739dc6fa43fSVignesh R }
2740