blob: 2a0e624eca6ce4e18f04548ef6d9a2129b605757 [file] [log] [blame]
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001/*
2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
3 *
4 * Derived from:
5 * https://github.com/yuq/sunxi-nfc-mtd
6 * Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
7 *
8 * https://github.com/hno/Allwinner-Info
9 * Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
10 *
11 * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
12 * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 */
24
25#include <linux/dma-mapping.h>
26#include <linux/slab.h>
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/platform_device.h>
30#include <linux/of.h>
31#include <linux/of_device.h>
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020032#include <linux/mtd/mtd.h>
Boris Brezillond4092d72017-08-04 17:29:10 +020033#include <linux/mtd/rawnand.h>
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020034#include <linux/mtd/partitions.h>
35#include <linux/clk.h>
36#include <linux/delay.h>
37#include <linux/dmaengine.h>
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020038#include <linux/interrupt.h>
Boris Brezillon166f08c2016-03-07 15:25:17 +010039#include <linux/iopoll.h>
Icenowy Zhengab9d6a72016-06-20 12:48:38 +080040#include <linux/reset.h>
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020041
42#define NFC_REG_CTL 0x0000
43#define NFC_REG_ST 0x0004
44#define NFC_REG_INT 0x0008
45#define NFC_REG_TIMING_CTL 0x000C
46#define NFC_REG_TIMING_CFG 0x0010
47#define NFC_REG_ADDR_LOW 0x0014
48#define NFC_REG_ADDR_HIGH 0x0018
49#define NFC_REG_SECTOR_NUM 0x001C
50#define NFC_REG_CNT 0x0020
51#define NFC_REG_CMD 0x0024
52#define NFC_REG_RCMD_SET 0x0028
53#define NFC_REG_WCMD_SET 0x002C
54#define NFC_REG_IO_DATA 0x0030
55#define NFC_REG_ECC_CTL 0x0034
56#define NFC_REG_ECC_ST 0x0038
57#define NFC_REG_DEBUG 0x003C
Boris BREZILLONb6a02c02015-09-16 09:46:36 +020058#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
59#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4))
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020060#define NFC_REG_SPARE_AREA 0x00A0
Boris BREZILLON4be4e032015-12-02 12:01:07 +010061#define NFC_REG_PAT_ID 0x00A4
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020062#define NFC_RAM0_BASE 0x0400
63#define NFC_RAM1_BASE 0x0800
64
65/* define bit use in NFC_CTL */
66#define NFC_EN BIT(0)
67#define NFC_RESET BIT(1)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +020068#define NFC_BUS_WIDTH_MSK BIT(2)
69#define NFC_BUS_WIDTH_8 (0 << 2)
70#define NFC_BUS_WIDTH_16 (1 << 2)
71#define NFC_RB_SEL_MSK BIT(3)
72#define NFC_RB_SEL(x) ((x) << 3)
73#define NFC_CE_SEL_MSK GENMASK(26, 24)
74#define NFC_CE_SEL(x) ((x) << 24)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020075#define NFC_CE_CTL BIT(6)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +020076#define NFC_PAGE_SHIFT_MSK GENMASK(11, 8)
77#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020078#define NFC_SAM BIT(12)
79#define NFC_RAM_METHOD BIT(14)
80#define NFC_DEBUG_CTL BIT(31)
81
82/* define bit use in NFC_ST */
83#define NFC_RB_B2R BIT(0)
84#define NFC_CMD_INT_FLAG BIT(1)
85#define NFC_DMA_INT_FLAG BIT(2)
86#define NFC_CMD_FIFO_STATUS BIT(3)
87#define NFC_STA BIT(4)
88#define NFC_NATCH_INT_FLAG BIT(5)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +020089#define NFC_RB_STATE(x) BIT(x + 8)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +020090
91/* define bit use in NFC_INT */
92#define NFC_B2R_INT_ENABLE BIT(0)
93#define NFC_CMD_INT_ENABLE BIT(1)
94#define NFC_DMA_INT_ENABLE BIT(2)
95#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \
96 NFC_CMD_INT_ENABLE | \
97 NFC_DMA_INT_ENABLE)
98
Roy Splietd052e502015-06-26 11:00:11 +020099/* define bit use in NFC_TIMING_CTL */
100#define NFC_TIMING_CTL_EDO BIT(8)
101
Roy Spliet9c618292015-06-26 11:00:10 +0200102/* define NFC_TIMING_CFG register layout */
103#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \
104 (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \
105 (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \
106 (((tCAD) & 0x7) << 8))
107
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200108/* define bit use in NFC_CMD */
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200109#define NFC_CMD_LOW_BYTE_MSK GENMASK(7, 0)
110#define NFC_CMD_HIGH_BYTE_MSK GENMASK(15, 8)
111#define NFC_CMD(x) (x)
112#define NFC_ADR_NUM_MSK GENMASK(18, 16)
113#define NFC_ADR_NUM(x) (((x) - 1) << 16)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200114#define NFC_SEND_ADR BIT(19)
115#define NFC_ACCESS_DIR BIT(20)
116#define NFC_DATA_TRANS BIT(21)
117#define NFC_SEND_CMD1 BIT(22)
118#define NFC_WAIT_FLAG BIT(23)
119#define NFC_SEND_CMD2 BIT(24)
120#define NFC_SEQ BIT(25)
121#define NFC_DATA_SWAP_METHOD BIT(26)
122#define NFC_ROW_AUTO_INC BIT(27)
123#define NFC_SEND_CMD3 BIT(28)
124#define NFC_SEND_CMD4 BIT(29)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200125#define NFC_CMD_TYPE_MSK GENMASK(31, 30)
126#define NFC_NORMAL_OP (0 << 30)
127#define NFC_ECC_OP (1 << 30)
Boris Brezilloncf3e3fd2018-07-09 22:09:31 +0200128#define NFC_PAGE_OP (2U << 30)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200129
130/* define bit use in NFC_RCMD_SET */
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200131#define NFC_READ_CMD_MSK GENMASK(7, 0)
132#define NFC_RND_READ_CMD0_MSK GENMASK(15, 8)
133#define NFC_RND_READ_CMD1_MSK GENMASK(23, 16)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200134
135/* define bit use in NFC_WCMD_SET */
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200136#define NFC_PROGRAM_CMD_MSK GENMASK(7, 0)
137#define NFC_RND_WRITE_CMD_MSK GENMASK(15, 8)
138#define NFC_READ_CMD0_MSK GENMASK(23, 16)
139#define NFC_READ_CMD1_MSK GENMASK(31, 24)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200140
141/* define bit use in NFC_ECC_CTL */
142#define NFC_ECC_EN BIT(0)
143#define NFC_ECC_PIPELINE BIT(3)
144#define NFC_ECC_EXCEPTION BIT(4)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200145#define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
Boris Brezillonf59dab82016-10-20 10:12:42 +0200146#define NFC_ECC_BLOCK_512 BIT(5)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200147#define NFC_RANDOM_EN BIT(9)
148#define NFC_RANDOM_DIRECTION BIT(10)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200149#define NFC_ECC_MODE_MSK GENMASK(15, 12)
150#define NFC_ECC_MODE(x) ((x) << 12)
151#define NFC_RANDOM_SEED_MSK GENMASK(30, 16)
152#define NFC_RANDOM_SEED(x) ((x) << 16)
153
154/* define bit use in NFC_ECC_ST */
155#define NFC_ECC_ERR(x) BIT(x)
Boris Brezillon614049a2016-04-15 15:10:30 +0200156#define NFC_ECC_ERR_MSK GENMASK(15, 0)
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200157#define NFC_ECC_PAT_FOUND(x) BIT(x + 16)
Boris Brezillonf8b04742016-03-04 17:25:08 +0100158#define NFC_ECC_ERR_CNT(b, x) (((x) >> (((b) % 4) * 8)) & 0xff)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200159
160#define NFC_DEFAULT_TIMEOUT_MS 1000
161
162#define NFC_SRAM_SIZE 1024
163
164#define NFC_MAX_CS 7
165
166/*
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200167 * Chip Select structure: stores information related to NAND Chip Select
168 *
169 * @cs: the NAND CS id used to communicate with a NAND Chip
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200170 * @rb: the Ready/Busy pin ID. -1 means no R/B pin connected to the
171 * NFC
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200172 */
173struct sunxi_nand_chip_sel {
174 u8 cs;
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200175 s8 rb;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200176};
177
178/*
179 * sunxi HW ECC infos: stores information related to HW ECC support
180 *
181 * @mode: the sunxi ECC mode field deduced from ECC requirements
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200182 */
183struct sunxi_nand_hw_ecc {
184 int mode;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200185};
186
187/*
188 * NAND chip structure: stores NAND chip device related information
189 *
190 * @node: used to store NAND chips into a list
191 * @nand: base NAND chip structure
192 * @mtd: base MTD structure
193 * @clk_rate: clk_rate required for this NAND chip
Roy Spliet9c618292015-06-26 11:00:10 +0200194 * @timing_cfg TIMING_CFG register value for this NAND chip
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200195 * @selected: current active CS
196 * @nsels: number of CS lines required by the NAND chip
197 * @sels: array of CS lines descriptions
198 */
199struct sunxi_nand_chip {
200 struct list_head node;
201 struct nand_chip nand;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200202 unsigned long clk_rate;
Roy Spliet9c618292015-06-26 11:00:10 +0200203 u32 timing_cfg;
Roy Splietd052e502015-06-26 11:00:11 +0200204 u32 timing_ctl;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200205 int selected;
Boris Brezillone9aa6712015-09-16 09:05:31 +0200206 int addr_cycles;
207 u32 addr[2];
208 int cmd_cycles;
209 u8 cmd[2];
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200210 int nsels;
211 struct sunxi_nand_chip_sel sels[0];
212};
213
214static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
215{
216 return container_of(nand, struct sunxi_nand_chip, nand);
217}
218
219/*
220 * NAND Controller structure: stores sunxi NAND controller information
221 *
222 * @controller: base controller structure
223 * @dev: parent device (used to print error messages)
224 * @regs: NAND controller registers
225 * @ahb_clk: NAND Controller AHB clock
226 * @mod_clk: NAND Controller mod clock
227 * @assigned_cs: bitmask describing already assigned CS lines
228 * @clk_rate: NAND controller current clock rate
229 * @chips: a list containing all the NAND chips attached to
230 * this NAND controller
231 * @complete: a completion object used to wait for NAND
232 * controller events
233 */
234struct sunxi_nfc {
Miquel Raynal7da45132018-07-17 09:08:02 +0200235 struct nand_controller controller;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200236 struct device *dev;
237 void __iomem *regs;
238 struct clk *ahb_clk;
239 struct clk *mod_clk;
Icenowy Zhengab9d6a72016-06-20 12:48:38 +0800240 struct reset_control *reset;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200241 unsigned long assigned_cs;
242 unsigned long clk_rate;
243 struct list_head chips;
244 struct completion complete;
Boris Brezillon614049a2016-04-15 15:10:30 +0200245 struct dma_chan *dmac;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200246};
247
Miquel Raynal7da45132018-07-17 09:08:02 +0200248static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200249{
250 return container_of(ctrl, struct sunxi_nfc, controller);
251}
252
253static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
254{
255 struct sunxi_nfc *nfc = dev_id;
256 u32 st = readl(nfc->regs + NFC_REG_ST);
257 u32 ien = readl(nfc->regs + NFC_REG_INT);
258
259 if (!(ien & st))
260 return IRQ_NONE;
261
262 if ((ien & st) == ien)
263 complete(&nfc->complete);
264
265 writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
266 writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
267
268 return IRQ_HANDLED;
269}
270
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100271static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
272 bool use_polling, unsigned int timeout_ms)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200273{
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100274 int ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200275
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100276 if (events & ~NFC_INT_MASK)
277 return -EINVAL;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200278
279 if (!timeout_ms)
280 timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
281
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100282 if (!use_polling) {
283 init_completion(&nfc->complete);
284
285 writel(events, nfc->regs + NFC_REG_INT);
286
287 ret = wait_for_completion_timeout(&nfc->complete,
288 msecs_to_jiffies(timeout_ms));
Boris Brezillon19649e22017-01-06 10:42:05 +0100289 if (!ret)
290 ret = -ETIMEDOUT;
291 else
292 ret = 0;
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100293
294 writel(0, nfc->regs + NFC_REG_INT);
295 } else {
296 u32 status;
297
298 ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
299 (status & events) == events, 1,
300 timeout_ms * 1000);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200301 }
302
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100303 writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
304
305 if (ret)
306 dev_err(nfc->dev, "wait interrupt timedout\n");
307
308 return ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200309}
310
311static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
312{
Boris Brezillon166f08c2016-03-07 15:25:17 +0100313 u32 status;
314 int ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200315
Boris Brezillon166f08c2016-03-07 15:25:17 +0100316 ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
317 !(status & NFC_CMD_FIFO_STATUS), 1,
318 NFC_DEFAULT_TIMEOUT_MS * 1000);
319 if (ret)
320 dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200321
Boris Brezillon166f08c2016-03-07 15:25:17 +0100322 return ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200323}
324
325static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
326{
Boris Brezillon166f08c2016-03-07 15:25:17 +0100327 u32 ctl;
328 int ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200329
330 writel(0, nfc->regs + NFC_REG_ECC_CTL);
331 writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
332
Boris Brezillon166f08c2016-03-07 15:25:17 +0100333 ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
334 !(ctl & NFC_RESET), 1,
335 NFC_DEFAULT_TIMEOUT_MS * 1000);
336 if (ret)
337 dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200338
Boris Brezillon166f08c2016-03-07 15:25:17 +0100339 return ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200340}
341
Boris Brezillon614049a2016-04-15 15:10:30 +0200342static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
343 int chunksize, int nchunks,
344 enum dma_data_direction ddir,
345 struct scatterlist *sg)
346{
347 struct nand_chip *nand = mtd_to_nand(mtd);
348 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
349 struct dma_async_tx_descriptor *dmad;
350 enum dma_transfer_direction tdir;
351 dma_cookie_t dmat;
352 int ret;
353
354 if (ddir == DMA_FROM_DEVICE)
355 tdir = DMA_DEV_TO_MEM;
356 else
357 tdir = DMA_MEM_TO_DEV;
358
359 sg_init_one(sg, buf, nchunks * chunksize);
360 ret = dma_map_sg(nfc->dev, sg, 1, ddir);
361 if (!ret)
362 return -ENOMEM;
363
364 dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
Wei Yongjun28f3d012016-06-13 14:27:18 +0000365 if (!dmad) {
366 ret = -EINVAL;
Boris Brezillon614049a2016-04-15 15:10:30 +0200367 goto err_unmap_buf;
368 }
369
370 writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
371 nfc->regs + NFC_REG_CTL);
372 writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
373 writel(chunksize, nfc->regs + NFC_REG_CNT);
374 dmat = dmaengine_submit(dmad);
375
376 ret = dma_submit_error(dmat);
377 if (ret)
378 goto err_clr_dma_flag;
379
380 return 0;
381
382err_clr_dma_flag:
383 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
384 nfc->regs + NFC_REG_CTL);
385
386err_unmap_buf:
387 dma_unmap_sg(nfc->dev, sg, 1, ddir);
388 return ret;
389}
390
391static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
392 enum dma_data_direction ddir,
393 struct scatterlist *sg)
394{
395 struct nand_chip *nand = mtd_to_nand(mtd);
396 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
397
398 dma_unmap_sg(nfc->dev, sg, 1, ddir);
399 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
400 nfc->regs + NFC_REG_CTL);
401}
402
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200403static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
404{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100405 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200406 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
407 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200408 u32 mask;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200409
410 if (sunxi_nand->selected < 0)
411 return 0;
412
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200413 if (sunxi_nand->sels[sunxi_nand->selected].rb < 0) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200414 dev_err(nfc->dev, "cannot check R/B NAND status!\n");
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200415 return 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200416 }
417
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200418 mask = NFC_RB_STATE(sunxi_nand->sels[sunxi_nand->selected].rb);
419
420 return !!(readl(nfc->regs + NFC_REG_ST) & mask);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200421}
422
423static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
424{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100425 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200426 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
427 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
428 struct sunxi_nand_chip_sel *sel;
429 u32 ctl;
430
431 if (chip > 0 && chip >= sunxi_nand->nsels)
432 return;
433
434 if (chip == sunxi_nand->selected)
435 return;
436
437 ctl = readl(nfc->regs + NFC_REG_CTL) &
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200438 ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200439
440 if (chip >= 0) {
441 sel = &sunxi_nand->sels[chip];
442
Boris BREZILLONb6a02c02015-09-16 09:46:36 +0200443 ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
Boris Brezillon68ffbf72016-03-04 17:29:20 +0100444 NFC_PAGE_SHIFT(nand->page_shift);
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200445 if (sel->rb < 0) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200446 nand->dev_ready = NULL;
447 } else {
448 nand->dev_ready = sunxi_nfc_dev_ready;
Boris Brezillonddd5ed32018-03-27 09:06:14 +0200449 ctl |= NFC_RB_SEL(sel->rb);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200450 }
451
452 writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
453
454 if (nfc->clk_rate != sunxi_nand->clk_rate) {
455 clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
456 nfc->clk_rate = sunxi_nand->clk_rate;
457 }
458 }
459
Roy Splietd052e502015-06-26 11:00:11 +0200460 writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
Roy Spliet9c618292015-06-26 11:00:10 +0200461 writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200462 writel(ctl, nfc->regs + NFC_REG_CTL);
463
464 sunxi_nand->selected = chip;
465}
466
Boris Brezillon7e534322018-09-06 14:05:22 +0200467static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200468{
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200469 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
470 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
471 int ret;
472 int cnt;
473 int offs = 0;
474 u32 tmp;
475
476 while (len > offs) {
Boris Brezillon8de15e12017-01-06 10:42:06 +0100477 bool poll = false;
478
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200479 cnt = min(len - offs, NFC_SRAM_SIZE);
480
481 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
482 if (ret)
483 break;
484
485 writel(cnt, nfc->regs + NFC_REG_CNT);
486 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
487 writel(tmp, nfc->regs + NFC_REG_CMD);
488
Boris Brezillon8de15e12017-01-06 10:42:06 +0100489 /* Arbitrary limit for polling mode */
490 if (cnt < 64)
491 poll = true;
492
493 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200494 if (ret)
495 break;
496
497 if (buf)
498 memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
499 cnt);
500 offs += cnt;
501 }
502}
503
504static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
505 int len)
506{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100507 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200508 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
509 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
510 int ret;
511 int cnt;
512 int offs = 0;
513 u32 tmp;
514
515 while (len > offs) {
Boris Brezillon8de15e12017-01-06 10:42:06 +0100516 bool poll = false;
517
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200518 cnt = min(len - offs, NFC_SRAM_SIZE);
519
520 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
521 if (ret)
522 break;
523
524 writel(cnt, nfc->regs + NFC_REG_CNT);
525 memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
526 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
527 NFC_ACCESS_DIR;
528 writel(tmp, nfc->regs + NFC_REG_CMD);
529
Boris Brezillon8de15e12017-01-06 10:42:06 +0100530 /* Arbitrary limit for polling mode */
531 if (cnt < 64)
532 poll = true;
533
534 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200535 if (ret)
536 break;
537
538 offs += cnt;
539 }
540}
541
Boris Brezillon7e534322018-09-06 14:05:22 +0200542static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200543{
Boris Brezillon06c8b5d2018-07-09 22:09:32 +0200544 uint8_t ret = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200545
Boris Brezillon7e534322018-09-06 14:05:22 +0200546 sunxi_nfc_read_buf(nand, &ret, 1);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200547
548 return ret;
549}
550
551static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
552 unsigned int ctrl)
553{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100554 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200555 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
556 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
557 int ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200558
Boris Brezillone9aa6712015-09-16 09:05:31 +0200559 if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
560 !(ctrl & (NAND_CLE | NAND_ALE))) {
561 u32 cmd = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200562
Boris Brezillone9aa6712015-09-16 09:05:31 +0200563 if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
564 return;
565
566 if (sunxi_nand->cmd_cycles--)
567 cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
568
569 if (sunxi_nand->cmd_cycles--) {
570 cmd |= NFC_SEND_CMD2;
571 writel(sunxi_nand->cmd[1],
572 nfc->regs + NFC_REG_RCMD_SET);
573 }
574
575 sunxi_nand->cmd_cycles = 0;
576
577 if (sunxi_nand->addr_cycles) {
578 cmd |= NFC_SEND_ADR |
579 NFC_ADR_NUM(sunxi_nand->addr_cycles);
580 writel(sunxi_nand->addr[0],
581 nfc->regs + NFC_REG_ADDR_LOW);
582 }
583
584 if (sunxi_nand->addr_cycles > 4)
585 writel(sunxi_nand->addr[1],
586 nfc->regs + NFC_REG_ADDR_HIGH);
587
Boris Brezilloncad32742017-01-06 10:42:07 +0100588 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
589 if (ret)
590 return;
591
Boris Brezillone9aa6712015-09-16 09:05:31 +0200592 writel(cmd, nfc->regs + NFC_REG_CMD);
593 sunxi_nand->addr[0] = 0;
594 sunxi_nand->addr[1] = 0;
595 sunxi_nand->addr_cycles = 0;
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100596 sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200597 }
598
Boris Brezillone9aa6712015-09-16 09:05:31 +0200599 if (ctrl & NAND_CLE) {
600 sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
601 } else if (ctrl & NAND_ALE) {
602 sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
603 dat << ((sunxi_nand->addr_cycles % 4) * 8);
604 sunxi_nand->addr_cycles++;
605 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200606}
607
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100608/* These seed values have been extracted from Allwinner's BSP */
609static const u16 sunxi_nfc_randomizer_page_seeds[] = {
610 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
611 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
612 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
613 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
614 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
615 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
616 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
617 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
618 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
619 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
620 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
621 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
622 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
623 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
624 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
625 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
626};
627
628/*
629 * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
630 * have been generated using
631 * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
632 * the randomizer engine does internally before de/scrambling OOB data.
633 *
634 * Those tables are statically defined to avoid calculating randomizer state
635 * at runtime.
636 */
637static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
638 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
639 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
640 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
641 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
642 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
643 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
644 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
645 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
646 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
647 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
648 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
649 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
650 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
651 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
652 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
653 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
654};
655
656static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
657 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
658 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
659 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
660 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
661 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
662 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
663 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
664 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
665 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
666 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
667 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
668 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
669 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
670 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
671 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
672 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
673};
674
675static u16 sunxi_nfc_randomizer_step(u16 state, int count)
676{
677 state &= 0x7fff;
678
679 /*
680 * This loop is just a simple implementation of a Fibonacci LFSR using
681 * the x16 + x15 + 1 polynomial.
682 */
683 while (count--)
684 state = ((state >> 1) |
685 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
686
687 return state;
688}
689
690static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
691{
692 const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
Brian Norris46c135c2016-01-22 18:57:13 -0800693 int mod = mtd_div_by_ws(mtd->erasesize, mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100694
695 if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
696 mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
697
698 if (ecc) {
699 if (mtd->ecc_step_size == 512)
700 seeds = sunxi_nfc_randomizer_ecc512_seeds;
701 else
702 seeds = sunxi_nfc_randomizer_ecc1024_seeds;
703 }
704
705 return seeds[page % mod];
706}
707
708static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
709 int page, bool ecc)
710{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100711 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100712 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
713 u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
714 u16 state;
715
716 if (!(nand->options & NAND_NEED_SCRAMBLING))
717 return;
718
719 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
720 state = sunxi_nfc_randomizer_state(mtd, page, ecc);
721 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
722 writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
723}
724
725static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
726{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100727 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100728 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
729
730 if (!(nand->options & NAND_NEED_SCRAMBLING))
731 return;
732
733 writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
734 nfc->regs + NFC_REG_ECC_CTL);
735}
736
737static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
738{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100739 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100740 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
741
742 if (!(nand->options & NAND_NEED_SCRAMBLING))
743 return;
744
745 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
746 nfc->regs + NFC_REG_ECC_CTL);
747}
748
749static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
750{
751 u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
752
753 bbm[0] ^= state;
754 bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
755}
756
757static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
758 const uint8_t *buf, int len,
759 bool ecc, int page)
760{
761 sunxi_nfc_randomizer_config(mtd, page, ecc);
762 sunxi_nfc_randomizer_enable(mtd);
763 sunxi_nfc_write_buf(mtd, buf, len);
764 sunxi_nfc_randomizer_disable(mtd);
765}
766
767static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
768 int len, bool ecc, int page)
769{
770 sunxi_nfc_randomizer_config(mtd, page, ecc);
771 sunxi_nfc_randomizer_enable(mtd);
Boris Brezillon7e534322018-09-06 14:05:22 +0200772 sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100773 sunxi_nfc_randomizer_disable(mtd);
774}
775
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200776static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
777{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100778 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200779 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
780 struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
781 u32 ecc_ctl;
782
783 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
784 ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
785 NFC_ECC_BLOCK_SIZE_MSK);
Boris Brezillon336de7b2016-03-04 17:33:10 +0100786 ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
787 NFC_ECC_PIPELINE;
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200788
Boris Brezillonf59dab82016-10-20 10:12:42 +0200789 if (nand->ecc.size == 512)
790 ecc_ctl |= NFC_ECC_BLOCK_512;
791
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200792 writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
793}
794
795static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
796{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100797 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200798 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
799
800 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
801 nfc->regs + NFC_REG_ECC_CTL);
802}
803
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200804static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
805{
806 buf[0] = user_data;
807 buf[1] = user_data >> 8;
808 buf[2] = user_data >> 16;
809 buf[3] = user_data >> 24;
810}
811
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100812static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
813{
814 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
815}
816
817static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
818 int step, bool bbm, int page)
819{
820 struct nand_chip *nand = mtd_to_nand(mtd);
821 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
822
823 sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
824 oob);
825
826 /* De-randomize the Bad Block Marker. */
827 if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
828 sunxi_nfc_randomize_bbm(mtd, page, oob);
829}
830
831static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
832 const u8 *oob, int step,
833 bool bbm, int page)
834{
835 struct nand_chip *nand = mtd_to_nand(mtd);
836 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
837 u8 user_data[4];
838
839 /* Randomize the Bad Block Marker. */
840 if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
841 memcpy(user_data, oob, sizeof(user_data));
842 sunxi_nfc_randomize_bbm(mtd, page, user_data);
843 oob = user_data;
844 }
845
846 writel(sunxi_nfc_buf_to_user_data(oob),
847 nfc->regs + NFC_REG_USER_DATA(step));
848}
849
850static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
851 unsigned int *max_bitflips, int ret)
852{
853 if (ret < 0) {
854 mtd->ecc_stats.failed++;
855 } else {
856 mtd->ecc_stats.corrected += ret;
857 *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
858 }
859}
860
861static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
Boris Brezillon614049a2016-04-15 15:10:30 +0200862 int step, u32 status, bool *erased)
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100863{
864 struct nand_chip *nand = mtd_to_nand(mtd);
865 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
866 struct nand_ecc_ctrl *ecc = &nand->ecc;
Boris Brezillon614049a2016-04-15 15:10:30 +0200867 u32 tmp;
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100868
869 *erased = false;
870
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100871 if (status & NFC_ECC_ERR(step))
872 return -EBADMSG;
873
874 if (status & NFC_ECC_PAT_FOUND(step)) {
875 u8 pattern;
876
877 if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
878 pattern = 0x0;
879 } else {
880 pattern = 0xff;
881 *erased = true;
882 }
883
884 if (data)
885 memset(data, pattern, ecc->size);
886
887 if (oob)
888 memset(oob, pattern, ecc->bytes + 4);
889
890 return 0;
891 }
892
893 tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
894
895 return NFC_ECC_ERR_CNT(step, tmp);
896}
897
Boris BREZILLON913821b2015-09-30 23:45:24 +0200898static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
899 u8 *data, int data_off,
900 u8 *oob, int oob_off,
901 int *cur_off,
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100902 unsigned int *max_bitflips,
Boris Brezillon828dec12016-03-04 18:09:21 +0100903 bool bbm, bool oob_required, int page)
Boris BREZILLON913821b2015-09-30 23:45:24 +0200904{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100905 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200906 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
907 struct nand_ecc_ctrl *ecc = &nand->ecc;
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100908 int raw_mode = 0;
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100909 bool erased;
Boris BREZILLON913821b2015-09-30 23:45:24 +0200910 int ret;
911
912 if (*cur_off != data_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100913 nand_change_read_column_op(nand, data_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200914
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100915 sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200916
Boris BREZILLON74eb9ff2015-10-20 22:16:00 +0200917 if (data_off + ecc->size != oob_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100918 nand_change_read_column_op(nand, oob_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200919
920 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
921 if (ret)
922 return ret;
923
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100924 sunxi_nfc_randomizer_enable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200925 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
926 nfc->regs + NFC_REG_CMD);
927
Boris Brezillon8de15e12017-01-06 10:42:06 +0100928 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100929 sunxi_nfc_randomizer_disable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200930 if (ret)
931 return ret;
932
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100933 *cur_off = oob_off + ecc->bytes + 4;
934
Boris Brezillon828dec12016-03-04 18:09:21 +0100935 ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
Boris Brezillon614049a2016-04-15 15:10:30 +0200936 readl(nfc->regs + NFC_REG_ECC_ST),
Boris Brezillon828dec12016-03-04 18:09:21 +0100937 &erased);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100938 if (erased)
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100939 return 1;
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100940
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100941 if (ret < 0) {
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100942 /*
943 * Re-read the data with the randomizer disabled to identify
944 * bitflips in erased pages.
945 */
Boris Brezillon97d90da2017-11-30 18:01:29 +0100946 if (nand->options & NAND_NEED_SCRAMBLING)
947 nand_change_read_column_op(nand, data_off, data,
948 ecc->size, false);
949 else
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100950 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
951 ecc->size);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100952
Boris Brezillon97d90da2017-11-30 18:01:29 +0100953 nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
954 false);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100955
Boris BREZILLON146b5032015-09-30 23:45:29 +0200956 ret = nand_check_erased_ecc_chunk(data, ecc->size,
957 oob, ecc->bytes + 4,
958 NULL, 0, ecc->strength);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100959 if (ret >= 0)
960 raw_mode = 1;
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200961 } else {
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100962 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100963
Boris Brezillon828dec12016-03-04 18:09:21 +0100964 if (oob_required) {
Boris Brezillon97d90da2017-11-30 18:01:29 +0100965 nand_change_read_column_op(nand, oob_off, NULL, 0,
966 false);
Boris Brezillon828dec12016-03-04 18:09:21 +0100967 sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
968 true, page);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100969
Boris Brezillon828dec12016-03-04 18:09:21 +0100970 sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
971 bbm, page);
972 }
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200973 }
Boris BREZILLON913821b2015-09-30 23:45:24 +0200974
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100975 sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200976
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100977 return raw_mode;
Boris BREZILLON913821b2015-09-30 23:45:24 +0200978}
979
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200980static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100981 u8 *oob, int *cur_off,
982 bool randomize, int page)
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200983{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100984 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200985 struct nand_ecc_ctrl *ecc = &nand->ecc;
986 int offset = ((ecc->bytes + 4) * ecc->steps);
987 int len = mtd->oobsize - offset;
988
989 if (len <= 0)
990 return;
991
Boris Brezillonc4f3ef22016-03-04 18:13:10 +0100992 if (!cur_off || *cur_off != offset)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100993 nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
994 false);
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200995
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100996 if (!randomize)
Boris Brezillon7e534322018-09-06 14:05:22 +0200997 sunxi_nfc_read_buf(nand, oob + offset, len);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100998 else
999 sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
1000 false, page);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001001
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001002 if (cur_off)
1003 *cur_off = mtd->oobsize + mtd->writesize;
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001004}
1005
Boris Brezillon614049a2016-04-15 15:10:30 +02001006static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
1007 int oob_required, int page,
1008 int nchunks)
1009{
1010 struct nand_chip *nand = mtd_to_nand(mtd);
1011 bool randomized = nand->options & NAND_NEED_SCRAMBLING;
1012 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1013 struct nand_ecc_ctrl *ecc = &nand->ecc;
1014 unsigned int max_bitflips = 0;
1015 int ret, i, raw_mode = 0;
1016 struct scatterlist sg;
1017 u32 status;
1018
1019 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1020 if (ret)
1021 return ret;
1022
1023 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
1024 DMA_FROM_DEVICE, &sg);
1025 if (ret)
1026 return ret;
1027
1028 sunxi_nfc_hw_ecc_enable(mtd);
1029 sunxi_nfc_randomizer_config(mtd, page, false);
1030 sunxi_nfc_randomizer_enable(mtd);
1031
1032 writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
1033 NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
1034
1035 dma_async_issue_pending(nfc->dmac);
1036
1037 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
1038 nfc->regs + NFC_REG_CMD);
1039
Boris Brezillon8de15e12017-01-06 10:42:06 +01001040 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris Brezillon614049a2016-04-15 15:10:30 +02001041 if (ret)
1042 dmaengine_terminate_all(nfc->dmac);
1043
1044 sunxi_nfc_randomizer_disable(mtd);
1045 sunxi_nfc_hw_ecc_disable(mtd);
1046
1047 sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
1048
1049 if (ret)
1050 return ret;
1051
1052 status = readl(nfc->regs + NFC_REG_ECC_ST);
1053
1054 for (i = 0; i < nchunks; i++) {
1055 int data_off = i * ecc->size;
1056 int oob_off = i * (ecc->bytes + 4);
1057 u8 *data = buf + data_off;
1058 u8 *oob = nand->oob_poi + oob_off;
1059 bool erased;
1060
1061 ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
1062 oob_required ? oob : NULL,
1063 i, status, &erased);
1064
1065 /* ECC errors are handled in the second loop. */
1066 if (ret < 0)
1067 continue;
1068
1069 if (oob_required && !erased) {
1070 /* TODO: use DMA to retrieve OOB */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001071 nand_change_read_column_op(nand,
1072 mtd->writesize + oob_off,
1073 oob, ecc->bytes + 4, false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001074
1075 sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
1076 !i, page);
1077 }
1078
1079 if (erased)
1080 raw_mode = 1;
1081
1082 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1083 }
1084
1085 if (status & NFC_ECC_ERR_MSK) {
1086 for (i = 0; i < nchunks; i++) {
1087 int data_off = i * ecc->size;
1088 int oob_off = i * (ecc->bytes + 4);
1089 u8 *data = buf + data_off;
1090 u8 *oob = nand->oob_poi + oob_off;
1091
1092 if (!(status & NFC_ECC_ERR(i)))
1093 continue;
1094
1095 /*
1096 * Re-read the data with the randomizer disabled to
1097 * identify bitflips in erased pages.
Boris Brezillon97d90da2017-11-30 18:01:29 +01001098 * TODO: use DMA to read page in raw mode
Boris Brezillon614049a2016-04-15 15:10:30 +02001099 */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001100 if (randomized)
1101 nand_change_read_column_op(nand, data_off,
1102 data, ecc->size,
1103 false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001104
1105 /* TODO: use DMA to retrieve OOB */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001106 nand_change_read_column_op(nand,
1107 mtd->writesize + oob_off,
1108 oob, ecc->bytes + 4, false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001109
1110 ret = nand_check_erased_ecc_chunk(data, ecc->size,
1111 oob, ecc->bytes + 4,
1112 NULL, 0,
1113 ecc->strength);
1114 if (ret >= 0)
1115 raw_mode = 1;
1116
1117 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1118 }
1119 }
1120
1121 if (oob_required)
1122 sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
1123 NULL, !raw_mode,
1124 page);
1125
1126 return max_bitflips;
1127}
1128
Boris BREZILLON913821b2015-09-30 23:45:24 +02001129static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
1130 const u8 *data, int data_off,
1131 const u8 *oob, int oob_off,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001132 int *cur_off, bool bbm,
1133 int page)
Boris BREZILLON913821b2015-09-30 23:45:24 +02001134{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001135 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001136 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1137 struct nand_ecc_ctrl *ecc = &nand->ecc;
1138 int ret;
1139
1140 if (data_off != *cur_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001141 nand_change_write_column_op(nand, data_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001142
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001143 sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001144
Boris BREZILLON74eb9ff2015-10-20 22:16:00 +02001145 if (data_off + ecc->size != oob_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001146 nand_change_write_column_op(nand, oob_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001147
1148 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1149 if (ret)
1150 return ret;
1151
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001152 sunxi_nfc_randomizer_enable(mtd);
Boris Brezilloncc6822f2016-03-04 17:56:47 +01001153 sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
1154
Boris BREZILLON913821b2015-09-30 23:45:24 +02001155 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
1156 NFC_ACCESS_DIR | NFC_ECC_OP,
1157 nfc->regs + NFC_REG_CMD);
1158
Boris Brezillon8de15e12017-01-06 10:42:06 +01001159 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001160 sunxi_nfc_randomizer_disable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001161 if (ret)
1162 return ret;
1163
1164 *cur_off = oob_off + ecc->bytes + 4;
1165
1166 return 0;
1167}
1168
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001169static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001170 u8 *oob, int *cur_off,
1171 int page)
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001172{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001173 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001174 struct nand_ecc_ctrl *ecc = &nand->ecc;
1175 int offset = ((ecc->bytes + 4) * ecc->steps);
1176 int len = mtd->oobsize - offset;
1177
1178 if (len <= 0)
1179 return;
1180
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001181 if (!cur_off || *cur_off != offset)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001182 nand_change_write_column_op(nand, offset + mtd->writesize,
1183 NULL, 0, false);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001184
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001185 sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001186
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001187 if (cur_off)
1188 *cur_off = mtd->oobsize + mtd->writesize;
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001189}
1190
Boris Brezillonb9761682018-09-06 14:05:20 +02001191static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001192 int oob_required, int page)
1193{
Boris Brezillonb9761682018-09-06 14:05:20 +02001194 struct mtd_info *mtd = nand_to_mtd(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001195 struct nand_ecc_ctrl *ecc = &chip->ecc;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001196 unsigned int max_bitflips = 0;
Boris BREZILLONb4625512015-09-30 23:45:25 +02001197 int ret, i, cur_off = 0;
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001198 bool raw_mode = false;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001199
Boris Brezillon25f815f2017-11-30 18:01:30 +01001200 nand_read_page_op(chip, page, 0, NULL, 0);
1201
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001202 sunxi_nfc_hw_ecc_enable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001203
1204 for (i = 0; i < ecc->steps; i++) {
Boris BREZILLONb4625512015-09-30 23:45:25 +02001205 int data_off = i * ecc->size;
1206 int oob_off = i * (ecc->bytes + 4);
1207 u8 *data = buf + data_off;
1208 u8 *oob = chip->oob_poi + oob_off;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001209
Boris BREZILLONb4625512015-09-30 23:45:25 +02001210 ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
1211 oob_off + mtd->writesize,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001212 &cur_off, &max_bitflips,
Boris Brezillon828dec12016-03-04 18:09:21 +01001213 !i, oob_required, page);
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001214 if (ret < 0)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001215 return ret;
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001216 else if (ret)
1217 raw_mode = true;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001218 }
1219
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001220 if (oob_required)
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001221 sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
1222 !raw_mode, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001223
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001224 sunxi_nfc_hw_ecc_disable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001225
1226 return max_bitflips;
1227}
1228
Boris Brezillonb9761682018-09-06 14:05:20 +02001229static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
Boris Brezillon614049a2016-04-15 15:10:30 +02001230 int oob_required, int page)
1231{
Boris Brezillonb9761682018-09-06 14:05:20 +02001232 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001233 int ret;
1234
Boris Brezillon25f815f2017-11-30 18:01:30 +01001235 nand_read_page_op(chip, page, 0, NULL, 0);
1236
Boris Brezillon614049a2016-04-15 15:10:30 +02001237 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
1238 chip->ecc.steps);
1239 if (ret >= 0)
1240 return ret;
1241
1242 /* Fallback to PIO mode */
Boris Brezillonb9761682018-09-06 14:05:20 +02001243 return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
Boris Brezillon614049a2016-04-15 15:10:30 +02001244}
1245
Boris Brezillonb9761682018-09-06 14:05:20 +02001246static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001247 u32 data_offs, u32 readlen,
1248 u8 *bufpoi, int page)
1249{
Boris Brezillonb9761682018-09-06 14:05:20 +02001250 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001251 struct nand_ecc_ctrl *ecc = &chip->ecc;
1252 int ret, i, cur_off = 0;
1253 unsigned int max_bitflips = 0;
1254
Boris Brezillon25f815f2017-11-30 18:01:30 +01001255 nand_read_page_op(chip, page, 0, NULL, 0);
1256
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001257 sunxi_nfc_hw_ecc_enable(mtd);
1258
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001259 for (i = data_offs / ecc->size;
1260 i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
1261 int data_off = i * ecc->size;
1262 int oob_off = i * (ecc->bytes + 4);
1263 u8 *data = bufpoi + data_off;
1264 u8 *oob = chip->oob_poi + oob_off;
1265
1266 ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
1267 oob,
1268 oob_off + mtd->writesize,
Boris Brezillon828dec12016-03-04 18:09:21 +01001269 &cur_off, &max_bitflips, !i,
1270 false, page);
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001271 if (ret < 0)
1272 return ret;
1273 }
1274
1275 sunxi_nfc_hw_ecc_disable(mtd);
1276
1277 return max_bitflips;
1278}
1279
Boris Brezillonb9761682018-09-06 14:05:20 +02001280static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
Boris Brezillon614049a2016-04-15 15:10:30 +02001281 u32 data_offs, u32 readlen,
1282 u8 *buf, int page)
1283{
Boris Brezillonb9761682018-09-06 14:05:20 +02001284 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001285 int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
1286 int ret;
1287
Boris Brezillon25f815f2017-11-30 18:01:30 +01001288 nand_read_page_op(chip, page, 0, NULL, 0);
1289
Boris Brezillon614049a2016-04-15 15:10:30 +02001290 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
1291 if (ret >= 0)
1292 return ret;
1293
1294 /* Fallback to PIO mode */
Boris Brezillonb9761682018-09-06 14:05:20 +02001295 return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
Boris Brezillon614049a2016-04-15 15:10:30 +02001296 buf, page);
1297}
1298
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001299static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
Boris BREZILLON45aaeff2015-10-13 11:22:18 +02001300 const uint8_t *buf, int oob_required,
1301 int page)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001302{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001303 struct mtd_info *mtd = nand_to_mtd(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001304 struct nand_ecc_ctrl *ecc = &chip->ecc;
Boris BREZILLONb4625512015-09-30 23:45:25 +02001305 int ret, i, cur_off = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001306
Boris Brezillon25f815f2017-11-30 18:01:30 +01001307 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1308
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001309 sunxi_nfc_hw_ecc_enable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001310
1311 for (i = 0; i < ecc->steps; i++) {
Boris BREZILLONb4625512015-09-30 23:45:25 +02001312 int data_off = i * ecc->size;
1313 int oob_off = i * (ecc->bytes + 4);
1314 const u8 *data = buf + data_off;
1315 const u8 *oob = chip->oob_poi + oob_off;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001316
Boris BREZILLONb4625512015-09-30 23:45:25 +02001317 ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
1318 oob_off + mtd->writesize,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001319 &cur_off, !i, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001320 if (ret)
1321 return ret;
1322 }
1323
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001324 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
1325 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
1326 &cur_off, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001327
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001328 sunxi_nfc_hw_ecc_disable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001329
Boris Brezillon25f815f2017-11-30 18:01:30 +01001330 return nand_prog_page_end_op(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001331}
1332
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001333static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
Boris Brezillon03b1d112016-06-06 13:59:14 +02001334 u32 data_offs, u32 data_len,
1335 const u8 *buf, int oob_required,
1336 int page)
1337{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001338 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon03b1d112016-06-06 13:59:14 +02001339 struct nand_ecc_ctrl *ecc = &chip->ecc;
1340 int ret, i, cur_off = 0;
1341
Boris Brezillon25f815f2017-11-30 18:01:30 +01001342 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1343
Boris Brezillon03b1d112016-06-06 13:59:14 +02001344 sunxi_nfc_hw_ecc_enable(mtd);
1345
1346 for (i = data_offs / ecc->size;
1347 i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
1348 int data_off = i * ecc->size;
1349 int oob_off = i * (ecc->bytes + 4);
1350 const u8 *data = buf + data_off;
1351 const u8 *oob = chip->oob_poi + oob_off;
1352
1353 ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
1354 oob_off + mtd->writesize,
1355 &cur_off, !i, page);
1356 if (ret)
1357 return ret;
1358 }
1359
1360 sunxi_nfc_hw_ecc_disable(mtd);
1361
Boris Brezillon25f815f2017-11-30 18:01:30 +01001362 return nand_prog_page_end_op(chip);
Boris Brezillon03b1d112016-06-06 13:59:14 +02001363}
1364
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001365static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
Boris Brezillon614049a2016-04-15 15:10:30 +02001366 const u8 *buf,
1367 int oob_required,
1368 int page)
1369{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001370 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001371 struct nand_chip *nand = mtd_to_nand(mtd);
1372 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1373 struct nand_ecc_ctrl *ecc = &nand->ecc;
1374 struct scatterlist sg;
1375 int ret, i;
1376
1377 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1378 if (ret)
1379 return ret;
1380
1381 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
1382 DMA_TO_DEVICE, &sg);
1383 if (ret)
1384 goto pio_fallback;
1385
1386 for (i = 0; i < ecc->steps; i++) {
1387 const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
1388
1389 sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
1390 }
1391
Boris Brezillon25f815f2017-11-30 18:01:30 +01001392 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1393
Boris Brezillon614049a2016-04-15 15:10:30 +02001394 sunxi_nfc_hw_ecc_enable(mtd);
1395 sunxi_nfc_randomizer_config(mtd, page, false);
1396 sunxi_nfc_randomizer_enable(mtd);
1397
1398 writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
1399 nfc->regs + NFC_REG_RCMD_SET);
1400
1401 dma_async_issue_pending(nfc->dmac);
1402
1403 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
1404 NFC_DATA_TRANS | NFC_ACCESS_DIR,
1405 nfc->regs + NFC_REG_CMD);
1406
Boris Brezillon8de15e12017-01-06 10:42:06 +01001407 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris Brezillon614049a2016-04-15 15:10:30 +02001408 if (ret)
1409 dmaengine_terminate_all(nfc->dmac);
1410
1411 sunxi_nfc_randomizer_disable(mtd);
1412 sunxi_nfc_hw_ecc_disable(mtd);
1413
1414 sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
1415
1416 if (ret)
1417 return ret;
1418
1419 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
1420 /* TODO: use DMA to transfer extra OOB bytes ? */
1421 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
1422 NULL, page);
1423
Boris Brezillon25f815f2017-11-30 18:01:30 +01001424 return nand_prog_page_end_op(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001425
1426pio_fallback:
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001427 return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
Boris Brezillon614049a2016-04-15 15:10:30 +02001428}
1429
Boris Brezillonb9761682018-09-06 14:05:20 +02001430static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001431{
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001432 chip->pagebuf = -1;
1433
Boris Brezillonb9761682018-09-06 14:05:20 +02001434 return chip->ecc.read_page(chip, chip->data_buf, 1, page);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001435}
1436
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001437static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001438{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001439 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon97d90da2017-11-30 18:01:29 +01001440 int ret;
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001441
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001442 chip->pagebuf = -1;
1443
Masahiro Yamadac0313b92017-12-05 17:47:16 +09001444 memset(chip->data_buf, 0xff, mtd->writesize);
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001445 ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001446 if (ret)
1447 return ret;
1448
1449 /* Send command to program the OOB data */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001450 return nand_prog_page_end_op(chip);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001451}
1452
Roy Spliet9c618292015-06-26 11:00:10 +02001453static const s32 tWB_lut[] = {6, 12, 16, 20};
1454static const s32 tRHW_lut[] = {4, 8, 12, 20};
1455
1456static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
1457 u32 clk_period)
1458{
1459 u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
1460 int i;
1461
1462 for (i = 0; i < lut_size; i++) {
1463 if (clk_cycles <= lut[i])
1464 return i;
1465 }
1466
1467 /* Doesn't fit */
1468 return -EINVAL;
1469}
1470
1471#define sunxi_nand_lookup_timing(l, p, c) \
1472 _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
1473
Boris Brezillon104e4422017-03-16 09:35:58 +01001474static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
1475 const struct nand_data_interface *conf)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001476{
Sascha Hauer907f45f2016-09-15 10:32:51 +02001477 struct nand_chip *nand = mtd_to_nand(mtd);
1478 struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
Roy Spliet9c618292015-06-26 11:00:10 +02001479 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
Sascha Hauer907f45f2016-09-15 10:32:51 +02001480 const struct nand_sdr_timings *timings;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001481 u32 min_clk_period = 0;
Roy Spliet9c618292015-06-26 11:00:10 +02001482 s32 tWB, tADL, tWHR, tRHW, tCAD;
Boris Brezillon2d434572015-12-02 15:57:20 +01001483 long real_clk_rate;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001484
Sascha Hauer907f45f2016-09-15 10:32:51 +02001485 timings = nand_get_sdr_timings(conf);
1486 if (IS_ERR(timings))
1487 return -ENOTSUPP;
1488
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001489 /* T1 <=> tCLS */
1490 if (timings->tCLS_min > min_clk_period)
1491 min_clk_period = timings->tCLS_min;
1492
1493 /* T2 <=> tCLH */
1494 if (timings->tCLH_min > min_clk_period)
1495 min_clk_period = timings->tCLH_min;
1496
1497 /* T3 <=> tCS */
1498 if (timings->tCS_min > min_clk_period)
1499 min_clk_period = timings->tCS_min;
1500
1501 /* T4 <=> tCH */
1502 if (timings->tCH_min > min_clk_period)
1503 min_clk_period = timings->tCH_min;
1504
1505 /* T5 <=> tWP */
1506 if (timings->tWP_min > min_clk_period)
1507 min_clk_period = timings->tWP_min;
1508
1509 /* T6 <=> tWH */
1510 if (timings->tWH_min > min_clk_period)
1511 min_clk_period = timings->tWH_min;
1512
1513 /* T7 <=> tALS */
1514 if (timings->tALS_min > min_clk_period)
1515 min_clk_period = timings->tALS_min;
1516
1517 /* T8 <=> tDS */
1518 if (timings->tDS_min > min_clk_period)
1519 min_clk_period = timings->tDS_min;
1520
1521 /* T9 <=> tDH */
1522 if (timings->tDH_min > min_clk_period)
1523 min_clk_period = timings->tDH_min;
1524
1525 /* T10 <=> tRR */
1526 if (timings->tRR_min > (min_clk_period * 3))
1527 min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
1528
1529 /* T11 <=> tALH */
1530 if (timings->tALH_min > min_clk_period)
1531 min_clk_period = timings->tALH_min;
1532
1533 /* T12 <=> tRP */
1534 if (timings->tRP_min > min_clk_period)
1535 min_clk_period = timings->tRP_min;
1536
1537 /* T13 <=> tREH */
1538 if (timings->tREH_min > min_clk_period)
1539 min_clk_period = timings->tREH_min;
1540
1541 /* T14 <=> tRC */
1542 if (timings->tRC_min > (min_clk_period * 2))
1543 min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
1544
1545 /* T15 <=> tWC */
1546 if (timings->tWC_min > (min_clk_period * 2))
1547 min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
1548
Roy Spliet9c618292015-06-26 11:00:10 +02001549 /* T16 - T19 + tCAD */
Boris Brezillon5abcd952015-11-11 22:30:30 +01001550 if (timings->tWB_max > (min_clk_period * 20))
1551 min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
1552
1553 if (timings->tADL_min > (min_clk_period * 32))
1554 min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
1555
1556 if (timings->tWHR_min > (min_clk_period * 32))
1557 min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
1558
1559 if (timings->tRHW_min > (min_clk_period * 20))
1560 min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
1561
Roy Spliet9c618292015-06-26 11:00:10 +02001562 tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
1563 min_clk_period);
1564 if (tWB < 0) {
1565 dev_err(nfc->dev, "unsupported tWB\n");
1566 return tWB;
1567 }
1568
1569 tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
1570 if (tADL > 3) {
1571 dev_err(nfc->dev, "unsupported tADL\n");
1572 return -EINVAL;
1573 }
1574
1575 tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
1576 if (tWHR > 3) {
1577 dev_err(nfc->dev, "unsupported tWHR\n");
1578 return -EINVAL;
1579 }
1580
1581 tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
1582 min_clk_period);
1583 if (tRHW < 0) {
1584 dev_err(nfc->dev, "unsupported tRHW\n");
1585 return tRHW;
1586 }
1587
Boris Brezillon104e4422017-03-16 09:35:58 +01001588 if (csline == NAND_DATA_IFACE_CHECK_ONLY)
Sascha Hauer907f45f2016-09-15 10:32:51 +02001589 return 0;
1590
Roy Spliet9c618292015-06-26 11:00:10 +02001591 /*
1592 * TODO: according to ONFI specs this value only applies for DDR NAND,
1593 * but Allwinner seems to set this to 0x7. Mimic them for now.
1594 */
1595 tCAD = 0x7;
1596
1597 /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
1598 chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001599
1600 /* Convert min_clk_period from picoseconds to nanoseconds */
1601 min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
1602
1603 /*
Boris Brezillon2f9992e2015-12-02 15:10:40 +01001604 * Unlike what is stated in Allwinner datasheet, the clk_rate should
1605 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
1606 * This new formula was verified with a scope and validated by
1607 * Allwinner engineers.
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001608 */
Boris Brezillon2f9992e2015-12-02 15:10:40 +01001609 chip->clk_rate = NSEC_PER_SEC / min_clk_period;
Boris Brezillon2d434572015-12-02 15:57:20 +01001610 real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
Bryan O'Donoghue791eccd2017-07-28 14:22:57 +01001611 if (real_clk_rate <= 0) {
1612 dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
1613 return -EINVAL;
1614 }
Boris Brezillon2d434572015-12-02 15:57:20 +01001615
1616 /*
1617 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
1618 * output cycle timings shall be used if the host drives tRC less than
1619 * 30 ns.
1620 */
1621 min_clk_period = NSEC_PER_SEC / real_clk_rate;
1622 chip->timing_ctl = ((min_clk_period * 2) < 30) ?
1623 NFC_TIMING_CTL_EDO : 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001624
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001625 return 0;
1626}
1627
Boris Brezillonc66811e2016-02-03 20:05:13 +01001628static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
1629 struct mtd_oob_region *oobregion)
1630{
1631 struct nand_chip *nand = mtd_to_nand(mtd);
1632 struct nand_ecc_ctrl *ecc = &nand->ecc;
1633
1634 if (section >= ecc->steps)
1635 return -ERANGE;
1636
1637 oobregion->offset = section * (ecc->bytes + 4) + 4;
1638 oobregion->length = ecc->bytes;
1639
1640 return 0;
1641}
1642
1643static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
1644 struct mtd_oob_region *oobregion)
1645{
1646 struct nand_chip *nand = mtd_to_nand(mtd);
1647 struct nand_ecc_ctrl *ecc = &nand->ecc;
1648
1649 if (section > ecc->steps)
1650 return -ERANGE;
1651
1652 /*
1653 * The first 2 bytes are used for BB markers, hence we
1654 * only have 2 bytes available in the first user data
1655 * section.
1656 */
1657 if (!section && ecc->mode == NAND_ECC_HW) {
1658 oobregion->offset = 2;
1659 oobregion->length = 2;
1660
1661 return 0;
1662 }
1663
1664 oobregion->offset = section * (ecc->bytes + 4);
1665
1666 if (section < ecc->steps)
1667 oobregion->length = 4;
1668 else
1669 oobregion->offset = mtd->oobsize - oobregion->offset;
1670
1671 return 0;
1672}
1673
1674static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
1675 .ecc = sunxi_nand_ooblayout_ecc,
1676 .free = sunxi_nand_ooblayout_free,
1677};
1678
Boris Brezillon15d6f112018-03-21 09:36:18 +01001679static void sunxi_nand_hw_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
1680{
1681 kfree(ecc->priv);
1682}
1683
1684static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
1685 struct nand_ecc_ctrl *ecc,
1686 struct device_node *np)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001687{
1688 static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001689 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001690 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
1691 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
1692 struct sunxi_nand_hw_ecc *data;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001693 int nsectors;
1694 int ret;
1695 int i;
1696
Boris Brezillon4796d862016-06-08 17:04:24 +02001697 if (ecc->options & NAND_ECC_MAXIMIZE) {
1698 int bytes;
1699
1700 ecc->size = 1024;
1701 nsectors = mtd->writesize / ecc->size;
1702
1703 /* Reserve 2 bytes for the BBM */
1704 bytes = (mtd->oobsize - 2) / nsectors;
1705
1706 /* 4 non-ECC bytes are added before each ECC bytes section */
1707 bytes -= 4;
1708
1709 /* and bytes has to be even. */
1710 if (bytes % 2)
1711 bytes--;
1712
1713 ecc->strength = bytes * 8 / fls(8 * ecc->size);
1714
1715 for (i = 0; i < ARRAY_SIZE(strengths); i++) {
1716 if (strengths[i] > ecc->strength)
1717 break;
1718 }
1719
1720 if (!i)
1721 ecc->strength = 0;
1722 else
1723 ecc->strength = strengths[i - 1];
1724 }
1725
Dan Carpenter40297e72016-06-24 15:24:03 +03001726 if (ecc->size != 512 && ecc->size != 1024)
1727 return -EINVAL;
1728
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001729 data = kzalloc(sizeof(*data), GFP_KERNEL);
1730 if (!data)
1731 return -ENOMEM;
1732
Boris Brezillon872164e2016-06-06 13:59:12 +02001733 /* Prefer 1k ECC chunk over 512 ones */
1734 if (ecc->size == 512 && mtd->writesize > 512) {
1735 ecc->size = 1024;
1736 ecc->strength *= 2;
1737 }
1738
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001739 /* Add ECC info retrieval from DT */
1740 for (i = 0; i < ARRAY_SIZE(strengths); i++) {
Miquel Raynalf4c6cd12018-01-24 23:49:31 +01001741 if (ecc->strength <= strengths[i]) {
1742 /*
1743 * Update ecc->strength value with the actual strength
1744 * that will be used by the ECC engine.
1745 */
1746 ecc->strength = strengths[i];
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001747 break;
Miquel Raynalf4c6cd12018-01-24 23:49:31 +01001748 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001749 }
1750
1751 if (i >= ARRAY_SIZE(strengths)) {
1752 dev_err(nfc->dev, "unsupported strength\n");
1753 ret = -ENOTSUPP;
1754 goto err;
1755 }
1756
1757 data->mode = i;
1758
1759 /* HW ECC always request ECC bytes for 1024 bytes blocks */
1760 ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
1761
1762 /* HW ECC always work with even numbers of ECC bytes */
1763 ecc->bytes = ALIGN(ecc->bytes, 2);
1764
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001765 nsectors = mtd->writesize / ecc->size;
1766
1767 if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
1768 ret = -EINVAL;
1769 goto err;
1770 }
1771
Boris Brezillon15d6f112018-03-21 09:36:18 +01001772 ecc->read_oob = sunxi_nfc_hw_ecc_read_oob;
1773 ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
Boris Brezillonc66811e2016-02-03 20:05:13 +01001774 mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001775 ecc->priv = data;
1776
Boris Brezillon614049a2016-04-15 15:10:30 +02001777 if (nfc->dmac) {
1778 ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
1779 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
1780 ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
1781 nand->options |= NAND_USE_BOUNCE_BUFFER;
1782 } else {
1783 ecc->read_page = sunxi_nfc_hw_ecc_read_page;
1784 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
1785 ecc->write_page = sunxi_nfc_hw_ecc_write_page;
1786 }
1787
Boris Brezillon03b1d112016-06-06 13:59:14 +02001788 /* TODO: support DMA for raw accesses and subpage write */
1789 ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001790 ecc->read_oob_raw = nand_read_oob_std;
1791 ecc->write_oob_raw = nand_write_oob_std;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001792
1793 return 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001794
Boris Brezillon15d6f112018-03-21 09:36:18 +01001795err:
1796 kfree(data);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001797
Boris Brezillon15d6f112018-03-21 09:36:18 +01001798 return ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001799}
1800
1801static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
1802{
1803 switch (ecc->mode) {
1804 case NAND_ECC_HW:
Boris Brezillon15d6f112018-03-21 09:36:18 +01001805 sunxi_nand_hw_ecc_ctrl_cleanup(ecc);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001806 break;
1807 case NAND_ECC_NONE:
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001808 default:
1809 break;
1810 }
1811}
1812
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001813static int sunxi_nand_attach_chip(struct nand_chip *nand)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001814{
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001815 struct mtd_info *mtd = nand_to_mtd(nand);
1816 struct nand_ecc_ctrl *ecc = &nand->ecc;
1817 struct device_node *np = nand_get_flash_node(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001818 int ret;
1819
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001820 if (nand->bbt_options & NAND_BBT_USE_FLASH)
1821 nand->bbt_options |= NAND_BBT_NO_OOB;
1822
1823 if (nand->options & NAND_NEED_SCRAMBLING)
1824 nand->options |= NAND_NO_SUBPAGE_WRITE;
1825
1826 nand->options |= NAND_SUBPAGE_READ;
1827
Boris BREZILLONa3d22a52015-09-02 10:30:25 +02001828 if (!ecc->size) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001829 ecc->size = nand->ecc_step_ds;
1830 ecc->strength = nand->ecc_strength_ds;
1831 }
1832
1833 if (!ecc->size || !ecc->strength)
1834 return -EINVAL;
1835
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001836 switch (ecc->mode) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001837 case NAND_ECC_HW:
1838 ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
1839 if (ret)
1840 return ret;
1841 break;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001842 case NAND_ECC_NONE:
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001843 case NAND_ECC_SOFT:
1844 break;
1845 default:
1846 return -EINVAL;
1847 }
1848
1849 return 0;
1850}
1851
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001852static const struct nand_controller_ops sunxi_nand_controller_ops = {
1853 .attach_chip = sunxi_nand_attach_chip,
1854};
1855
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001856static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
1857 struct device_node *np)
1858{
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001859 struct sunxi_nand_chip *chip;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001860 struct mtd_info *mtd;
1861 struct nand_chip *nand;
1862 int nsels;
1863 int ret;
1864 int i;
1865 u32 tmp;
1866
1867 if (!of_get_property(np, "reg", &nsels))
1868 return -EINVAL;
1869
1870 nsels /= sizeof(u32);
1871 if (!nsels) {
1872 dev_err(dev, "invalid reg property size\n");
1873 return -EINVAL;
1874 }
1875
1876 chip = devm_kzalloc(dev,
1877 sizeof(*chip) +
1878 (nsels * sizeof(struct sunxi_nand_chip_sel)),
1879 GFP_KERNEL);
1880 if (!chip) {
1881 dev_err(dev, "could not allocate chip\n");
1882 return -ENOMEM;
1883 }
1884
1885 chip->nsels = nsels;
1886 chip->selected = -1;
1887
1888 for (i = 0; i < nsels; i++) {
1889 ret = of_property_read_u32_index(np, "reg", i, &tmp);
1890 if (ret) {
1891 dev_err(dev, "could not retrieve reg property: %d\n",
1892 ret);
1893 return ret;
1894 }
1895
1896 if (tmp > NFC_MAX_CS) {
1897 dev_err(dev,
1898 "invalid reg value: %u (max CS = 7)\n",
1899 tmp);
1900 return -EINVAL;
1901 }
1902
1903 if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
1904 dev_err(dev, "CS %d already assigned\n", tmp);
1905 return -EINVAL;
1906 }
1907
1908 chip->sels[i].cs = tmp;
1909
1910 if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
Boris Brezillonddd5ed32018-03-27 09:06:14 +02001911 tmp < 2)
1912 chip->sels[i].rb = tmp;
1913 else
1914 chip->sels[i].rb = -1;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001915 }
1916
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001917 nand = &chip->nand;
1918 /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
1919 nand->chip_delay = 200;
1920 nand->controller = &nfc->controller;
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001921 nand->controller->ops = &sunxi_nand_controller_ops;
1922
Boris BREZILLONa3d22a52015-09-02 10:30:25 +02001923 /*
1924 * Set the ECC mode to the default value in case nothing is specified
1925 * in the DT.
1926 */
1927 nand->ecc.mode = NAND_ECC_HW;
Brian Norris63752192015-10-30 20:33:23 -07001928 nand_set_flash_node(nand, np);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001929 nand->select_chip = sunxi_nfc_select_chip;
1930 nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
1931 nand->read_buf = sunxi_nfc_read_buf;
1932 nand->write_buf = sunxi_nfc_write_buf;
1933 nand->read_byte = sunxi_nfc_read_byte;
Sascha Hauer907f45f2016-09-15 10:32:51 +02001934 nand->setup_data_interface = sunxi_nfc_setup_data_interface;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001935
Boris BREZILLON32e9f2d2015-12-10 09:00:26 +01001936 mtd = nand_to_mtd(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001937 mtd->dev.parent = dev;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001938
Boris Brezillon00ad3782018-09-06 14:05:14 +02001939 ret = nand_scan(nand, nsels);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001940 if (ret)
1941 return ret;
1942
Brian Norrisa61ae812015-10-30 20:33:25 -07001943 ret = mtd_device_register(mtd, NULL, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001944 if (ret) {
1945 dev_err(dev, "failed to register mtd device: %d\n", ret);
Boris Brezillon59ac2762018-09-06 14:05:15 +02001946 nand_release(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001947 return ret;
1948 }
1949
1950 list_add_tail(&chip->node, &nfc->chips);
1951
1952 return 0;
1953}
1954
1955static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
1956{
1957 struct device_node *np = dev->of_node;
1958 struct device_node *nand_np;
1959 int nchips = of_get_child_count(np);
1960 int ret;
1961
1962 if (nchips > 8) {
1963 dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
1964 return -EINVAL;
1965 }
1966
1967 for_each_child_of_node(np, nand_np) {
1968 ret = sunxi_nand_chip_init(dev, nfc, nand_np);
Julia Lawalla81c0f02015-11-18 23:04:12 +01001969 if (ret) {
1970 of_node_put(nand_np);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001971 return ret;
Julia Lawalla81c0f02015-11-18 23:04:12 +01001972 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001973 }
1974
1975 return 0;
1976}
1977
1978static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
1979{
1980 struct sunxi_nand_chip *chip;
1981
1982 while (!list_empty(&nfc->chips)) {
1983 chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
1984 node);
Boris Brezillon59ac2762018-09-06 14:05:15 +02001985 nand_release(&chip->nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001986 sunxi_nand_ecc_cleanup(&chip->nand.ecc);
Boris BREZILLON8e375cc2015-09-13 18:14:43 +02001987 list_del(&chip->node);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001988 }
1989}
1990
1991static int sunxi_nfc_probe(struct platform_device *pdev)
1992{
1993 struct device *dev = &pdev->dev;
1994 struct resource *r;
1995 struct sunxi_nfc *nfc;
1996 int irq;
1997 int ret;
1998
1999 nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
2000 if (!nfc)
2001 return -ENOMEM;
2002
2003 nfc->dev = dev;
Miquel Raynal7da45132018-07-17 09:08:02 +02002004 nand_controller_init(&nfc->controller);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002005 INIT_LIST_HEAD(&nfc->chips);
2006
2007 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2008 nfc->regs = devm_ioremap_resource(dev, r);
2009 if (IS_ERR(nfc->regs))
2010 return PTR_ERR(nfc->regs);
2011
2012 irq = platform_get_irq(pdev, 0);
2013 if (irq < 0) {
2014 dev_err(dev, "failed to retrieve irq\n");
2015 return irq;
2016 }
2017
2018 nfc->ahb_clk = devm_clk_get(dev, "ahb");
2019 if (IS_ERR(nfc->ahb_clk)) {
2020 dev_err(dev, "failed to retrieve ahb clk\n");
2021 return PTR_ERR(nfc->ahb_clk);
2022 }
2023
2024 ret = clk_prepare_enable(nfc->ahb_clk);
2025 if (ret)
2026 return ret;
2027
2028 nfc->mod_clk = devm_clk_get(dev, "mod");
2029 if (IS_ERR(nfc->mod_clk)) {
2030 dev_err(dev, "failed to retrieve mod clk\n");
2031 ret = PTR_ERR(nfc->mod_clk);
2032 goto out_ahb_clk_unprepare;
2033 }
2034
2035 ret = clk_prepare_enable(nfc->mod_clk);
2036 if (ret)
2037 goto out_ahb_clk_unprepare;
2038
Philipp Zabelfcf59f12017-07-19 17:25:46 +02002039 nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002040 if (IS_ERR(nfc->reset)) {
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002041 ret = PTR_ERR(nfc->reset);
2042 goto out_mod_clk_unprepare;
2043 }
2044
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002045 ret = reset_control_deassert(nfc->reset);
2046 if (ret) {
2047 dev_err(dev, "reset err %d\n", ret);
2048 goto out_mod_clk_unprepare;
2049 }
2050
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002051 ret = sunxi_nfc_rst(nfc);
2052 if (ret)
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002053 goto out_ahb_reset_reassert;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002054
2055 writel(0, nfc->regs + NFC_REG_INT);
2056 ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
2057 0, "sunxi-nand", nfc);
2058 if (ret)
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002059 goto out_ahb_reset_reassert;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002060
Boris Brezillon614049a2016-04-15 15:10:30 +02002061 nfc->dmac = dma_request_slave_channel(dev, "rxtx");
2062 if (nfc->dmac) {
2063 struct dma_slave_config dmac_cfg = { };
2064
2065 dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
2066 dmac_cfg.dst_addr = dmac_cfg.src_addr;
2067 dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2068 dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
2069 dmac_cfg.src_maxburst = 4;
2070 dmac_cfg.dst_maxburst = 4;
2071 dmaengine_slave_config(nfc->dmac, &dmac_cfg);
2072 } else {
2073 dev_warn(dev, "failed to request rxtx DMA channel\n");
2074 }
2075
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002076 platform_set_drvdata(pdev, nfc);
2077
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002078 ret = sunxi_nand_chips_init(dev, nfc);
2079 if (ret) {
2080 dev_err(dev, "failed to init nand chips\n");
Boris Brezillon614049a2016-04-15 15:10:30 +02002081 goto out_release_dmac;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002082 }
2083
2084 return 0;
2085
Boris Brezillon614049a2016-04-15 15:10:30 +02002086out_release_dmac:
2087 if (nfc->dmac)
2088 dma_release_channel(nfc->dmac);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002089out_ahb_reset_reassert:
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002090 reset_control_assert(nfc->reset);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002091out_mod_clk_unprepare:
2092 clk_disable_unprepare(nfc->mod_clk);
2093out_ahb_clk_unprepare:
2094 clk_disable_unprepare(nfc->ahb_clk);
2095
2096 return ret;
2097}
2098
2099static int sunxi_nfc_remove(struct platform_device *pdev)
2100{
2101 struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
2102
2103 sunxi_nand_chips_cleanup(nfc);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002104
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002105 reset_control_assert(nfc->reset);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002106
Boris Brezillon614049a2016-04-15 15:10:30 +02002107 if (nfc->dmac)
2108 dma_release_channel(nfc->dmac);
Boris Brezillondd26a452016-03-04 18:26:40 +01002109 clk_disable_unprepare(nfc->mod_clk);
2110 clk_disable_unprepare(nfc->ahb_clk);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002111
2112 return 0;
2113}
2114
2115static const struct of_device_id sunxi_nfc_ids[] = {
2116 { .compatible = "allwinner,sun4i-a10-nand" },
2117 { /* sentinel */ }
2118};
2119MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
2120
2121static struct platform_driver sunxi_nfc_driver = {
2122 .driver = {
2123 .name = "sunxi_nand",
2124 .of_match_table = sunxi_nfc_ids,
2125 },
2126 .probe = sunxi_nfc_probe,
2127 .remove = sunxi_nfc_remove,
2128};
2129module_platform_driver(sunxi_nfc_driver);
2130
2131MODULE_LICENSE("GPL v2");
2132MODULE_AUTHOR("Boris BREZILLON");
2133MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
2134MODULE_ALIAS("platform:sunxi_nand");