OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 60eee49f37b77bc2d5f46c5db5a5c24d0c31bd02 Mon Sep 17 00:00:00 2001 |
2 | From: Biwen Li <biwen.li@nxp.com> |
||
3 | Date: Tue, 20 Nov 2018 15:36:57 +0800 |
||
4 | Subject: [PATCH] qspi: support layerscape |
||
5 | |||
6 | This is an integrated patch of qspi for layerscape |
||
7 | |||
8 | Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com> |
||
9 | Signed-off-by: Cyrille Pitchen <cyrille.pitchen@wedev4u.fr> |
||
10 | Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> |
||
11 | Signed-off-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com> |
||
12 | Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com> |
||
13 | Signed-off-by: Yogesh Gaur <yogeshnarayan.gaur@nxp.com> |
||
14 | Signed-off-by: Biwen Li <biwen.li@nxp.com> |
||
15 | Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> |
||
16 | --- |
||
17 | .../devicetree/bindings/mtd/fsl-quadspi.txt | 31 ++ |
||
18 | drivers/mtd/spi-nor/fsl-quadspi.c | 444 +++++++++++------- |
||
19 | drivers/mtd/spi-nor/spi-nor.c | 5 + |
||
20 | 3 files changed, 320 insertions(+), 160 deletions(-) |
||
21 | |||
22 | --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt |
||
23 | +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt |
||
24 | @@ -7,6 +7,7 @@ Required properties: |
||
25 | or |
||
26 | "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi", |
||
27 | "fsl,ls1043a-qspi" followed by "fsl,ls1021a-qspi" |
||
28 | + "fsl,ls2080a-qspi" followed by "fsl,ls1088a-qspi", |
||
29 | - reg : the first contains the register location and length, |
||
30 | the second contains the memory mapping address and length |
||
31 | - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" |
||
32 | @@ -39,3 +40,33 @@ qspi0: quadspi@40044000 { |
||
33 | .... |
||
34 | }; |
||
35 | }; |
||
36 | + |
||
37 | +qspi1: quadspi@20c0000 { |
||
38 | + #address-cells = <1>; |
||
39 | + #size-cells = <0>; |
||
40 | + reg = <0x0 0x20c0000 0x0 0x10000>, |
||
41 | + <0x0 0x20000000 0x0 0x10000000>; |
||
42 | + reg-names = "QuadSPI", "QuadSPI-memory"; |
||
43 | + interrupts = <0 25 0x4>; /* Level high type */ |
||
44 | + clocks = <&clockgen 4 3>, <&clockgen 4 3>; |
||
45 | + clock-names = "qspi_en", "qspi"; |
||
46 | + status = "okay"; |
||
47 | + |
||
48 | + qflash0: s25fs512s@0 { |
||
49 | + #address-cells = <1>; |
||
50 | + #size-cells = <1>; |
||
51 | + spi-max-frequency = <20000000>; |
||
52 | + reg = <0>; |
||
53 | + spi-rx-bus-width = <4>; |
||
54 | + spi-tx-bus-width = <4>; |
||
55 | + }; |
||
56 | + |
||
57 | + qflash1: s25fs512s@1 { |
||
58 | + #address-cells = <1>; |
||
59 | + #size-cells = <1>; |
||
60 | + spi-max-frequency = <20000000>; |
||
61 | + reg = <1>; |
||
62 | + spi-rx-bus-width = <4>; |
||
63 | + spi-tx-bus-width = <4>; |
||
64 | + }; |
||
65 | +}; |
||
66 | --- a/drivers/mtd/spi-nor/fsl-quadspi.c |
||
67 | +++ b/drivers/mtd/spi-nor/fsl-quadspi.c |
||
68 | @@ -41,6 +41,7 @@ |
||
69 | #define QUADSPI_QUIRK_TKT253890 (1 << 2) |
||
70 | /* Controller cannot wake up from wait mode, TKT245618 */ |
||
71 | #define QUADSPI_QUIRK_TKT245618 (1 << 3) |
||
72 | +#define QUADSPI_ADDR_REMAP (1 << 4) |
||
73 | |||
74 | /* The registers */ |
||
75 | #define QUADSPI_MCR 0x00 |
||
76 | @@ -183,7 +184,7 @@ |
||
77 | |||
78 | /* Macros for constructing the LUT register. */ |
||
79 | #define LUT0(ins, pad, opr) \ |
||
80 | - (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \ |
||
81 | + (((opr) << OPRND0_SHIFT) | ((pad) << PAD0_SHIFT) | \ |
||
82 | ((LUT_##ins) << INSTR0_SHIFT)) |
||
83 | |||
84 | #define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT) |
||
85 | @@ -193,27 +194,29 @@ |
||
86 | #define QUADSPI_LUT_NUM 64 |
||
87 | |||
88 | /* SEQID -- we can have 16 seqids at most. */ |
||
89 | -#define SEQID_READ 0 |
||
90 | -#define SEQID_WREN 1 |
||
91 | -#define SEQID_WRDI 2 |
||
92 | -#define SEQID_RDSR 3 |
||
93 | -#define SEQID_SE 4 |
||
94 | -#define SEQID_CHIP_ERASE 5 |
||
95 | -#define SEQID_PP 6 |
||
96 | -#define SEQID_RDID 7 |
||
97 | -#define SEQID_WRSR 8 |
||
98 | -#define SEQID_RDCR 9 |
||
99 | -#define SEQID_EN4B 10 |
||
100 | -#define SEQID_BRWR 11 |
||
101 | +/* LUT0 programmed by bootloader, for run-time create entry for LUT seqid 1 */ |
||
102 | +#define SEQID_LUT0_BOOTLOADER 0 |
||
103 | +#define SEQID_LUT1_RUNTIME 1 |
||
104 | +#define SEQID_LUT2_AHBREAD 2 |
||
105 | |||
106 | #define QUADSPI_MIN_IOMAP SZ_4M |
||
107 | |||
108 | +enum fsl_qspi_ops { |
||
109 | + FSL_QSPI_OPS_READ = 0, |
||
110 | + FSL_QSPI_OPS_WRITE, |
||
111 | + FSL_QSPI_OPS_ERASE, |
||
112 | + FSL_QSPI_OPS_READ_REG, |
||
113 | + FSL_QSPI_OPS_WRITE_REG, |
||
114 | + FSL_QSPI_OPS_WRITE_BUF_REG, |
||
115 | +}; |
||
116 | + |
||
117 | enum fsl_qspi_devtype { |
||
118 | FSL_QUADSPI_VYBRID, |
||
119 | FSL_QUADSPI_IMX6SX, |
||
120 | FSL_QUADSPI_IMX7D, |
||
121 | FSL_QUADSPI_IMX6UL, |
||
122 | FSL_QUADSPI_LS1021A, |
||
123 | + FSL_QUADSPI_LS2080A, |
||
124 | }; |
||
125 | |||
126 | struct fsl_qspi_devtype_data { |
||
127 | @@ -267,6 +270,15 @@ static struct fsl_qspi_devtype_data ls10 |
||
128 | .driver_data = 0, |
||
129 | }; |
||
130 | |||
131 | +static const struct fsl_qspi_devtype_data ls2080a_data = { |
||
132 | + .devtype = FSL_QUADSPI_LS2080A, |
||
133 | + .rxfifo = 128, |
||
134 | + .txfifo = 64, |
||
135 | + .ahb_buf_size = 1024, |
||
136 | + .driver_data = QUADSPI_QUIRK_TKT253890 | QUADSPI_ADDR_REMAP, |
||
137 | +}; |
||
138 | + |
||
139 | + |
||
140 | #define FSL_QSPI_MAX_CHIP 4 |
||
141 | struct fsl_qspi { |
||
142 | struct spi_nor nor[FSL_QSPI_MAX_CHIP]; |
||
143 | @@ -310,6 +322,22 @@ static inline int needs_wakeup_wait_mode |
||
144 | } |
||
145 | |||
146 | /* |
||
147 | + * QSPI memory regions split into two parts: a 256MB region that is located |
||
148 | + * in the least significant 4GB of the SoC address space and a 3.75GB region |
||
149 | + * that is located above the least significant 4GB of the SoC address space. |
||
150 | + * |
||
151 | + * The 4GB QSPI address space map is shown below. |
||
152 | + * |
||
153 | + * SoC Address QSPI Address |
||
154 | + * 0x00_2000_0000-0x00_2FFF_FFFF 0x00_0000_0000-0x00_0FFF_FFFF First 256MB |
||
155 | + * 0x04_1000_0000-0x04_FFFF_FFFF 0x00_1000_0000-0x00_FFFF_FFFF Last 3.75GB |
||
156 | + */ |
||
157 | +static inline int need_address_remap(struct fsl_qspi *q) |
||
158 | +{ |
||
159 | + return q->devtype_data->driver_data & QUADSPI_ADDR_REMAP; |
||
160 | +} |
||
161 | + |
||
162 | +/* |
||
163 | * R/W functions for big- or little-endian registers: |
||
164 | * The qSPI controller's endian is independent of the CPU core's endian. |
||
165 | * So far, although the CPU core is little-endian but the qSPI have two |
||
166 | @@ -368,137 +396,160 @@ static irqreturn_t fsl_qspi_irq_handler( |
||
167 | return IRQ_HANDLED; |
||
168 | } |
||
169 | |||
170 | -static void fsl_qspi_init_lut(struct fsl_qspi *q) |
||
171 | +static inline s8 pad_count(s8 pad_val) |
||
172 | { |
||
173 | + s8 count = -1; |
||
174 | + |
||
175 | + if (!pad_val) |
||
176 | + return 0; |
||
177 | + |
||
178 | + while (pad_val) { |
||
179 | + pad_val >>= 1; |
||
180 | + count++; |
||
181 | + } |
||
182 | + return count; |
||
183 | +} |
||
184 | + |
||
185 | +/* |
||
186 | + * Prepare LUT entry for the input cmd. |
||
187 | + * Protocol info is present in instance of struct spi_nor, using which fields |
||
188 | + * like cmd, data, addrlen along with pad info etc can be parsed. |
||
189 | + */ |
||
190 | +static void fsl_qspi_prepare_lut(struct spi_nor *nor, |
||
191 | + enum fsl_qspi_ops ops, u8 cmd) |
||
192 | +{ |
||
193 | + struct fsl_qspi *q = nor->priv; |
||
194 | void __iomem *base = q->iobase; |
||
195 | int rxfifo = q->devtype_data->rxfifo; |
||
196 | + int txfifo = q->devtype_data->txfifo; |
||
197 | u32 lut_base; |
||
198 | - int i; |
||
199 | + u8 cmd_pad, addr_pad, data_pad, dummy_pad; |
||
200 | + enum spi_nor_protocol protocol = 0; |
||
201 | + u8 addrlen = 0; |
||
202 | + u8 read_dm, opcode; |
||
203 | + int stop_lut; |
||
204 | + |
||
205 | + read_dm = opcode = cmd_pad = addr_pad = data_pad = dummy_pad = 0; |
||
206 | + |
||
207 | + switch (ops) { |
||
208 | + case FSL_QSPI_OPS_READ_REG: |
||
209 | + case FSL_QSPI_OPS_WRITE_REG: |
||
210 | + case FSL_QSPI_OPS_WRITE_BUF_REG: |
||
211 | + opcode = cmd; |
||
212 | + protocol = nor->reg_proto; |
||
213 | + break; |
||
214 | + case FSL_QSPI_OPS_READ: |
||
215 | + opcode = cmd; |
||
216 | + read_dm = nor->read_dummy; |
||
217 | + protocol = nor->read_proto; |
||
218 | + break; |
||
219 | + case FSL_QSPI_OPS_WRITE: |
||
220 | + opcode = cmd; |
||
221 | + protocol = nor->write_proto; |
||
222 | + break; |
||
223 | + case FSL_QSPI_OPS_ERASE: |
||
224 | + opcode = cmd; |
||
225 | + break; |
||
226 | + default: |
||
227 | + dev_err(q->dev, "Unsupported operation 0x%.2x\n", ops); |
||
228 | + return; |
||
229 | + } |
||
230 | + |
||
231 | + if (protocol) { |
||
232 | + cmd_pad = spi_nor_get_protocol_inst_nbits(protocol); |
||
233 | + addr_pad = spi_nor_get_protocol_addr_nbits(protocol); |
||
234 | + data_pad = spi_nor_get_protocol_data_nbits(protocol); |
||
235 | + } |
||
236 | + |
||
237 | + dummy_pad = data_pad; |
||
238 | |||
239 | - struct spi_nor *nor = &q->nor[0]; |
||
240 | - u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; |
||
241 | - u8 read_op = nor->read_opcode; |
||
242 | - u8 read_dm = nor->read_dummy; |
||
243 | + dev_dbg(q->dev, "ops:%x opcode:%x pad[cmd:%d, addr:%d, data:%d]\n", |
||
244 | + ops, opcode, cmd_pad, addr_pad, data_pad); |
||
245 | |||
246 | fsl_qspi_unlock_lut(q); |
||
247 | |||
248 | - /* Clear all the LUT table */ |
||
249 | - for (i = 0; i < QUADSPI_LUT_NUM; i++) |
||
250 | - qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); |
||
251 | - |
||
252 | - /* Read */ |
||
253 | - lut_base = SEQID_READ * 4; |
||
254 | - |
||
255 | - qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen), |
||
256 | - base + QUADSPI_LUT(lut_base)); |
||
257 | - qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | |
||
258 | - LUT1(FSL_READ, PAD4, rxfifo), |
||
259 | - base + QUADSPI_LUT(lut_base + 1)); |
||
260 | - |
||
261 | - /* Write enable */ |
||
262 | - lut_base = SEQID_WREN * 4; |
||
263 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN), |
||
264 | - base + QUADSPI_LUT(lut_base)); |
||
265 | - |
||
266 | - /* Page Program */ |
||
267 | - lut_base = SEQID_PP * 4; |
||
268 | - |
||
269 | - qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | |
||
270 | - LUT1(ADDR, PAD1, addrlen), |
||
271 | - base + QUADSPI_LUT(lut_base)); |
||
272 | - qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), |
||
273 | - base + QUADSPI_LUT(lut_base + 1)); |
||
274 | - |
||
275 | - /* Read Status */ |
||
276 | - lut_base = SEQID_RDSR * 4; |
||
277 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) | |
||
278 | - LUT1(FSL_READ, PAD1, 0x1), |
||
279 | - base + QUADSPI_LUT(lut_base)); |
||
280 | - |
||
281 | - /* Erase a sector */ |
||
282 | - lut_base = SEQID_SE * 4; |
||
283 | - |
||
284 | - qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | |
||
285 | - LUT1(ADDR, PAD1, addrlen), |
||
286 | - base + QUADSPI_LUT(lut_base)); |
||
287 | - |
||
288 | - /* Erase the whole chip */ |
||
289 | - lut_base = SEQID_CHIP_ERASE * 4; |
||
290 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE), |
||
291 | - base + QUADSPI_LUT(lut_base)); |
||
292 | - |
||
293 | - /* READ ID */ |
||
294 | - lut_base = SEQID_RDID * 4; |
||
295 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDID) | |
||
296 | - LUT1(FSL_READ, PAD1, 0x8), |
||
297 | - base + QUADSPI_LUT(lut_base)); |
||
298 | - |
||
299 | - /* Write Register */ |
||
300 | - lut_base = SEQID_WRSR * 4; |
||
301 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRSR) | |
||
302 | - LUT1(FSL_WRITE, PAD1, 0x2), |
||
303 | - base + QUADSPI_LUT(lut_base)); |
||
304 | - |
||
305 | - /* Read Configuration Register */ |
||
306 | - lut_base = SEQID_RDCR * 4; |
||
307 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDCR) | |
||
308 | - LUT1(FSL_READ, PAD1, 0x1), |
||
309 | - base + QUADSPI_LUT(lut_base)); |
||
310 | - |
||
311 | - /* Write disable */ |
||
312 | - lut_base = SEQID_WRDI * 4; |
||
313 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI), |
||
314 | - base + QUADSPI_LUT(lut_base)); |
||
315 | - |
||
316 | - /* Enter 4 Byte Mode (Micron) */ |
||
317 | - lut_base = SEQID_EN4B * 4; |
||
318 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B), |
||
319 | - base + QUADSPI_LUT(lut_base)); |
||
320 | - |
||
321 | - /* Enter 4 Byte Mode (Spansion) */ |
||
322 | - lut_base = SEQID_BRWR * 4; |
||
323 | - qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR), |
||
324 | - base + QUADSPI_LUT(lut_base)); |
||
325 | + /* Dynamic LUT */ |
||
326 | + lut_base = SEQID_LUT1_RUNTIME * 4; |
||
327 | + if (ops == FSL_QSPI_OPS_READ) |
||
328 | + lut_base = SEQID_LUT2_AHBREAD * 4; |
||
329 | + |
||
330 | + /* default, STOP instruction to be programmed in (lut_base + 1) reg */ |
||
331 | + stop_lut = 1; |
||
332 | + switch (ops) { |
||
333 | + case FSL_QSPI_OPS_READ_REG: |
||
334 | + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) | |
||
335 | + LUT1(FSL_READ, pad_count(data_pad), rxfifo), |
||
336 | + base + QUADSPI_LUT(lut_base)); |
||
337 | + break; |
||
338 | + case FSL_QSPI_OPS_WRITE_REG: |
||
339 | + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode), |
||
340 | + base + QUADSPI_LUT(lut_base)); |
||
341 | + break; |
||
342 | + case FSL_QSPI_OPS_WRITE_BUF_REG: |
||
343 | + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) | |
||
344 | + LUT1(FSL_WRITE, pad_count(data_pad), txfifo), |
||
345 | + base + QUADSPI_LUT(lut_base)); |
||
346 | + break; |
||
347 | + case FSL_QSPI_OPS_READ: |
||
348 | + case FSL_QSPI_OPS_WRITE: |
||
349 | + case FSL_QSPI_OPS_ERASE: |
||
350 | + /* Common for Read, Write and Erase ops. */ |
||
351 | + |
||
352 | + addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; |
||
353 | + |
||
354 | + qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) | |
||
355 | + LUT1(ADDR, pad_count(addr_pad), addrlen), |
||
356 | + base + QUADSPI_LUT(lut_base)); |
||
357 | + /* |
||
358 | + * For Erase ops - Data and Dummy not required. |
||
359 | + * For Write ops - Dummy not required. |
||
360 | + */ |
||
361 | |||
362 | - fsl_qspi_lock_lut(q); |
||
363 | -} |
||
364 | + if (ops == FSL_QSPI_OPS_READ) { |
||
365 | |||
366 | -/* Get the SEQID for the command */ |
||
367 | -static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) |
||
368 | -{ |
||
369 | - switch (cmd) { |
||
370 | - case SPINOR_OP_READ_1_1_4: |
||
371 | - case SPINOR_OP_READ_1_1_4_4B: |
||
372 | - return SEQID_READ; |
||
373 | - case SPINOR_OP_WREN: |
||
374 | - return SEQID_WREN; |
||
375 | - case SPINOR_OP_WRDI: |
||
376 | - return SEQID_WRDI; |
||
377 | - case SPINOR_OP_RDSR: |
||
378 | - return SEQID_RDSR; |
||
379 | - case SPINOR_OP_SE: |
||
380 | - return SEQID_SE; |
||
381 | - case SPINOR_OP_CHIP_ERASE: |
||
382 | - return SEQID_CHIP_ERASE; |
||
383 | - case SPINOR_OP_PP: |
||
384 | - return SEQID_PP; |
||
385 | - case SPINOR_OP_RDID: |
||
386 | - return SEQID_RDID; |
||
387 | - case SPINOR_OP_WRSR: |
||
388 | - return SEQID_WRSR; |
||
389 | - case SPINOR_OP_RDCR: |
||
390 | - return SEQID_RDCR; |
||
391 | - case SPINOR_OP_EN4B: |
||
392 | - return SEQID_EN4B; |
||
393 | - case SPINOR_OP_BRWR: |
||
394 | - return SEQID_BRWR; |
||
395 | + /* |
||
396 | + * For cmds SPINOR_OP_READ and SPINOR_OP_READ_4B value |
||
397 | + * of dummy cycles are 0. |
||
398 | + */ |
||
399 | + if (read_dm) |
||
400 | + qspi_writel(q, |
||
401 | + LUT0(DUMMY, pad_count(dummy_pad), |
||
402 | + read_dm) | |
||
403 | + LUT1(FSL_READ, pad_count(data_pad), |
||
404 | + rxfifo), |
||
405 | + base + QUADSPI_LUT(lut_base + 1)); |
||
406 | + else |
||
407 | + qspi_writel(q, |
||
408 | + LUT0(FSL_READ, pad_count(data_pad), |
||
409 | + rxfifo), |
||
410 | + base + QUADSPI_LUT(lut_base + 1)); |
||
411 | + |
||
412 | + stop_lut = 2; |
||
413 | + |
||
414 | + /* TODO Add condition to check if READ is IP/AHB. */ |
||
415 | + |
||
416 | + /* For AHB read, add seqid in BFGENCR register. */ |
||
417 | + qspi_writel(q, |
||
418 | + SEQID_LUT2_AHBREAD << |
||
419 | + QUADSPI_BFGENCR_SEQID_SHIFT, |
||
420 | + q->iobase + QUADSPI_BFGENCR); |
||
421 | + } |
||
422 | + |
||
423 | + if (ops == FSL_QSPI_OPS_WRITE) { |
||
424 | + qspi_writel(q, LUT0(FSL_WRITE, pad_count(data_pad), 0), |
||
425 | + base + QUADSPI_LUT(lut_base + 1)); |
||
426 | + stop_lut = 2; |
||
427 | + } |
||
428 | + break; |
||
429 | default: |
||
430 | - if (cmd == q->nor[0].erase_opcode) |
||
431 | - return SEQID_SE; |
||
432 | - dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); |
||
433 | + dev_err(q->dev, "Unsupported operation 0x%.2x\n", ops); |
||
434 | break; |
||
435 | } |
||
436 | - return -EINVAL; |
||
437 | + |
||
438 | + /* prepare LUT for STOP instruction. */ |
||
439 | + qspi_writel(q, 0, base + QUADSPI_LUT(lut_base + stop_lut)); |
||
440 | + |
||
441 | + fsl_qspi_lock_lut(q); |
||
442 | } |
||
443 | |||
444 | static int |
||
445 | @@ -508,6 +559,10 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c |
||
446 | int seqid; |
||
447 | u32 reg, reg2; |
||
448 | int err; |
||
449 | + u32 memmap_phyadd = q->memmap_phy; |
||
450 | + |
||
451 | + if (need_address_remap(q)) |
||
452 | + memmap_phyadd = 0; |
||
453 | |||
454 | init_completion(&q->c); |
||
455 | dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n", |
||
456 | @@ -516,7 +571,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c |
||
457 | /* save the reg */ |
||
458 | reg = qspi_readl(q, base + QUADSPI_MCR); |
||
459 | |||
460 | - qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, |
||
461 | + qspi_writel(q, memmap_phyadd + q->chip_base_addr + addr, |
||
462 | base + QUADSPI_SFAR); |
||
463 | qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, |
||
464 | base + QUADSPI_RBCT); |
||
465 | @@ -533,7 +588,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c |
||
466 | } while (1); |
||
467 | |||
468 | /* trigger the LUT now */ |
||
469 | - seqid = fsl_qspi_get_seqid(q, cmd); |
||
470 | + seqid = SEQID_LUT1_RUNTIME; |
||
471 | qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, |
||
472 | base + QUADSPI_IPCR); |
||
473 | |||
474 | @@ -609,6 +664,7 @@ static ssize_t fsl_qspi_nor_write(struct |
||
475 | { |
||
476 | int ret, i, j; |
||
477 | u32 tmp; |
||
478 | + u8 byts; |
||
479 | |||
480 | dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n", |
||
481 | q->chip_base_addr, to, count); |
||
482 | @@ -618,10 +674,18 @@ static ssize_t fsl_qspi_nor_write(struct |
||
483 | qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); |
||
484 | |||
485 | /* fill the TX data to the FIFO */ |
||
486 | + byts = count; |
||
487 | for (j = 0, i = ((count + 3) / 4); j < i; j++) { |
||
488 | - tmp = fsl_qspi_endian_xchg(q, *txbuf); |
||
489 | + if(byts >= 4) |
||
490 | + tmp = fsl_qspi_endian_xchg(q, *txbuf); |
||
491 | + else { |
||
492 | + memcpy(&tmp, txbuf, byts); |
||
493 | + tmp = fsl_qspi_endian_xchg(q, tmp); |
||
494 | + } |
||
495 | + |
||
496 | qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR); |
||
497 | txbuf++; |
||
498 | + byts -= 4; |
||
499 | } |
||
500 | |||
501 | /* fill the TXFIFO upto 16 bytes for i.MX7d */ |
||
502 | @@ -642,11 +706,15 @@ static void fsl_qspi_set_map_addr(struct |
||
503 | { |
||
504 | int nor_size = q->nor_size; |
||
505 | void __iomem *base = q->iobase; |
||
506 | + u32 memmap_phyadd = q->memmap_phy; |
||
507 | + |
||
508 | + if (need_address_remap(q)) |
||
509 | + memmap_phyadd = 0; |
||
510 | |||
511 | - qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); |
||
512 | - qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD); |
||
513 | - qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD); |
||
514 | - qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD); |
||
515 | + qspi_writel(q, nor_size + memmap_phyadd, base + QUADSPI_SFA1AD); |
||
516 | + qspi_writel(q, nor_size * 2 + memmap_phyadd, base + QUADSPI_SFA2AD); |
||
517 | + qspi_writel(q, nor_size * 3 + memmap_phyadd, base + QUADSPI_SFB1AD); |
||
518 | + qspi_writel(q, nor_size * 4 + memmap_phyadd, base + QUADSPI_SFB2AD); |
||
519 | } |
||
520 | |||
521 | /* |
||
522 | @@ -662,7 +730,7 @@ static void fsl_qspi_set_map_addr(struct |
||
523 | * causes the controller to clear the buffer, and use the sequence pointed |
||
524 | * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. |
||
525 | */ |
||
526 | -static void fsl_qspi_init_abh_read(struct fsl_qspi *q) |
||
527 | +static void fsl_qspi_init_ahb_read(struct fsl_qspi *q) |
||
528 | { |
||
529 | void __iomem *base = q->iobase; |
||
530 | int seqid; |
||
531 | @@ -685,8 +753,8 @@ static void fsl_qspi_init_abh_read(struc |
||
532 | qspi_writel(q, 0, base + QUADSPI_BUF1IND); |
||
533 | qspi_writel(q, 0, base + QUADSPI_BUF2IND); |
||
534 | |||
535 | - /* Set the default lut sequence for AHB Read. */ |
||
536 | - seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); |
||
537 | + /* Set dynamic LUT entry as lut sequence for AHB Read . */ |
||
538 | + seqid = SEQID_LUT2_AHBREAD; |
||
539 | qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT, |
||
540 | q->iobase + QUADSPI_BFGENCR); |
||
541 | } |
||
542 | @@ -729,7 +797,6 @@ static int fsl_qspi_nor_setup(struct fsl |
||
543 | void __iomem *base = q->iobase; |
||
544 | u32 reg; |
||
545 | int ret; |
||
546 | - |
||
547 | /* disable and unprepare clock to avoid glitch pass to controller */ |
||
548 | fsl_qspi_clk_disable_unprep(q); |
||
549 | |||
550 | @@ -747,9 +814,6 @@ static int fsl_qspi_nor_setup(struct fsl |
||
551 | base + QUADSPI_MCR); |
||
552 | udelay(1); |
||
553 | |||
554 | - /* Init the LUT table. */ |
||
555 | - fsl_qspi_init_lut(q); |
||
556 | - |
||
557 | /* Disable the module */ |
||
558 | qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK, |
||
559 | base + QUADSPI_MCR); |
||
560 | @@ -770,6 +834,9 @@ static int fsl_qspi_nor_setup(struct fsl |
||
561 | /* enable the interrupt */ |
||
562 | qspi_writel(q, QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); |
||
563 | |||
564 | + /* Init for AHB read */ |
||
565 | + fsl_qspi_init_ahb_read(q); |
||
566 | + |
||
567 | return 0; |
||
568 | } |
||
569 | |||
570 | @@ -792,12 +859,6 @@ static int fsl_qspi_nor_setup_last(struc |
||
571 | if (ret) |
||
572 | return ret; |
||
573 | |||
574 | - /* Init the LUT table again. */ |
||
575 | - fsl_qspi_init_lut(q); |
||
576 | - |
||
577 | - /* Init for AHB read */ |
||
578 | - fsl_qspi_init_abh_read(q); |
||
579 | - |
||
580 | return 0; |
||
581 | } |
||
582 | |||
583 | @@ -807,6 +868,7 @@ static const struct of_device_id fsl_qsp |
||
584 | { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, |
||
585 | { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, |
||
586 | { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, |
||
587 | + { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, }, |
||
588 | { /* sentinel */ } |
||
589 | }; |
||
590 | MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); |
||
591 | @@ -821,6 +883,7 @@ static int fsl_qspi_read_reg(struct spi_ |
||
592 | int ret; |
||
593 | struct fsl_qspi *q = nor->priv; |
||
594 | |||
595 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ_REG, opcode); |
||
596 | ret = fsl_qspi_runcmd(q, opcode, 0, len); |
||
597 | if (ret) |
||
598 | return ret; |
||
599 | @@ -835,6 +898,8 @@ static int fsl_qspi_write_reg(struct spi |
||
600 | int ret; |
||
601 | |||
602 | if (!buf) { |
||
603 | + /* Prepare LUT for WRITE_REG cmd with input BUF as NULL. */ |
||
604 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE_REG, opcode); |
||
605 | ret = fsl_qspi_runcmd(q, opcode, 0, 1); |
||
606 | if (ret) |
||
607 | return ret; |
||
608 | @@ -843,6 +908,8 @@ static int fsl_qspi_write_reg(struct spi |
||
609 | fsl_qspi_invalid(q); |
||
610 | |||
611 | } else if (len > 0) { |
||
612 | + /* Prepare LUT for WRITE_REG cmd with input BUF non-NULL. */ |
||
613 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE_BUF_REG, opcode); |
||
614 | ret = fsl_qspi_nor_write(q, nor, opcode, 0, |
||
615 | (u32 *)buf, len); |
||
616 | if (ret > 0) |
||
617 | @@ -859,8 +926,11 @@ static ssize_t fsl_qspi_write(struct spi |
||
618 | size_t len, const u_char *buf) |
||
619 | { |
||
620 | struct fsl_qspi *q = nor->priv; |
||
621 | - ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, |
||
622 | - (u32 *)buf, len); |
||
623 | + ssize_t ret; |
||
624 | + |
||
625 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_WRITE, nor->program_opcode); |
||
626 | + ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, |
||
627 | + (u32 *)buf, len); |
||
628 | |||
629 | /* invalid the data in the AHB buffer. */ |
||
630 | fsl_qspi_invalid(q); |
||
631 | @@ -873,6 +943,8 @@ static ssize_t fsl_qspi_read(struct spi_ |
||
632 | struct fsl_qspi *q = nor->priv; |
||
633 | u8 cmd = nor->read_opcode; |
||
634 | |||
635 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ, nor->read_opcode); |
||
636 | + |
||
637 | /* if necessary,ioremap buffer before AHB read, */ |
||
638 | if (!q->ahb_addr) { |
||
639 | q->memmap_offs = q->chip_base_addr + from; |
||
640 | @@ -907,8 +979,9 @@ static ssize_t fsl_qspi_read(struct spi_ |
||
641 | len); |
||
642 | |||
643 | /* Read out the data directly from the AHB buffer.*/ |
||
644 | - memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, |
||
645 | - len); |
||
646 | + memcpy_fromio(buf, |
||
647 | + q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, |
||
648 | + len); |
||
649 | |||
650 | return len; |
||
651 | } |
||
652 | @@ -921,6 +994,7 @@ static int fsl_qspi_erase(struct spi_nor |
||
653 | dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", |
||
654 | nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs); |
||
655 | |||
656 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_ERASE, nor->erase_opcode); |
||
657 | ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0); |
||
658 | if (ret) |
||
659 | return ret; |
||
660 | @@ -958,17 +1032,14 @@ static void fsl_qspi_unprep(struct spi_n |
||
661 | |||
662 | static int fsl_qspi_probe(struct platform_device *pdev) |
||
663 | { |
||
664 | - const struct spi_nor_hwcaps hwcaps = { |
||
665 | - .mask = SNOR_HWCAPS_READ_1_1_4 | |
||
666 | - SNOR_HWCAPS_PP, |
||
667 | - }; |
||
668 | + struct spi_nor_hwcaps hwcaps; |
||
669 | struct device_node *np = pdev->dev.of_node; |
||
670 | struct device *dev = &pdev->dev; |
||
671 | struct fsl_qspi *q; |
||
672 | struct resource *res; |
||
673 | struct spi_nor *nor; |
||
674 | struct mtd_info *mtd; |
||
675 | - int ret, i = 0; |
||
676 | + int ret, i = 0, value; |
||
677 | |||
678 | q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); |
||
679 | if (!q) |
||
680 | @@ -1041,6 +1112,10 @@ static int fsl_qspi_probe(struct platfor |
||
681 | |||
682 | /* iterate the subnodes. */ |
||
683 | for_each_available_child_of_node(dev->of_node, np) { |
||
684 | + /* Reset hwcaps mask to minimal caps for the slave node. */ |
||
685 | + hwcaps.mask = SNOR_HWCAPS_READ | SNOR_HWCAPS_PP; |
||
686 | + value = 0; |
||
687 | + |
||
688 | /* skip the holes */ |
||
689 | if (!q->has_second_chip) |
||
690 | i *= 2; |
||
691 | @@ -1070,6 +1145,51 @@ static int fsl_qspi_probe(struct platfor |
||
692 | /* set the chip address for READID */ |
||
693 | fsl_qspi_set_base_addr(q, nor); |
||
694 | |||
695 | + /* |
||
696 | + * If spi-rx-bus-width and spi-tx-bus-width not defined assign |
||
697 | + * default hardware capabilities SNOR_HWCAPS_READ_1_1_4 and |
||
698 | + * SNOR_HWCAPS_PP supported by the Quad-SPI controller. |
||
699 | + */ |
||
700 | + if (!of_property_read_u32(np, "spi-rx-bus-width", &value)) { |
||
701 | + switch (value) { |
||
702 | + case 1: |
||
703 | + hwcaps.mask |= SNOR_HWCAPS_READ | |
||
704 | + SNOR_HWCAPS_READ_FAST; |
||
705 | + break; |
||
706 | + case 2: |
||
707 | + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2 | |
||
708 | + SNOR_HWCAPS_READ_1_2_2; |
||
709 | + break; |
||
710 | + case 4: |
||
711 | + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4 | |
||
712 | + SNOR_HWCAPS_READ_1_4_4; |
||
713 | + break; |
||
714 | + default: |
||
715 | + dev_err(dev, |
||
716 | + "spi-rx-bus-width %d not supported\n", |
||
717 | + value); |
||
718 | + break; |
||
719 | + } |
||
720 | + } else |
||
721 | + hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; |
||
722 | + |
||
723 | + if (!of_property_read_u32(np, "spi-tx-bus-width", &value)) { |
||
724 | + switch (value) { |
||
725 | + case 1: |
||
726 | + hwcaps.mask |= SNOR_HWCAPS_PP; |
||
727 | + break; |
||
728 | + case 4: |
||
729 | + hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4 | |
||
730 | + SNOR_HWCAPS_PP_1_4_4; |
||
731 | + break; |
||
732 | + default: |
||
733 | + dev_err(dev, |
||
734 | + "spi-tx-bus-width %d not supported\n", |
||
735 | + value); |
||
736 | + break; |
||
737 | + } |
||
738 | + } |
||
739 | + |
||
740 | ret = spi_nor_scan(nor, NULL, &hwcaps); |
||
741 | if (ret) |
||
742 | goto mutex_failed; |
||
743 | @@ -1098,6 +1218,8 @@ static int fsl_qspi_probe(struct platfor |
||
744 | if (nor->page_size > q->devtype_data->txfifo) |
||
745 | nor->page_size = q->devtype_data->txfifo; |
||
746 | |||
747 | + /*required for memory mapped AHB read*/ |
||
748 | + fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ, nor->read_opcode); |
||
749 | i++; |
||
750 | } |
||
751 | |||
752 | @@ -1106,6 +1228,8 @@ static int fsl_qspi_probe(struct platfor |
||
753 | if (ret) |
||
754 | goto last_init_failed; |
||
755 | |||
756 | + |
||
757 | + |
||
758 | fsl_qspi_clk_disable_unprep(q); |
||
759 | return 0; |
||
760 | |||
761 | --- a/drivers/mtd/spi-nor/spi-nor.c |
||
762 | +++ b/drivers/mtd/spi-nor/spi-nor.c |
||
763 | @@ -1147,6 +1147,11 @@ static const struct flash_info spi_nor_i |
||
764 | { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, |
||
765 | { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, |
||
766 | { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, |
||
767 | + { |
||
768 | + "w25q16dw", INFO(0xef6015, 0, 64 * 1024, 32, |
||
769 | + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | |
||
770 | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) |
||
771 | + }, |
||
772 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, |
||
773 | { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, |
||
774 | { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, |