1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Hisilicon NAND Flash controller driver |
4 | * |
5 | * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd. |
6 | * http://www.hisilicon.com |
7 | * |
8 | * Author: Zhou Wang <wangzhou.bry@gmail.com> |
9 | * The initial developer of the original code is Zhiyong Cai |
10 | * <caizhiyong@huawei.com> |
11 | */ |
12 | #include <linux/of.h> |
13 | #include <linux/mtd/mtd.h> |
14 | #include <linux/sizes.h> |
15 | #include <linux/clk.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/module.h> |
18 | #include <linux/delay.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/mtd/rawnand.h> |
21 | #include <linux/dma-mapping.h> |
22 | #include <linux/platform_device.h> |
23 | #include <linux/mtd/partitions.h> |
24 | |
25 | #define HINFC504_MAX_CHIP (4) |
26 | #define HINFC504_W_LATCH (5) |
27 | #define HINFC504_R_LATCH (7) |
28 | #define HINFC504_RW_LATCH (3) |
29 | |
30 | #define HINFC504_NFC_TIMEOUT (2 * HZ) |
31 | #define HINFC504_NFC_PM_TIMEOUT (1 * HZ) |
32 | #define HINFC504_NFC_DMA_TIMEOUT (5 * HZ) |
33 | #define HINFC504_CHIP_DELAY (25) |
34 | |
35 | #define HINFC504_REG_BASE_ADDRESS_LEN (0x100) |
36 | #define HINFC504_BUFFER_BASE_ADDRESS_LEN (2048 + 128) |
37 | |
38 | #define HINFC504_ADDR_CYCLE_MASK 0x4 |
39 | |
40 | #define HINFC504_CON 0x00 |
41 | #define HINFC504_CON_OP_MODE_NORMAL BIT(0) |
42 | #define HINFC504_CON_PAGEISZE_SHIFT (1) |
43 | #define HINFC504_CON_PAGESIZE_MASK (0x07) |
44 | #define HINFC504_CON_BUS_WIDTH BIT(4) |
45 | #define HINFC504_CON_READY_BUSY_SEL BIT(8) |
46 | #define HINFC504_CON_ECCTYPE_SHIFT (9) |
47 | #define HINFC504_CON_ECCTYPE_MASK (0x07) |
48 | |
49 | #define HINFC504_PWIDTH 0x04 |
50 | #define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \ |
51 | ((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8)) |
52 | |
53 | #define HINFC504_CMD 0x0C |
54 | #define HINFC504_ADDRL 0x10 |
55 | #define HINFC504_ADDRH 0x14 |
56 | #define HINFC504_DATA_NUM 0x18 |
57 | |
58 | #define HINFC504_OP 0x1C |
59 | #define HINFC504_OP_READ_DATA_EN BIT(1) |
60 | #define HINFC504_OP_WAIT_READY_EN BIT(2) |
61 | #define HINFC504_OP_CMD2_EN BIT(3) |
62 | #define HINFC504_OP_WRITE_DATA_EN BIT(4) |
63 | #define HINFC504_OP_ADDR_EN BIT(5) |
64 | #define HINFC504_OP_CMD1_EN BIT(6) |
65 | #define HINFC504_OP_NF_CS_SHIFT (7) |
66 | #define HINFC504_OP_NF_CS_MASK (3) |
67 | #define HINFC504_OP_ADDR_CYCLE_SHIFT (9) |
68 | #define HINFC504_OP_ADDR_CYCLE_MASK (7) |
69 | |
70 | #define HINFC504_STATUS 0x20 |
71 | #define HINFC504_READY BIT(0) |
72 | |
73 | #define HINFC504_INTEN 0x24 |
74 | #define HINFC504_INTEN_DMA BIT(9) |
75 | #define HINFC504_INTEN_UE BIT(6) |
76 | #define HINFC504_INTEN_CE BIT(5) |
77 | |
78 | #define HINFC504_INTS 0x28 |
79 | #define HINFC504_INTS_DMA BIT(9) |
80 | #define HINFC504_INTS_UE BIT(6) |
81 | #define HINFC504_INTS_CE BIT(5) |
82 | |
83 | #define HINFC504_INTCLR 0x2C |
84 | #define HINFC504_INTCLR_DMA BIT(9) |
85 | #define HINFC504_INTCLR_UE BIT(6) |
86 | #define HINFC504_INTCLR_CE BIT(5) |
87 | |
88 | #define HINFC504_ECC_STATUS 0x5C |
89 | #define HINFC504_ECC_16_BIT_SHIFT 12 |
90 | |
91 | #define HINFC504_DMA_CTRL 0x60 |
92 | #define HINFC504_DMA_CTRL_DMA_START BIT(0) |
93 | #define HINFC504_DMA_CTRL_WE BIT(1) |
94 | #define HINFC504_DMA_CTRL_DATA_AREA_EN BIT(2) |
95 | #define HINFC504_DMA_CTRL_OOB_AREA_EN BIT(3) |
96 | #define HINFC504_DMA_CTRL_BURST4_EN BIT(4) |
97 | #define HINFC504_DMA_CTRL_BURST8_EN BIT(5) |
98 | #define HINFC504_DMA_CTRL_BURST16_EN BIT(6) |
99 | #define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT (7) |
100 | #define HINFC504_DMA_CTRL_ADDR_NUM_MASK (1) |
101 | #define HINFC504_DMA_CTRL_CS_SHIFT (8) |
102 | #define HINFC504_DMA_CTRL_CS_MASK (0x03) |
103 | |
104 | #define HINFC504_DMA_ADDR_DATA 0x64 |
105 | #define HINFC504_DMA_ADDR_OOB 0x68 |
106 | |
107 | #define HINFC504_DMA_LEN 0x6C |
108 | #define HINFC504_DMA_LEN_OOB_SHIFT (16) |
109 | #define HINFC504_DMA_LEN_OOB_MASK (0xFFF) |
110 | |
111 | #define HINFC504_DMA_PARA 0x70 |
112 | #define HINFC504_DMA_PARA_DATA_RW_EN BIT(0) |
113 | #define HINFC504_DMA_PARA_OOB_RW_EN BIT(1) |
114 | #define HINFC504_DMA_PARA_DATA_EDC_EN BIT(2) |
115 | #define HINFC504_DMA_PARA_OOB_EDC_EN BIT(3) |
116 | #define HINFC504_DMA_PARA_DATA_ECC_EN BIT(4) |
117 | #define HINFC504_DMA_PARA_OOB_ECC_EN BIT(5) |
118 | |
119 | #define HINFC_VERSION 0x74 |
120 | #define HINFC504_LOG_READ_ADDR 0x7C |
121 | #define HINFC504_LOG_READ_LEN 0x80 |
122 | |
123 | #define HINFC504_NANDINFO_LEN 0x10 |
124 | |
125 | struct hinfc_host { |
126 | struct nand_chip chip; |
127 | struct device *dev; |
128 | void __iomem *iobase; |
129 | void __iomem *mmio; |
130 | struct completion cmd_complete; |
131 | unsigned int offset; |
132 | unsigned int command; |
133 | int chipselect; |
134 | unsigned int addr_cycle; |
135 | u32 addr_value[2]; |
136 | u32 cache_addr_value[2]; |
137 | char *buffer; |
138 | dma_addr_t dma_buffer; |
139 | dma_addr_t dma_oob; |
140 | int version; |
141 | unsigned int irq_status; /* interrupt status */ |
142 | }; |
143 | |
144 | static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg) |
145 | { |
146 | return readl(addr: host->iobase + reg); |
147 | } |
148 | |
149 | static inline void hinfc_write(struct hinfc_host *host, unsigned int value, |
150 | unsigned int reg) |
151 | { |
152 | writel(val: value, addr: host->iobase + reg); |
153 | } |
154 | |
155 | static void wait_controller_finished(struct hinfc_host *host) |
156 | { |
157 | unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT; |
158 | int val; |
159 | |
160 | while (time_before(jiffies, timeout)) { |
161 | val = hinfc_read(host, HINFC504_STATUS); |
162 | if (host->command == NAND_CMD_ERASE2) { |
163 | /* nfc is ready */ |
164 | while (!(val & HINFC504_READY)) { |
165 | usleep_range(min: 500, max: 1000); |
166 | val = hinfc_read(host, HINFC504_STATUS); |
167 | } |
168 | return; |
169 | } |
170 | |
171 | if (val & HINFC504_READY) |
172 | return; |
173 | } |
174 | |
175 | /* wait cmd timeout */ |
176 | dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n" ); |
177 | } |
178 | |
179 | static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev) |
180 | { |
181 | struct nand_chip *chip = &host->chip; |
182 | struct mtd_info *mtd = nand_to_mtd(chip); |
183 | unsigned long val; |
184 | int ret; |
185 | |
186 | hinfc_write(host, value: host->dma_buffer, HINFC504_DMA_ADDR_DATA); |
187 | hinfc_write(host, value: host->dma_oob, HINFC504_DMA_ADDR_OOB); |
188 | |
189 | if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_NONE) { |
190 | hinfc_write(host, value: ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK) |
191 | << HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN); |
192 | |
193 | hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN |
194 | | HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA); |
195 | } else { |
196 | if (host->command == NAND_CMD_READOOB) |
197 | hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN |
198 | | HINFC504_DMA_PARA_OOB_EDC_EN |
199 | | HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA); |
200 | else |
201 | hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN |
202 | | HINFC504_DMA_PARA_OOB_RW_EN |
203 | | HINFC504_DMA_PARA_DATA_EDC_EN |
204 | | HINFC504_DMA_PARA_OOB_EDC_EN |
205 | | HINFC504_DMA_PARA_DATA_ECC_EN |
206 | | HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA); |
207 | |
208 | } |
209 | |
210 | val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN |
211 | | HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN |
212 | | HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN |
213 | | ((host->addr_cycle == 4 ? 1 : 0) |
214 | << HINFC504_DMA_CTRL_ADDR_NUM_SHIFT) |
215 | | ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK) |
216 | << HINFC504_DMA_CTRL_CS_SHIFT)); |
217 | |
218 | if (todev) |
219 | val |= HINFC504_DMA_CTRL_WE; |
220 | |
221 | init_completion(x: &host->cmd_complete); |
222 | |
223 | hinfc_write(host, value: val, HINFC504_DMA_CTRL); |
224 | ret = wait_for_completion_timeout(x: &host->cmd_complete, |
225 | HINFC504_NFC_DMA_TIMEOUT); |
226 | |
227 | if (!ret) { |
228 | dev_err(host->dev, "DMA operation(irq) timeout!\n" ); |
229 | /* sanity check */ |
230 | val = hinfc_read(host, HINFC504_DMA_CTRL); |
231 | if (!(val & HINFC504_DMA_CTRL_DMA_START)) |
232 | dev_err(host->dev, "DMA is already done but without irq ACK!\n" ); |
233 | else |
234 | dev_err(host->dev, "DMA is really timeout!\n" ); |
235 | } |
236 | } |
237 | |
238 | static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host) |
239 | { |
240 | host->addr_value[0] &= 0xffff0000; |
241 | |
242 | hinfc_write(host, value: host->addr_value[0], HINFC504_ADDRL); |
243 | hinfc_write(host, value: host->addr_value[1], HINFC504_ADDRH); |
244 | hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN, |
245 | HINFC504_CMD); |
246 | |
247 | hisi_nfc_dma_transfer(host, todev: 1); |
248 | |
249 | return 0; |
250 | } |
251 | |
252 | static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host) |
253 | { |
254 | struct mtd_info *mtd = nand_to_mtd(chip: &host->chip); |
255 | |
256 | if ((host->addr_value[0] == host->cache_addr_value[0]) && |
257 | (host->addr_value[1] == host->cache_addr_value[1])) |
258 | return 0; |
259 | |
260 | host->addr_value[0] &= 0xffff0000; |
261 | |
262 | hinfc_write(host, value: host->addr_value[0], HINFC504_ADDRL); |
263 | hinfc_write(host, value: host->addr_value[1], HINFC504_ADDRH); |
264 | hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0, |
265 | HINFC504_CMD); |
266 | |
267 | hinfc_write(host, value: 0, HINFC504_LOG_READ_ADDR); |
268 | hinfc_write(host, value: mtd->writesize + mtd->oobsize, |
269 | HINFC504_LOG_READ_LEN); |
270 | |
271 | hisi_nfc_dma_transfer(host, todev: 0); |
272 | |
273 | host->cache_addr_value[0] = host->addr_value[0]; |
274 | host->cache_addr_value[1] = host->addr_value[1]; |
275 | |
276 | return 0; |
277 | } |
278 | |
279 | static int hisi_nfc_send_cmd_erase(struct hinfc_host *host) |
280 | { |
281 | hinfc_write(host, value: host->addr_value[0], HINFC504_ADDRL); |
282 | hinfc_write(host, value: (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1, |
283 | HINFC504_CMD); |
284 | |
285 | hinfc_write(host, HINFC504_OP_WAIT_READY_EN |
286 | | HINFC504_OP_CMD2_EN |
287 | | HINFC504_OP_CMD1_EN |
288 | | HINFC504_OP_ADDR_EN |
289 | | ((host->chipselect & HINFC504_OP_NF_CS_MASK) |
290 | << HINFC504_OP_NF_CS_SHIFT) |
291 | | ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK) |
292 | << HINFC504_OP_ADDR_CYCLE_SHIFT), |
293 | HINFC504_OP); |
294 | |
295 | wait_controller_finished(host); |
296 | |
297 | return 0; |
298 | } |
299 | |
300 | static int hisi_nfc_send_cmd_readid(struct hinfc_host *host) |
301 | { |
302 | hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM); |
303 | hinfc_write(host, NAND_CMD_READID, HINFC504_CMD); |
304 | hinfc_write(host, value: 0, HINFC504_ADDRL); |
305 | |
306 | hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN |
307 | | HINFC504_OP_READ_DATA_EN |
308 | | ((host->chipselect & HINFC504_OP_NF_CS_MASK) |
309 | << HINFC504_OP_NF_CS_SHIFT) |
310 | | 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP); |
311 | |
312 | wait_controller_finished(host); |
313 | |
314 | return 0; |
315 | } |
316 | |
317 | static int hisi_nfc_send_cmd_status(struct hinfc_host *host) |
318 | { |
319 | hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM); |
320 | hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD); |
321 | hinfc_write(host, HINFC504_OP_CMD1_EN |
322 | | HINFC504_OP_READ_DATA_EN |
323 | | ((host->chipselect & HINFC504_OP_NF_CS_MASK) |
324 | << HINFC504_OP_NF_CS_SHIFT), |
325 | HINFC504_OP); |
326 | |
327 | wait_controller_finished(host); |
328 | |
329 | return 0; |
330 | } |
331 | |
332 | static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect) |
333 | { |
334 | hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD); |
335 | |
336 | hinfc_write(host, HINFC504_OP_CMD1_EN |
337 | | ((chipselect & HINFC504_OP_NF_CS_MASK) |
338 | << HINFC504_OP_NF_CS_SHIFT) |
339 | | HINFC504_OP_WAIT_READY_EN, |
340 | HINFC504_OP); |
341 | |
342 | wait_controller_finished(host); |
343 | |
344 | return 0; |
345 | } |
346 | |
347 | static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect) |
348 | { |
349 | struct hinfc_host *host = nand_get_controller_data(chip); |
350 | |
351 | if (chipselect < 0) |
352 | return; |
353 | |
354 | host->chipselect = chipselect; |
355 | } |
356 | |
357 | static uint8_t hisi_nfc_read_byte(struct nand_chip *chip) |
358 | { |
359 | struct hinfc_host *host = nand_get_controller_data(chip); |
360 | |
361 | if (host->command == NAND_CMD_STATUS) |
362 | return *(uint8_t *)(host->mmio); |
363 | |
364 | host->offset++; |
365 | |
366 | if (host->command == NAND_CMD_READID) |
367 | return *(uint8_t *)(host->mmio + host->offset - 1); |
368 | |
369 | return *(uint8_t *)(host->buffer + host->offset - 1); |
370 | } |
371 | |
372 | static void |
373 | hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) |
374 | { |
375 | struct hinfc_host *host = nand_get_controller_data(chip); |
376 | |
377 | memcpy(host->buffer + host->offset, buf, len); |
378 | host->offset += len; |
379 | } |
380 | |
381 | static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) |
382 | { |
383 | struct hinfc_host *host = nand_get_controller_data(chip); |
384 | |
385 | memcpy(buf, host->buffer + host->offset, len); |
386 | host->offset += len; |
387 | } |
388 | |
389 | static void set_addr(struct mtd_info *mtd, int column, int page_addr) |
390 | { |
391 | struct nand_chip *chip = mtd_to_nand(mtd); |
392 | struct hinfc_host *host = nand_get_controller_data(chip); |
393 | unsigned int command = host->command; |
394 | |
395 | host->addr_cycle = 0; |
396 | host->addr_value[0] = 0; |
397 | host->addr_value[1] = 0; |
398 | |
399 | /* Serially input address */ |
400 | if (column != -1) { |
401 | /* Adjust columns for 16 bit buswidth */ |
402 | if (chip->options & NAND_BUSWIDTH_16 && |
403 | !nand_opcode_8bits(command)) |
404 | column >>= 1; |
405 | |
406 | host->addr_value[0] = column & 0xffff; |
407 | host->addr_cycle = 2; |
408 | } |
409 | if (page_addr != -1) { |
410 | host->addr_value[0] |= (page_addr & 0xffff) |
411 | << (host->addr_cycle * 8); |
412 | host->addr_cycle += 2; |
413 | if (chip->options & NAND_ROW_ADDR_3) { |
414 | host->addr_cycle += 1; |
415 | if (host->command == NAND_CMD_ERASE1) |
416 | host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16; |
417 | else |
418 | host->addr_value[1] |= ((page_addr >> 16) & 0xff); |
419 | } |
420 | } |
421 | } |
422 | |
423 | static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command, |
424 | int column, int page_addr) |
425 | { |
426 | struct mtd_info *mtd = nand_to_mtd(chip); |
427 | struct hinfc_host *host = nand_get_controller_data(chip); |
428 | int is_cache_invalid = 1; |
429 | unsigned int flag = 0; |
430 | |
431 | host->command = command; |
432 | |
433 | switch (command) { |
434 | case NAND_CMD_READ0: |
435 | case NAND_CMD_READOOB: |
436 | if (command == NAND_CMD_READ0) |
437 | host->offset = column; |
438 | else |
439 | host->offset = column + mtd->writesize; |
440 | |
441 | is_cache_invalid = 0; |
442 | set_addr(mtd, column, page_addr); |
443 | hisi_nfc_send_cmd_readstart(host); |
444 | break; |
445 | |
446 | case NAND_CMD_SEQIN: |
447 | host->offset = column; |
448 | set_addr(mtd, column, page_addr); |
449 | break; |
450 | |
451 | case NAND_CMD_ERASE1: |
452 | set_addr(mtd, column, page_addr); |
453 | break; |
454 | |
455 | case NAND_CMD_PAGEPROG: |
456 | hisi_nfc_send_cmd_pageprog(host); |
457 | break; |
458 | |
459 | case NAND_CMD_ERASE2: |
460 | hisi_nfc_send_cmd_erase(host); |
461 | break; |
462 | |
463 | case NAND_CMD_READID: |
464 | host->offset = column; |
465 | memset(host->mmio, 0, 0x10); |
466 | hisi_nfc_send_cmd_readid(host); |
467 | break; |
468 | |
469 | case NAND_CMD_STATUS: |
470 | flag = hinfc_read(host, HINFC504_CON); |
471 | if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) |
472 | hinfc_write(host, |
473 | value: flag & ~(HINFC504_CON_ECCTYPE_MASK << |
474 | HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON); |
475 | |
476 | host->offset = 0; |
477 | memset(host->mmio, 0, 0x10); |
478 | hisi_nfc_send_cmd_status(host); |
479 | hinfc_write(host, value: flag, HINFC504_CON); |
480 | break; |
481 | |
482 | case NAND_CMD_RESET: |
483 | hisi_nfc_send_cmd_reset(host, chipselect: host->chipselect); |
484 | break; |
485 | |
486 | default: |
487 | dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n" , |
488 | command, column, page_addr); |
489 | } |
490 | |
491 | if (is_cache_invalid) { |
492 | host->cache_addr_value[0] = ~0; |
493 | host->cache_addr_value[1] = ~0; |
494 | } |
495 | } |
496 | |
497 | static irqreturn_t hinfc_irq_handle(int irq, void *devid) |
498 | { |
499 | struct hinfc_host *host = devid; |
500 | unsigned int flag; |
501 | |
502 | flag = hinfc_read(host, HINFC504_INTS); |
503 | /* store interrupts state */ |
504 | host->irq_status |= flag; |
505 | |
506 | if (flag & HINFC504_INTS_DMA) { |
507 | hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR); |
508 | complete(&host->cmd_complete); |
509 | } else if (flag & HINFC504_INTS_CE) { |
510 | hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR); |
511 | } else if (flag & HINFC504_INTS_UE) { |
512 | hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR); |
513 | } |
514 | |
515 | return IRQ_HANDLED; |
516 | } |
517 | |
518 | static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, |
519 | int oob_required, int page) |
520 | { |
521 | struct mtd_info *mtd = nand_to_mtd(chip); |
522 | struct hinfc_host *host = nand_get_controller_data(chip); |
523 | int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc; |
524 | int stat_1, stat_2; |
525 | |
526 | nand_read_page_op(chip, page, offset_in_page: 0, buf, len: mtd->writesize); |
527 | chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); |
528 | |
529 | /* errors which can not be corrected by ECC */ |
530 | if (host->irq_status & HINFC504_INTS_UE) { |
531 | mtd->ecc_stats.failed++; |
532 | } else if (host->irq_status & HINFC504_INTS_CE) { |
533 | /* TODO: need add other ECC modes! */ |
534 | switch (chip->ecc.strength) { |
535 | case 16: |
536 | status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >> |
537 | HINFC504_ECC_16_BIT_SHIFT & 0x0fff; |
538 | stat_2 = status_ecc & 0x3f; |
539 | stat_1 = status_ecc >> 6 & 0x3f; |
540 | stat = stat_1 + stat_2; |
541 | stat_max = max_t(int, stat_1, stat_2); |
542 | } |
543 | mtd->ecc_stats.corrected += stat; |
544 | max_bitflips = max_t(int, max_bitflips, stat_max); |
545 | } |
546 | host->irq_status = 0; |
547 | |
548 | return max_bitflips; |
549 | } |
550 | |
551 | static int hisi_nand_read_oob(struct nand_chip *chip, int page) |
552 | { |
553 | struct mtd_info *mtd = nand_to_mtd(chip); |
554 | struct hinfc_host *host = nand_get_controller_data(chip); |
555 | |
556 | nand_read_oob_op(chip, page, offset_in_page: 0, buf: chip->oob_poi, len: mtd->oobsize); |
557 | |
558 | if (host->irq_status & HINFC504_INTS_UE) { |
559 | host->irq_status = 0; |
560 | return -EBADMSG; |
561 | } |
562 | |
563 | host->irq_status = 0; |
564 | return 0; |
565 | } |
566 | |
567 | static int hisi_nand_write_page_hwecc(struct nand_chip *chip, |
568 | const uint8_t *buf, int oob_required, |
569 | int page) |
570 | { |
571 | struct mtd_info *mtd = nand_to_mtd(chip); |
572 | |
573 | nand_prog_page_begin_op(chip, page, offset_in_page: 0, buf, len: mtd->writesize); |
574 | if (oob_required) |
575 | chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); |
576 | |
577 | return nand_prog_page_end_op(chip); |
578 | } |
579 | |
580 | static void hisi_nfc_host_init(struct hinfc_host *host) |
581 | { |
582 | struct nand_chip *chip = &host->chip; |
583 | unsigned int flag = 0; |
584 | |
585 | host->version = hinfc_read(host, HINFC_VERSION); |
586 | host->addr_cycle = 0; |
587 | host->addr_value[0] = 0; |
588 | host->addr_value[1] = 0; |
589 | host->cache_addr_value[0] = ~0; |
590 | host->cache_addr_value[1] = ~0; |
591 | host->chipselect = 0; |
592 | |
593 | /* default page size: 2K, ecc_none. need modify */ |
594 | flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL |
595 | | ((0x001 & HINFC504_CON_PAGESIZE_MASK) |
596 | << HINFC504_CON_PAGEISZE_SHIFT) |
597 | | ((0x0 & HINFC504_CON_ECCTYPE_MASK) |
598 | << HINFC504_CON_ECCTYPE_SHIFT) |
599 | | ((chip->options & NAND_BUSWIDTH_16) ? |
600 | HINFC504_CON_BUS_WIDTH : 0); |
601 | hinfc_write(host, value: flag, HINFC504_CON); |
602 | |
603 | memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN); |
604 | |
605 | hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH, |
606 | HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH); |
607 | |
608 | /* enable DMA irq */ |
609 | hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN); |
610 | } |
611 | |
612 | static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section, |
613 | struct mtd_oob_region *oobregion) |
614 | { |
615 | /* FIXME: add ECC bytes position */ |
616 | return -ENOTSUPP; |
617 | } |
618 | |
619 | static int hisi_ooblayout_free(struct mtd_info *mtd, int section, |
620 | struct mtd_oob_region *oobregion) |
621 | { |
622 | if (section) |
623 | return -ERANGE; |
624 | |
625 | oobregion->offset = 2; |
626 | oobregion->length = 6; |
627 | |
628 | return 0; |
629 | } |
630 | |
631 | static const struct mtd_ooblayout_ops hisi_ooblayout_ops = { |
632 | .ecc = hisi_ooblayout_ecc, |
633 | .free = hisi_ooblayout_free, |
634 | }; |
635 | |
636 | static int hisi_nfc_ecc_probe(struct hinfc_host *host) |
637 | { |
638 | unsigned int flag; |
639 | int size, strength, ecc_bits; |
640 | struct device *dev = host->dev; |
641 | struct nand_chip *chip = &host->chip; |
642 | struct mtd_info *mtd = nand_to_mtd(chip); |
643 | |
644 | size = chip->ecc.size; |
645 | strength = chip->ecc.strength; |
646 | if (size != 1024) { |
647 | dev_err(dev, "error ecc size: %d\n" , size); |
648 | return -EINVAL; |
649 | } |
650 | |
651 | if ((size == 1024) && ((strength != 8) && (strength != 16) && |
652 | (strength != 24) && (strength != 40))) { |
653 | dev_err(dev, "ecc size and strength do not match\n" ); |
654 | return -EINVAL; |
655 | } |
656 | |
657 | chip->ecc.size = size; |
658 | chip->ecc.strength = strength; |
659 | |
660 | chip->ecc.read_page = hisi_nand_read_page_hwecc; |
661 | chip->ecc.read_oob = hisi_nand_read_oob; |
662 | chip->ecc.write_page = hisi_nand_write_page_hwecc; |
663 | |
664 | switch (chip->ecc.strength) { |
665 | case 16: |
666 | ecc_bits = 6; |
667 | if (mtd->writesize == 2048) |
668 | mtd_set_ooblayout(mtd, ooblayout: &hisi_ooblayout_ops); |
669 | |
670 | /* TODO: add more page size support */ |
671 | break; |
672 | |
673 | /* TODO: add more ecc strength support */ |
674 | default: |
675 | dev_err(dev, "not support strength: %d\n" , chip->ecc.strength); |
676 | return -EINVAL; |
677 | } |
678 | |
679 | flag = hinfc_read(host, HINFC504_CON); |
680 | /* add ecc type configure */ |
681 | flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK) |
682 | << HINFC504_CON_ECCTYPE_SHIFT); |
683 | hinfc_write(host, value: flag, HINFC504_CON); |
684 | |
685 | /* enable ecc irq */ |
686 | flag = hinfc_read(host, HINFC504_INTEN) & 0xfff; |
687 | hinfc_write(host, value: flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE, |
688 | HINFC504_INTEN); |
689 | |
690 | return 0; |
691 | } |
692 | |
693 | static int hisi_nfc_attach_chip(struct nand_chip *chip) |
694 | { |
695 | struct mtd_info *mtd = nand_to_mtd(chip); |
696 | struct hinfc_host *host = nand_get_controller_data(chip); |
697 | int flag; |
698 | |
699 | host->buffer = dmam_alloc_coherent(dev: host->dev, |
700 | size: mtd->writesize + mtd->oobsize, |
701 | dma_handle: &host->dma_buffer, GFP_KERNEL); |
702 | if (!host->buffer) |
703 | return -ENOMEM; |
704 | |
705 | host->dma_oob = host->dma_buffer + mtd->writesize; |
706 | memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize); |
707 | |
708 | flag = hinfc_read(host, HINFC504_CON); |
709 | flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT); |
710 | switch (mtd->writesize) { |
711 | case 2048: |
712 | flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); |
713 | break; |
714 | /* |
715 | * TODO: add more pagesize support, |
716 | * default pagesize has been set in hisi_nfc_host_init |
717 | */ |
718 | default: |
719 | dev_err(host->dev, "NON-2KB page size nand flash\n" ); |
720 | return -EINVAL; |
721 | } |
722 | hinfc_write(host, value: flag, HINFC504_CON); |
723 | |
724 | if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) |
725 | hisi_nfc_ecc_probe(host); |
726 | |
727 | return 0; |
728 | } |
729 | |
730 | static const struct nand_controller_ops hisi_nfc_controller_ops = { |
731 | .attach_chip = hisi_nfc_attach_chip, |
732 | }; |
733 | |
734 | static int hisi_nfc_probe(struct platform_device *pdev) |
735 | { |
736 | int ret = 0, irq, max_chips = HINFC504_MAX_CHIP; |
737 | struct device *dev = &pdev->dev; |
738 | struct hinfc_host *host; |
739 | struct nand_chip *chip; |
740 | struct mtd_info *mtd; |
741 | struct device_node *np = dev->of_node; |
742 | |
743 | host = devm_kzalloc(dev, size: sizeof(*host), GFP_KERNEL); |
744 | if (!host) |
745 | return -ENOMEM; |
746 | host->dev = dev; |
747 | |
748 | platform_set_drvdata(pdev, data: host); |
749 | chip = &host->chip; |
750 | mtd = nand_to_mtd(chip); |
751 | |
752 | irq = platform_get_irq(pdev, 0); |
753 | if (irq < 0) |
754 | return -ENXIO; |
755 | |
756 | host->iobase = devm_platform_ioremap_resource(pdev, index: 0); |
757 | if (IS_ERR(ptr: host->iobase)) |
758 | return PTR_ERR(ptr: host->iobase); |
759 | |
760 | host->mmio = devm_platform_ioremap_resource(pdev, index: 1); |
761 | if (IS_ERR(ptr: host->mmio)) |
762 | return PTR_ERR(ptr: host->mmio); |
763 | |
764 | mtd->name = "hisi_nand" ; |
765 | mtd->dev.parent = &pdev->dev; |
766 | |
767 | nand_set_controller_data(chip, priv: host); |
768 | nand_set_flash_node(chip, np); |
769 | chip->legacy.cmdfunc = hisi_nfc_cmdfunc; |
770 | chip->legacy.select_chip = hisi_nfc_select_chip; |
771 | chip->legacy.read_byte = hisi_nfc_read_byte; |
772 | chip->legacy.write_buf = hisi_nfc_write_buf; |
773 | chip->legacy.read_buf = hisi_nfc_read_buf; |
774 | chip->legacy.chip_delay = HINFC504_CHIP_DELAY; |
775 | chip->legacy.set_features = nand_get_set_features_notsupp; |
776 | chip->legacy.get_features = nand_get_set_features_notsupp; |
777 | |
778 | hisi_nfc_host_init(host); |
779 | |
780 | ret = devm_request_irq(dev, irq, handler: hinfc_irq_handle, irqflags: 0x0, devname: "nandc" , dev_id: host); |
781 | if (ret) { |
782 | dev_err(dev, "failed to request IRQ\n" ); |
783 | return ret; |
784 | } |
785 | |
786 | chip->legacy.dummy_controller.ops = &hisi_nfc_controller_ops; |
787 | ret = nand_scan(chip, max_chips); |
788 | if (ret) |
789 | return ret; |
790 | |
791 | ret = mtd_device_register(mtd, NULL, 0); |
792 | if (ret) { |
793 | dev_err(dev, "Err MTD partition=%d\n" , ret); |
794 | nand_cleanup(chip); |
795 | return ret; |
796 | } |
797 | |
798 | return 0; |
799 | } |
800 | |
801 | static void hisi_nfc_remove(struct platform_device *pdev) |
802 | { |
803 | struct hinfc_host *host = platform_get_drvdata(pdev); |
804 | struct nand_chip *chip = &host->chip; |
805 | int ret; |
806 | |
807 | ret = mtd_device_unregister(master: nand_to_mtd(chip)); |
808 | WARN_ON(ret); |
809 | nand_cleanup(chip); |
810 | } |
811 | |
812 | #ifdef CONFIG_PM_SLEEP |
813 | static int hisi_nfc_suspend(struct device *dev) |
814 | { |
815 | struct hinfc_host *host = dev_get_drvdata(dev); |
816 | unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT; |
817 | |
818 | while (time_before(jiffies, timeout)) { |
819 | if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) && |
820 | (hinfc_read(host, HINFC504_DMA_CTRL) & |
821 | HINFC504_DMA_CTRL_DMA_START)) { |
822 | cond_resched(); |
823 | return 0; |
824 | } |
825 | } |
826 | |
827 | dev_err(host->dev, "nand controller suspend timeout.\n" ); |
828 | |
829 | return -EAGAIN; |
830 | } |
831 | |
832 | static int hisi_nfc_resume(struct device *dev) |
833 | { |
834 | int cs; |
835 | struct hinfc_host *host = dev_get_drvdata(dev); |
836 | struct nand_chip *chip = &host->chip; |
837 | |
838 | for (cs = 0; cs < nanddev_ntargets(nand: &chip->base); cs++) |
839 | hisi_nfc_send_cmd_reset(host, chipselect: cs); |
840 | hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH, |
841 | HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH); |
842 | |
843 | return 0; |
844 | } |
845 | #endif |
846 | static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume); |
847 | |
848 | static const struct of_device_id nfc_id_table[] = { |
849 | { .compatible = "hisilicon,504-nfc" }, |
850 | {} |
851 | }; |
852 | MODULE_DEVICE_TABLE(of, nfc_id_table); |
853 | |
854 | static struct platform_driver hisi_nfc_driver = { |
855 | .driver = { |
856 | .name = "hisi_nand" , |
857 | .of_match_table = nfc_id_table, |
858 | .pm = &hisi_nfc_pm_ops, |
859 | }, |
860 | .probe = hisi_nfc_probe, |
861 | .remove_new = hisi_nfc_remove, |
862 | }; |
863 | |
864 | module_platform_driver(hisi_nfc_driver); |
865 | |
866 | MODULE_LICENSE("GPL" ); |
867 | MODULE_AUTHOR("Zhou Wang" ); |
868 | MODULE_AUTHOR("Zhiyong Cai" ); |
869 | MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver" ); |
870 | |