blob: 80d9d2f8f5de634bdfd12457f582c7a0fd75fedf [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
Boris Brezillonc0739d82018-09-06 14:05:23 +0200504static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200505 int len)
506{
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200507 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
508 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
509 int ret;
510 int cnt;
511 int offs = 0;
512 u32 tmp;
513
514 while (len > offs) {
Boris Brezillon8de15e12017-01-06 10:42:06 +0100515 bool poll = false;
516
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200517 cnt = min(len - offs, NFC_SRAM_SIZE);
518
519 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
520 if (ret)
521 break;
522
523 writel(cnt, nfc->regs + NFC_REG_CNT);
524 memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
525 tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
526 NFC_ACCESS_DIR;
527 writel(tmp, nfc->regs + NFC_REG_CMD);
528
Boris Brezillon8de15e12017-01-06 10:42:06 +0100529 /* Arbitrary limit for polling mode */
530 if (cnt < 64)
531 poll = true;
532
533 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200534 if (ret)
535 break;
536
537 offs += cnt;
538 }
539}
540
Boris Brezillon7e534322018-09-06 14:05:22 +0200541static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200542{
Boris Brezillon06c8b5d2018-07-09 22:09:32 +0200543 uint8_t ret = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200544
Boris Brezillon7e534322018-09-06 14:05:22 +0200545 sunxi_nfc_read_buf(nand, &ret, 1);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200546
547 return ret;
548}
549
550static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
551 unsigned int ctrl)
552{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100553 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200554 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
555 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
556 int ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200557
Boris Brezillone9aa6712015-09-16 09:05:31 +0200558 if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
559 !(ctrl & (NAND_CLE | NAND_ALE))) {
560 u32 cmd = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200561
Boris Brezillone9aa6712015-09-16 09:05:31 +0200562 if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
563 return;
564
565 if (sunxi_nand->cmd_cycles--)
566 cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
567
568 if (sunxi_nand->cmd_cycles--) {
569 cmd |= NFC_SEND_CMD2;
570 writel(sunxi_nand->cmd[1],
571 nfc->regs + NFC_REG_RCMD_SET);
572 }
573
574 sunxi_nand->cmd_cycles = 0;
575
576 if (sunxi_nand->addr_cycles) {
577 cmd |= NFC_SEND_ADR |
578 NFC_ADR_NUM(sunxi_nand->addr_cycles);
579 writel(sunxi_nand->addr[0],
580 nfc->regs + NFC_REG_ADDR_LOW);
581 }
582
583 if (sunxi_nand->addr_cycles > 4)
584 writel(sunxi_nand->addr[1],
585 nfc->regs + NFC_REG_ADDR_HIGH);
586
Boris Brezilloncad32742017-01-06 10:42:07 +0100587 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
588 if (ret)
589 return;
590
Boris Brezillone9aa6712015-09-16 09:05:31 +0200591 writel(cmd, nfc->regs + NFC_REG_CMD);
592 sunxi_nand->addr[0] = 0;
593 sunxi_nand->addr[1] = 0;
594 sunxi_nand->addr_cycles = 0;
Boris Brezillonc0c9dfa2016-03-07 15:34:39 +0100595 sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200596 }
597
Boris Brezillone9aa6712015-09-16 09:05:31 +0200598 if (ctrl & NAND_CLE) {
599 sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
600 } else if (ctrl & NAND_ALE) {
601 sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
602 dat << ((sunxi_nand->addr_cycles % 4) * 8);
603 sunxi_nand->addr_cycles++;
604 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +0200605}
606
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100607/* These seed values have been extracted from Allwinner's BSP */
608static const u16 sunxi_nfc_randomizer_page_seeds[] = {
609 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
610 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
611 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
612 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
613 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
614 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
615 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
616 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
617 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
618 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
619 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
620 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
621 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
622 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
623 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
624 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
625};
626
627/*
628 * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
629 * have been generated using
630 * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
631 * the randomizer engine does internally before de/scrambling OOB data.
632 *
633 * Those tables are statically defined to avoid calculating randomizer state
634 * at runtime.
635 */
636static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
637 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
638 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
639 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
640 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
641 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
642 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
643 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
644 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
645 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
646 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
647 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
648 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
649 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
650 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
651 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
652 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
653};
654
655static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
656 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
657 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
658 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
659 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
660 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
661 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
662 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
663 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
664 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
665 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
666 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
667 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
668 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
669 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
670 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
671 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
672};
673
674static u16 sunxi_nfc_randomizer_step(u16 state, int count)
675{
676 state &= 0x7fff;
677
678 /*
679 * This loop is just a simple implementation of a Fibonacci LFSR using
680 * the x16 + x15 + 1 polynomial.
681 */
682 while (count--)
683 state = ((state >> 1) |
684 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
685
686 return state;
687}
688
689static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
690{
691 const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
Brian Norris46c135c2016-01-22 18:57:13 -0800692 int mod = mtd_div_by_ws(mtd->erasesize, mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100693
694 if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
695 mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
696
697 if (ecc) {
698 if (mtd->ecc_step_size == 512)
699 seeds = sunxi_nfc_randomizer_ecc512_seeds;
700 else
701 seeds = sunxi_nfc_randomizer_ecc1024_seeds;
702 }
703
704 return seeds[page % mod];
705}
706
707static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
708 int page, bool ecc)
709{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100710 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100711 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
712 u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
713 u16 state;
714
715 if (!(nand->options & NAND_NEED_SCRAMBLING))
716 return;
717
718 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
719 state = sunxi_nfc_randomizer_state(mtd, page, ecc);
720 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
721 writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
722}
723
724static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
725{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100726 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100727 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
728
729 if (!(nand->options & NAND_NEED_SCRAMBLING))
730 return;
731
732 writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
733 nfc->regs + NFC_REG_ECC_CTL);
734}
735
736static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
737{
Boris BREZILLONf671a1f2016-03-05 00:21:20 +0100738 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100739 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
740
741 if (!(nand->options & NAND_NEED_SCRAMBLING))
742 return;
743
744 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
745 nfc->regs + NFC_REG_ECC_CTL);
746}
747
748static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
749{
750 u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
751
752 bbm[0] ^= state;
753 bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
754}
755
756static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
757 const uint8_t *buf, int len,
758 bool ecc, int page)
759{
760 sunxi_nfc_randomizer_config(mtd, page, ecc);
761 sunxi_nfc_randomizer_enable(mtd);
Boris Brezillonc0739d82018-09-06 14:05:23 +0200762 sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100763 sunxi_nfc_randomizer_disable(mtd);
764}
765
766static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
767 int len, bool ecc, int page)
768{
769 sunxi_nfc_randomizer_config(mtd, page, ecc);
770 sunxi_nfc_randomizer_enable(mtd);
Boris Brezillon7e534322018-09-06 14:05:22 +0200771 sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100772 sunxi_nfc_randomizer_disable(mtd);
773}
774
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200775static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
776{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100777 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200778 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
779 struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
780 u32 ecc_ctl;
781
782 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
783 ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
784 NFC_ECC_BLOCK_SIZE_MSK);
Boris Brezillon336de7b2016-03-04 17:33:10 +0100785 ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
786 NFC_ECC_PIPELINE;
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200787
Boris Brezillonf59dab82016-10-20 10:12:42 +0200788 if (nand->ecc.size == 512)
789 ecc_ctl |= NFC_ECC_BLOCK_512;
790
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200791 writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
792}
793
794static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
795{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100796 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLONc9118ec2015-09-30 23:45:23 +0200797 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
798
799 writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
800 nfc->regs + NFC_REG_ECC_CTL);
801}
802
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200803static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
804{
805 buf[0] = user_data;
806 buf[1] = user_data >> 8;
807 buf[2] = user_data >> 16;
808 buf[3] = user_data >> 24;
809}
810
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100811static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
812{
813 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
814}
815
816static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
817 int step, bool bbm, int page)
818{
819 struct nand_chip *nand = mtd_to_nand(mtd);
820 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
821
822 sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
823 oob);
824
825 /* De-randomize the Bad Block Marker. */
826 if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
827 sunxi_nfc_randomize_bbm(mtd, page, oob);
828}
829
830static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
831 const u8 *oob, int step,
832 bool bbm, int page)
833{
834 struct nand_chip *nand = mtd_to_nand(mtd);
835 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
836 u8 user_data[4];
837
838 /* Randomize the Bad Block Marker. */
839 if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
840 memcpy(user_data, oob, sizeof(user_data));
841 sunxi_nfc_randomize_bbm(mtd, page, user_data);
842 oob = user_data;
843 }
844
845 writel(sunxi_nfc_buf_to_user_data(oob),
846 nfc->regs + NFC_REG_USER_DATA(step));
847}
848
849static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
850 unsigned int *max_bitflips, int ret)
851{
852 if (ret < 0) {
853 mtd->ecc_stats.failed++;
854 } else {
855 mtd->ecc_stats.corrected += ret;
856 *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
857 }
858}
859
860static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
Boris Brezillon614049a2016-04-15 15:10:30 +0200861 int step, u32 status, bool *erased)
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100862{
863 struct nand_chip *nand = mtd_to_nand(mtd);
864 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
865 struct nand_ecc_ctrl *ecc = &nand->ecc;
Boris Brezillon614049a2016-04-15 15:10:30 +0200866 u32 tmp;
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100867
868 *erased = false;
869
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100870 if (status & NFC_ECC_ERR(step))
871 return -EBADMSG;
872
873 if (status & NFC_ECC_PAT_FOUND(step)) {
874 u8 pattern;
875
876 if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
877 pattern = 0x0;
878 } else {
879 pattern = 0xff;
880 *erased = true;
881 }
882
883 if (data)
884 memset(data, pattern, ecc->size);
885
886 if (oob)
887 memset(oob, pattern, ecc->bytes + 4);
888
889 return 0;
890 }
891
892 tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
893
894 return NFC_ECC_ERR_CNT(step, tmp);
895}
896
Boris BREZILLON913821b2015-09-30 23:45:24 +0200897static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
898 u8 *data, int data_off,
899 u8 *oob, int oob_off,
900 int *cur_off,
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100901 unsigned int *max_bitflips,
Boris Brezillon828dec12016-03-04 18:09:21 +0100902 bool bbm, bool oob_required, int page)
Boris BREZILLON913821b2015-09-30 23:45:24 +0200903{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100904 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200905 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
906 struct nand_ecc_ctrl *ecc = &nand->ecc;
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100907 int raw_mode = 0;
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100908 bool erased;
Boris BREZILLON913821b2015-09-30 23:45:24 +0200909 int ret;
910
911 if (*cur_off != data_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100912 nand_change_read_column_op(nand, data_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200913
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100914 sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200915
Boris BREZILLON74eb9ff2015-10-20 22:16:00 +0200916 if (data_off + ecc->size != oob_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100917 nand_change_read_column_op(nand, oob_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200918
919 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
920 if (ret)
921 return ret;
922
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100923 sunxi_nfc_randomizer_enable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200924 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
925 nfc->regs + NFC_REG_CMD);
926
Boris Brezillon8de15e12017-01-06 10:42:06 +0100927 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100928 sunxi_nfc_randomizer_disable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200929 if (ret)
930 return ret;
931
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100932 *cur_off = oob_off + ecc->bytes + 4;
933
Boris Brezillon828dec12016-03-04 18:09:21 +0100934 ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
Boris Brezillon614049a2016-04-15 15:10:30 +0200935 readl(nfc->regs + NFC_REG_ECC_ST),
Boris Brezillon828dec12016-03-04 18:09:21 +0100936 &erased);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100937 if (erased)
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100938 return 1;
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100939
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100940 if (ret < 0) {
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100941 /*
942 * Re-read the data with the randomizer disabled to identify
943 * bitflips in erased pages.
944 */
Boris Brezillon97d90da2017-11-30 18:01:29 +0100945 if (nand->options & NAND_NEED_SCRAMBLING)
946 nand_change_read_column_op(nand, data_off, data,
947 ecc->size, false);
948 else
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100949 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
950 ecc->size);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100951
Boris Brezillon97d90da2017-11-30 18:01:29 +0100952 nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
953 false);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100954
Boris BREZILLON146b5032015-09-30 23:45:29 +0200955 ret = nand_check_erased_ecc_chunk(data, ecc->size,
956 oob, ecc->bytes + 4,
957 NULL, 0, ecc->strength);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100958 if (ret >= 0)
959 raw_mode = 1;
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200960 } else {
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100961 memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100962
Boris Brezillon828dec12016-03-04 18:09:21 +0100963 if (oob_required) {
Boris Brezillon97d90da2017-11-30 18:01:29 +0100964 nand_change_read_column_op(nand, oob_off, NULL, 0,
965 false);
Boris Brezillon828dec12016-03-04 18:09:21 +0100966 sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
967 true, page);
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100968
Boris Brezillon828dec12016-03-04 18:09:21 +0100969 sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
970 bbm, page);
971 }
Boris BREZILLONf363e0f2015-09-30 23:45:27 +0200972 }
Boris BREZILLON913821b2015-09-30 23:45:24 +0200973
Boris Brezilloncc6822f2016-03-04 17:56:47 +0100974 sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
Boris BREZILLON913821b2015-09-30 23:45:24 +0200975
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100976 return raw_mode;
Boris BREZILLON913821b2015-09-30 23:45:24 +0200977}
978
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200979static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100980 u8 *oob, int *cur_off,
981 bool randomize, int page)
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200982{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +0100983 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200984 struct nand_ecc_ctrl *ecc = &nand->ecc;
985 int offset = ((ecc->bytes + 4) * ecc->steps);
986 int len = mtd->oobsize - offset;
987
988 if (len <= 0)
989 return;
990
Boris Brezillonc4f3ef22016-03-04 18:13:10 +0100991 if (!cur_off || *cur_off != offset)
Boris Brezillon97d90da2017-11-30 18:01:29 +0100992 nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
993 false);
Boris BREZILLON35d0e242015-09-30 23:45:26 +0200994
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100995 if (!randomize)
Boris Brezillon7e534322018-09-06 14:05:22 +0200996 sunxi_nfc_read_buf(nand, oob + offset, len);
Boris BREZILLON4be4e032015-12-02 12:01:07 +0100997 else
998 sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
999 false, page);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001000
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001001 if (cur_off)
1002 *cur_off = mtd->oobsize + mtd->writesize;
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001003}
1004
Boris Brezillon614049a2016-04-15 15:10:30 +02001005static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
1006 int oob_required, int page,
1007 int nchunks)
1008{
1009 struct nand_chip *nand = mtd_to_nand(mtd);
1010 bool randomized = nand->options & NAND_NEED_SCRAMBLING;
1011 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1012 struct nand_ecc_ctrl *ecc = &nand->ecc;
1013 unsigned int max_bitflips = 0;
1014 int ret, i, raw_mode = 0;
1015 struct scatterlist sg;
1016 u32 status;
1017
1018 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1019 if (ret)
1020 return ret;
1021
1022 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
1023 DMA_FROM_DEVICE, &sg);
1024 if (ret)
1025 return ret;
1026
1027 sunxi_nfc_hw_ecc_enable(mtd);
1028 sunxi_nfc_randomizer_config(mtd, page, false);
1029 sunxi_nfc_randomizer_enable(mtd);
1030
1031 writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
1032 NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
1033
1034 dma_async_issue_pending(nfc->dmac);
1035
1036 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
1037 nfc->regs + NFC_REG_CMD);
1038
Boris Brezillon8de15e12017-01-06 10:42:06 +01001039 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris Brezillon614049a2016-04-15 15:10:30 +02001040 if (ret)
1041 dmaengine_terminate_all(nfc->dmac);
1042
1043 sunxi_nfc_randomizer_disable(mtd);
1044 sunxi_nfc_hw_ecc_disable(mtd);
1045
1046 sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
1047
1048 if (ret)
1049 return ret;
1050
1051 status = readl(nfc->regs + NFC_REG_ECC_ST);
1052
1053 for (i = 0; i < nchunks; i++) {
1054 int data_off = i * ecc->size;
1055 int oob_off = i * (ecc->bytes + 4);
1056 u8 *data = buf + data_off;
1057 u8 *oob = nand->oob_poi + oob_off;
1058 bool erased;
1059
1060 ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
1061 oob_required ? oob : NULL,
1062 i, status, &erased);
1063
1064 /* ECC errors are handled in the second loop. */
1065 if (ret < 0)
1066 continue;
1067
1068 if (oob_required && !erased) {
1069 /* TODO: use DMA to retrieve OOB */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001070 nand_change_read_column_op(nand,
1071 mtd->writesize + oob_off,
1072 oob, ecc->bytes + 4, false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001073
1074 sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
1075 !i, page);
1076 }
1077
1078 if (erased)
1079 raw_mode = 1;
1080
1081 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1082 }
1083
1084 if (status & NFC_ECC_ERR_MSK) {
1085 for (i = 0; i < nchunks; i++) {
1086 int data_off = i * ecc->size;
1087 int oob_off = i * (ecc->bytes + 4);
1088 u8 *data = buf + data_off;
1089 u8 *oob = nand->oob_poi + oob_off;
1090
1091 if (!(status & NFC_ECC_ERR(i)))
1092 continue;
1093
1094 /*
1095 * Re-read the data with the randomizer disabled to
1096 * identify bitflips in erased pages.
Boris Brezillon97d90da2017-11-30 18:01:29 +01001097 * TODO: use DMA to read page in raw mode
Boris Brezillon614049a2016-04-15 15:10:30 +02001098 */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001099 if (randomized)
1100 nand_change_read_column_op(nand, data_off,
1101 data, ecc->size,
1102 false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001103
1104 /* TODO: use DMA to retrieve OOB */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001105 nand_change_read_column_op(nand,
1106 mtd->writesize + oob_off,
1107 oob, ecc->bytes + 4, false);
Boris Brezillon614049a2016-04-15 15:10:30 +02001108
1109 ret = nand_check_erased_ecc_chunk(data, ecc->size,
1110 oob, ecc->bytes + 4,
1111 NULL, 0,
1112 ecc->strength);
1113 if (ret >= 0)
1114 raw_mode = 1;
1115
1116 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1117 }
1118 }
1119
1120 if (oob_required)
1121 sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
1122 NULL, !raw_mode,
1123 page);
1124
1125 return max_bitflips;
1126}
1127
Boris BREZILLON913821b2015-09-30 23:45:24 +02001128static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
1129 const u8 *data, int data_off,
1130 const u8 *oob, int oob_off,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001131 int *cur_off, bool bbm,
1132 int page)
Boris BREZILLON913821b2015-09-30 23:45:24 +02001133{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001134 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001135 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1136 struct nand_ecc_ctrl *ecc = &nand->ecc;
1137 int ret;
1138
1139 if (data_off != *cur_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001140 nand_change_write_column_op(nand, data_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001141
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001142 sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001143
Boris BREZILLON74eb9ff2015-10-20 22:16:00 +02001144 if (data_off + ecc->size != oob_off)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001145 nand_change_write_column_op(nand, oob_off, NULL, 0, false);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001146
1147 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1148 if (ret)
1149 return ret;
1150
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001151 sunxi_nfc_randomizer_enable(mtd);
Boris Brezilloncc6822f2016-03-04 17:56:47 +01001152 sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
1153
Boris BREZILLON913821b2015-09-30 23:45:24 +02001154 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
1155 NFC_ACCESS_DIR | NFC_ECC_OP,
1156 nfc->regs + NFC_REG_CMD);
1157
Boris Brezillon8de15e12017-01-06 10:42:06 +01001158 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001159 sunxi_nfc_randomizer_disable(mtd);
Boris BREZILLON913821b2015-09-30 23:45:24 +02001160 if (ret)
1161 return ret;
1162
1163 *cur_off = oob_off + ecc->bytes + 4;
1164
1165 return 0;
1166}
1167
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001168static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001169 u8 *oob, int *cur_off,
1170 int page)
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001171{
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001172 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001173 struct nand_ecc_ctrl *ecc = &nand->ecc;
1174 int offset = ((ecc->bytes + 4) * ecc->steps);
1175 int len = mtd->oobsize - offset;
1176
1177 if (len <= 0)
1178 return;
1179
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001180 if (!cur_off || *cur_off != offset)
Boris Brezillon97d90da2017-11-30 18:01:29 +01001181 nand_change_write_column_op(nand, offset + mtd->writesize,
1182 NULL, 0, false);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001183
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001184 sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001185
Boris Brezillonc4f3ef22016-03-04 18:13:10 +01001186 if (cur_off)
1187 *cur_off = mtd->oobsize + mtd->writesize;
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001188}
1189
Boris Brezillonb9761682018-09-06 14:05:20 +02001190static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001191 int oob_required, int page)
1192{
Boris Brezillonb9761682018-09-06 14:05:20 +02001193 struct mtd_info *mtd = nand_to_mtd(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001194 struct nand_ecc_ctrl *ecc = &chip->ecc;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001195 unsigned int max_bitflips = 0;
Boris BREZILLONb4625512015-09-30 23:45:25 +02001196 int ret, i, cur_off = 0;
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001197 bool raw_mode = false;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001198
Boris Brezillon25f815f2017-11-30 18:01:30 +01001199 nand_read_page_op(chip, page, 0, NULL, 0);
1200
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001201 sunxi_nfc_hw_ecc_enable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001202
1203 for (i = 0; i < ecc->steps; i++) {
Boris BREZILLONb4625512015-09-30 23:45:25 +02001204 int data_off = i * ecc->size;
1205 int oob_off = i * (ecc->bytes + 4);
1206 u8 *data = buf + data_off;
1207 u8 *oob = chip->oob_poi + oob_off;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001208
Boris BREZILLONb4625512015-09-30 23:45:25 +02001209 ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
1210 oob_off + mtd->writesize,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001211 &cur_off, &max_bitflips,
Boris Brezillon828dec12016-03-04 18:09:21 +01001212 !i, oob_required, page);
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001213 if (ret < 0)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001214 return ret;
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001215 else if (ret)
1216 raw_mode = true;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001217 }
1218
Boris BREZILLON35d0e242015-09-30 23:45:26 +02001219 if (oob_required)
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001220 sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
1221 !raw_mode, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001222
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001223 sunxi_nfc_hw_ecc_disable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001224
1225 return max_bitflips;
1226}
1227
Boris Brezillonb9761682018-09-06 14:05:20 +02001228static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
Boris Brezillon614049a2016-04-15 15:10:30 +02001229 int oob_required, int page)
1230{
Boris Brezillonb9761682018-09-06 14:05:20 +02001231 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001232 int ret;
1233
Boris Brezillon25f815f2017-11-30 18:01:30 +01001234 nand_read_page_op(chip, page, 0, NULL, 0);
1235
Boris Brezillon614049a2016-04-15 15:10:30 +02001236 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
1237 chip->ecc.steps);
1238 if (ret >= 0)
1239 return ret;
1240
1241 /* Fallback to PIO mode */
Boris Brezillonb9761682018-09-06 14:05:20 +02001242 return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
Boris Brezillon614049a2016-04-15 15:10:30 +02001243}
1244
Boris Brezillonb9761682018-09-06 14:05:20 +02001245static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001246 u32 data_offs, u32 readlen,
1247 u8 *bufpoi, int page)
1248{
Boris Brezillonb9761682018-09-06 14:05:20 +02001249 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001250 struct nand_ecc_ctrl *ecc = &chip->ecc;
1251 int ret, i, cur_off = 0;
1252 unsigned int max_bitflips = 0;
1253
Boris Brezillon25f815f2017-11-30 18:01:30 +01001254 nand_read_page_op(chip, page, 0, NULL, 0);
1255
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001256 sunxi_nfc_hw_ecc_enable(mtd);
1257
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001258 for (i = data_offs / ecc->size;
1259 i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
1260 int data_off = i * ecc->size;
1261 int oob_off = i * (ecc->bytes + 4);
1262 u8 *data = bufpoi + data_off;
1263 u8 *oob = chip->oob_poi + oob_off;
1264
1265 ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
1266 oob,
1267 oob_off + mtd->writesize,
Boris Brezillon828dec12016-03-04 18:09:21 +01001268 &cur_off, &max_bitflips, !i,
1269 false, page);
Boris Brezillonfe82cce2015-09-16 09:01:45 +02001270 if (ret < 0)
1271 return ret;
1272 }
1273
1274 sunxi_nfc_hw_ecc_disable(mtd);
1275
1276 return max_bitflips;
1277}
1278
Boris Brezillonb9761682018-09-06 14:05:20 +02001279static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
Boris Brezillon614049a2016-04-15 15:10:30 +02001280 u32 data_offs, u32 readlen,
1281 u8 *buf, int page)
1282{
Boris Brezillonb9761682018-09-06 14:05:20 +02001283 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001284 int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
1285 int ret;
1286
Boris Brezillon25f815f2017-11-30 18:01:30 +01001287 nand_read_page_op(chip, page, 0, NULL, 0);
1288
Boris Brezillon614049a2016-04-15 15:10:30 +02001289 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
1290 if (ret >= 0)
1291 return ret;
1292
1293 /* Fallback to PIO mode */
Boris Brezillonb9761682018-09-06 14:05:20 +02001294 return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
Boris Brezillon614049a2016-04-15 15:10:30 +02001295 buf, page);
1296}
1297
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001298static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
Boris BREZILLON45aaeff2015-10-13 11:22:18 +02001299 const uint8_t *buf, int oob_required,
1300 int page)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001301{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001302 struct mtd_info *mtd = nand_to_mtd(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001303 struct nand_ecc_ctrl *ecc = &chip->ecc;
Boris BREZILLONb4625512015-09-30 23:45:25 +02001304 int ret, i, cur_off = 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001305
Boris Brezillon25f815f2017-11-30 18:01:30 +01001306 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1307
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001308 sunxi_nfc_hw_ecc_enable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001309
1310 for (i = 0; i < ecc->steps; i++) {
Boris BREZILLONb4625512015-09-30 23:45:25 +02001311 int data_off = i * ecc->size;
1312 int oob_off = i * (ecc->bytes + 4);
1313 const u8 *data = buf + data_off;
1314 const u8 *oob = chip->oob_poi + oob_off;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001315
Boris BREZILLONb4625512015-09-30 23:45:25 +02001316 ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
1317 oob_off + mtd->writesize,
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001318 &cur_off, !i, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001319 if (ret)
1320 return ret;
1321 }
1322
Boris BREZILLON4be4e032015-12-02 12:01:07 +01001323 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
1324 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
1325 &cur_off, page);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001326
Boris BREZILLONc9118ec2015-09-30 23:45:23 +02001327 sunxi_nfc_hw_ecc_disable(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001328
Boris Brezillon25f815f2017-11-30 18:01:30 +01001329 return nand_prog_page_end_op(chip);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001330}
1331
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001332static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
Boris Brezillon03b1d112016-06-06 13:59:14 +02001333 u32 data_offs, u32 data_len,
1334 const u8 *buf, int oob_required,
1335 int page)
1336{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001337 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon03b1d112016-06-06 13:59:14 +02001338 struct nand_ecc_ctrl *ecc = &chip->ecc;
1339 int ret, i, cur_off = 0;
1340
Boris Brezillon25f815f2017-11-30 18:01:30 +01001341 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1342
Boris Brezillon03b1d112016-06-06 13:59:14 +02001343 sunxi_nfc_hw_ecc_enable(mtd);
1344
1345 for (i = data_offs / ecc->size;
1346 i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
1347 int data_off = i * ecc->size;
1348 int oob_off = i * (ecc->bytes + 4);
1349 const u8 *data = buf + data_off;
1350 const u8 *oob = chip->oob_poi + oob_off;
1351
1352 ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
1353 oob_off + mtd->writesize,
1354 &cur_off, !i, page);
1355 if (ret)
1356 return ret;
1357 }
1358
1359 sunxi_nfc_hw_ecc_disable(mtd);
1360
Boris Brezillon25f815f2017-11-30 18:01:30 +01001361 return nand_prog_page_end_op(chip);
Boris Brezillon03b1d112016-06-06 13:59:14 +02001362}
1363
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001364static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
Boris Brezillon614049a2016-04-15 15:10:30 +02001365 const u8 *buf,
1366 int oob_required,
1367 int page)
1368{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001369 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001370 struct nand_chip *nand = mtd_to_nand(mtd);
1371 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1372 struct nand_ecc_ctrl *ecc = &nand->ecc;
1373 struct scatterlist sg;
1374 int ret, i;
1375
1376 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1377 if (ret)
1378 return ret;
1379
1380 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
1381 DMA_TO_DEVICE, &sg);
1382 if (ret)
1383 goto pio_fallback;
1384
1385 for (i = 0; i < ecc->steps; i++) {
1386 const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
1387
1388 sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
1389 }
1390
Boris Brezillon25f815f2017-11-30 18:01:30 +01001391 nand_prog_page_begin_op(chip, page, 0, NULL, 0);
1392
Boris Brezillon614049a2016-04-15 15:10:30 +02001393 sunxi_nfc_hw_ecc_enable(mtd);
1394 sunxi_nfc_randomizer_config(mtd, page, false);
1395 sunxi_nfc_randomizer_enable(mtd);
1396
1397 writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
1398 nfc->regs + NFC_REG_RCMD_SET);
1399
1400 dma_async_issue_pending(nfc->dmac);
1401
1402 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
1403 NFC_DATA_TRANS | NFC_ACCESS_DIR,
1404 nfc->regs + NFC_REG_CMD);
1405
Boris Brezillon8de15e12017-01-06 10:42:06 +01001406 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
Boris Brezillon614049a2016-04-15 15:10:30 +02001407 if (ret)
1408 dmaengine_terminate_all(nfc->dmac);
1409
1410 sunxi_nfc_randomizer_disable(mtd);
1411 sunxi_nfc_hw_ecc_disable(mtd);
1412
1413 sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
1414
1415 if (ret)
1416 return ret;
1417
1418 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
1419 /* TODO: use DMA to transfer extra OOB bytes ? */
1420 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
1421 NULL, page);
1422
Boris Brezillon25f815f2017-11-30 18:01:30 +01001423 return nand_prog_page_end_op(chip);
Boris Brezillon614049a2016-04-15 15:10:30 +02001424
1425pio_fallback:
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001426 return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
Boris Brezillon614049a2016-04-15 15:10:30 +02001427}
1428
Boris Brezillonb9761682018-09-06 14:05:20 +02001429static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001430{
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001431 chip->pagebuf = -1;
1432
Boris Brezillonb9761682018-09-06 14:05:20 +02001433 return chip->ecc.read_page(chip, chip->data_buf, 1, page);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001434}
1435
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001436static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001437{
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001438 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon97d90da2017-11-30 18:01:29 +01001439 int ret;
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001440
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001441 chip->pagebuf = -1;
1442
Masahiro Yamadac0313b92017-12-05 17:47:16 +09001443 memset(chip->data_buf, 0xff, mtd->writesize);
Boris Brezillon767eb6f2018-09-06 14:05:21 +02001444 ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001445 if (ret)
1446 return ret;
1447
1448 /* Send command to program the OOB data */
Boris Brezillon97d90da2017-11-30 18:01:29 +01001449 return nand_prog_page_end_op(chip);
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001450}
1451
Roy Spliet9c618292015-06-26 11:00:10 +02001452static const s32 tWB_lut[] = {6, 12, 16, 20};
1453static const s32 tRHW_lut[] = {4, 8, 12, 20};
1454
1455static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
1456 u32 clk_period)
1457{
1458 u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
1459 int i;
1460
1461 for (i = 0; i < lut_size; i++) {
1462 if (clk_cycles <= lut[i])
1463 return i;
1464 }
1465
1466 /* Doesn't fit */
1467 return -EINVAL;
1468}
1469
1470#define sunxi_nand_lookup_timing(l, p, c) \
1471 _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
1472
Boris Brezillon104e4422017-03-16 09:35:58 +01001473static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
1474 const struct nand_data_interface *conf)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001475{
Sascha Hauer907f45f2016-09-15 10:32:51 +02001476 struct nand_chip *nand = mtd_to_nand(mtd);
1477 struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
Roy Spliet9c618292015-06-26 11:00:10 +02001478 struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
Sascha Hauer907f45f2016-09-15 10:32:51 +02001479 const struct nand_sdr_timings *timings;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001480 u32 min_clk_period = 0;
Roy Spliet9c618292015-06-26 11:00:10 +02001481 s32 tWB, tADL, tWHR, tRHW, tCAD;
Boris Brezillon2d434572015-12-02 15:57:20 +01001482 long real_clk_rate;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001483
Sascha Hauer907f45f2016-09-15 10:32:51 +02001484 timings = nand_get_sdr_timings(conf);
1485 if (IS_ERR(timings))
1486 return -ENOTSUPP;
1487
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001488 /* T1 <=> tCLS */
1489 if (timings->tCLS_min > min_clk_period)
1490 min_clk_period = timings->tCLS_min;
1491
1492 /* T2 <=> tCLH */
1493 if (timings->tCLH_min > min_clk_period)
1494 min_clk_period = timings->tCLH_min;
1495
1496 /* T3 <=> tCS */
1497 if (timings->tCS_min > min_clk_period)
1498 min_clk_period = timings->tCS_min;
1499
1500 /* T4 <=> tCH */
1501 if (timings->tCH_min > min_clk_period)
1502 min_clk_period = timings->tCH_min;
1503
1504 /* T5 <=> tWP */
1505 if (timings->tWP_min > min_clk_period)
1506 min_clk_period = timings->tWP_min;
1507
1508 /* T6 <=> tWH */
1509 if (timings->tWH_min > min_clk_period)
1510 min_clk_period = timings->tWH_min;
1511
1512 /* T7 <=> tALS */
1513 if (timings->tALS_min > min_clk_period)
1514 min_clk_period = timings->tALS_min;
1515
1516 /* T8 <=> tDS */
1517 if (timings->tDS_min > min_clk_period)
1518 min_clk_period = timings->tDS_min;
1519
1520 /* T9 <=> tDH */
1521 if (timings->tDH_min > min_clk_period)
1522 min_clk_period = timings->tDH_min;
1523
1524 /* T10 <=> tRR */
1525 if (timings->tRR_min > (min_clk_period * 3))
1526 min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
1527
1528 /* T11 <=> tALH */
1529 if (timings->tALH_min > min_clk_period)
1530 min_clk_period = timings->tALH_min;
1531
1532 /* T12 <=> tRP */
1533 if (timings->tRP_min > min_clk_period)
1534 min_clk_period = timings->tRP_min;
1535
1536 /* T13 <=> tREH */
1537 if (timings->tREH_min > min_clk_period)
1538 min_clk_period = timings->tREH_min;
1539
1540 /* T14 <=> tRC */
1541 if (timings->tRC_min > (min_clk_period * 2))
1542 min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
1543
1544 /* T15 <=> tWC */
1545 if (timings->tWC_min > (min_clk_period * 2))
1546 min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
1547
Roy Spliet9c618292015-06-26 11:00:10 +02001548 /* T16 - T19 + tCAD */
Boris Brezillon5abcd952015-11-11 22:30:30 +01001549 if (timings->tWB_max > (min_clk_period * 20))
1550 min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
1551
1552 if (timings->tADL_min > (min_clk_period * 32))
1553 min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
1554
1555 if (timings->tWHR_min > (min_clk_period * 32))
1556 min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
1557
1558 if (timings->tRHW_min > (min_clk_period * 20))
1559 min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
1560
Roy Spliet9c618292015-06-26 11:00:10 +02001561 tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
1562 min_clk_period);
1563 if (tWB < 0) {
1564 dev_err(nfc->dev, "unsupported tWB\n");
1565 return tWB;
1566 }
1567
1568 tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
1569 if (tADL > 3) {
1570 dev_err(nfc->dev, "unsupported tADL\n");
1571 return -EINVAL;
1572 }
1573
1574 tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
1575 if (tWHR > 3) {
1576 dev_err(nfc->dev, "unsupported tWHR\n");
1577 return -EINVAL;
1578 }
1579
1580 tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
1581 min_clk_period);
1582 if (tRHW < 0) {
1583 dev_err(nfc->dev, "unsupported tRHW\n");
1584 return tRHW;
1585 }
1586
Boris Brezillon104e4422017-03-16 09:35:58 +01001587 if (csline == NAND_DATA_IFACE_CHECK_ONLY)
Sascha Hauer907f45f2016-09-15 10:32:51 +02001588 return 0;
1589
Roy Spliet9c618292015-06-26 11:00:10 +02001590 /*
1591 * TODO: according to ONFI specs this value only applies for DDR NAND,
1592 * but Allwinner seems to set this to 0x7. Mimic them for now.
1593 */
1594 tCAD = 0x7;
1595
1596 /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
1597 chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001598
1599 /* Convert min_clk_period from picoseconds to nanoseconds */
1600 min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
1601
1602 /*
Boris Brezillon2f9992e2015-12-02 15:10:40 +01001603 * Unlike what is stated in Allwinner datasheet, the clk_rate should
1604 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
1605 * This new formula was verified with a scope and validated by
1606 * Allwinner engineers.
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001607 */
Boris Brezillon2f9992e2015-12-02 15:10:40 +01001608 chip->clk_rate = NSEC_PER_SEC / min_clk_period;
Boris Brezillon2d434572015-12-02 15:57:20 +01001609 real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
Bryan O'Donoghue791eccd2017-07-28 14:22:57 +01001610 if (real_clk_rate <= 0) {
1611 dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
1612 return -EINVAL;
1613 }
Boris Brezillon2d434572015-12-02 15:57:20 +01001614
1615 /*
1616 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
1617 * output cycle timings shall be used if the host drives tRC less than
1618 * 30 ns.
1619 */
1620 min_clk_period = NSEC_PER_SEC / real_clk_rate;
1621 chip->timing_ctl = ((min_clk_period * 2) < 30) ?
1622 NFC_TIMING_CTL_EDO : 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001623
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001624 return 0;
1625}
1626
Boris Brezillonc66811e2016-02-03 20:05:13 +01001627static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
1628 struct mtd_oob_region *oobregion)
1629{
1630 struct nand_chip *nand = mtd_to_nand(mtd);
1631 struct nand_ecc_ctrl *ecc = &nand->ecc;
1632
1633 if (section >= ecc->steps)
1634 return -ERANGE;
1635
1636 oobregion->offset = section * (ecc->bytes + 4) + 4;
1637 oobregion->length = ecc->bytes;
1638
1639 return 0;
1640}
1641
1642static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
1643 struct mtd_oob_region *oobregion)
1644{
1645 struct nand_chip *nand = mtd_to_nand(mtd);
1646 struct nand_ecc_ctrl *ecc = &nand->ecc;
1647
1648 if (section > ecc->steps)
1649 return -ERANGE;
1650
1651 /*
1652 * The first 2 bytes are used for BB markers, hence we
1653 * only have 2 bytes available in the first user data
1654 * section.
1655 */
1656 if (!section && ecc->mode == NAND_ECC_HW) {
1657 oobregion->offset = 2;
1658 oobregion->length = 2;
1659
1660 return 0;
1661 }
1662
1663 oobregion->offset = section * (ecc->bytes + 4);
1664
1665 if (section < ecc->steps)
1666 oobregion->length = 4;
1667 else
1668 oobregion->offset = mtd->oobsize - oobregion->offset;
1669
1670 return 0;
1671}
1672
1673static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
1674 .ecc = sunxi_nand_ooblayout_ecc,
1675 .free = sunxi_nand_ooblayout_free,
1676};
1677
Boris Brezillon15d6f112018-03-21 09:36:18 +01001678static void sunxi_nand_hw_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
1679{
1680 kfree(ecc->priv);
1681}
1682
1683static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
1684 struct nand_ecc_ctrl *ecc,
1685 struct device_node *np)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001686{
1687 static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
Boris BREZILLON4bd4ebc2015-12-01 12:03:04 +01001688 struct nand_chip *nand = mtd_to_nand(mtd);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001689 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
1690 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
1691 struct sunxi_nand_hw_ecc *data;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001692 int nsectors;
1693 int ret;
1694 int i;
1695
Boris Brezillon4796d862016-06-08 17:04:24 +02001696 if (ecc->options & NAND_ECC_MAXIMIZE) {
1697 int bytes;
1698
1699 ecc->size = 1024;
1700 nsectors = mtd->writesize / ecc->size;
1701
1702 /* Reserve 2 bytes for the BBM */
1703 bytes = (mtd->oobsize - 2) / nsectors;
1704
1705 /* 4 non-ECC bytes are added before each ECC bytes section */
1706 bytes -= 4;
1707
1708 /* and bytes has to be even. */
1709 if (bytes % 2)
1710 bytes--;
1711
1712 ecc->strength = bytes * 8 / fls(8 * ecc->size);
1713
1714 for (i = 0; i < ARRAY_SIZE(strengths); i++) {
1715 if (strengths[i] > ecc->strength)
1716 break;
1717 }
1718
1719 if (!i)
1720 ecc->strength = 0;
1721 else
1722 ecc->strength = strengths[i - 1];
1723 }
1724
Dan Carpenter40297e72016-06-24 15:24:03 +03001725 if (ecc->size != 512 && ecc->size != 1024)
1726 return -EINVAL;
1727
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001728 data = kzalloc(sizeof(*data), GFP_KERNEL);
1729 if (!data)
1730 return -ENOMEM;
1731
Boris Brezillon872164e2016-06-06 13:59:12 +02001732 /* Prefer 1k ECC chunk over 512 ones */
1733 if (ecc->size == 512 && mtd->writesize > 512) {
1734 ecc->size = 1024;
1735 ecc->strength *= 2;
1736 }
1737
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001738 /* Add ECC info retrieval from DT */
1739 for (i = 0; i < ARRAY_SIZE(strengths); i++) {
Miquel Raynalf4c6cd12018-01-24 23:49:31 +01001740 if (ecc->strength <= strengths[i]) {
1741 /*
1742 * Update ecc->strength value with the actual strength
1743 * that will be used by the ECC engine.
1744 */
1745 ecc->strength = strengths[i];
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001746 break;
Miquel Raynalf4c6cd12018-01-24 23:49:31 +01001747 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001748 }
1749
1750 if (i >= ARRAY_SIZE(strengths)) {
1751 dev_err(nfc->dev, "unsupported strength\n");
1752 ret = -ENOTSUPP;
1753 goto err;
1754 }
1755
1756 data->mode = i;
1757
1758 /* HW ECC always request ECC bytes for 1024 bytes blocks */
1759 ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
1760
1761 /* HW ECC always work with even numbers of ECC bytes */
1762 ecc->bytes = ALIGN(ecc->bytes, 2);
1763
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001764 nsectors = mtd->writesize / ecc->size;
1765
1766 if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
1767 ret = -EINVAL;
1768 goto err;
1769 }
1770
Boris Brezillon15d6f112018-03-21 09:36:18 +01001771 ecc->read_oob = sunxi_nfc_hw_ecc_read_oob;
1772 ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
Boris Brezillonc66811e2016-02-03 20:05:13 +01001773 mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001774 ecc->priv = data;
1775
Boris Brezillon614049a2016-04-15 15:10:30 +02001776 if (nfc->dmac) {
1777 ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
1778 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
1779 ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
1780 nand->options |= NAND_USE_BOUNCE_BUFFER;
1781 } else {
1782 ecc->read_page = sunxi_nfc_hw_ecc_read_page;
1783 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
1784 ecc->write_page = sunxi_nfc_hw_ecc_write_page;
1785 }
1786
Boris Brezillon03b1d112016-06-06 13:59:14 +02001787 /* TODO: support DMA for raw accesses and subpage write */
1788 ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
Boris Brezillon1c1bdd62015-09-02 15:05:52 +02001789 ecc->read_oob_raw = nand_read_oob_std;
1790 ecc->write_oob_raw = nand_write_oob_std;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001791
1792 return 0;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001793
Boris Brezillon15d6f112018-03-21 09:36:18 +01001794err:
1795 kfree(data);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001796
Boris Brezillon15d6f112018-03-21 09:36:18 +01001797 return ret;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001798}
1799
1800static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
1801{
1802 switch (ecc->mode) {
1803 case NAND_ECC_HW:
Boris Brezillon15d6f112018-03-21 09:36:18 +01001804 sunxi_nand_hw_ecc_ctrl_cleanup(ecc);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001805 break;
1806 case NAND_ECC_NONE:
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001807 default:
1808 break;
1809 }
1810}
1811
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001812static int sunxi_nand_attach_chip(struct nand_chip *nand)
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001813{
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001814 struct mtd_info *mtd = nand_to_mtd(nand);
1815 struct nand_ecc_ctrl *ecc = &nand->ecc;
1816 struct device_node *np = nand_get_flash_node(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001817 int ret;
1818
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001819 if (nand->bbt_options & NAND_BBT_USE_FLASH)
1820 nand->bbt_options |= NAND_BBT_NO_OOB;
1821
1822 if (nand->options & NAND_NEED_SCRAMBLING)
1823 nand->options |= NAND_NO_SUBPAGE_WRITE;
1824
1825 nand->options |= NAND_SUBPAGE_READ;
1826
Boris BREZILLONa3d22a52015-09-02 10:30:25 +02001827 if (!ecc->size) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001828 ecc->size = nand->ecc_step_ds;
1829 ecc->strength = nand->ecc_strength_ds;
1830 }
1831
1832 if (!ecc->size || !ecc->strength)
1833 return -EINVAL;
1834
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001835 switch (ecc->mode) {
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001836 case NAND_ECC_HW:
1837 ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
1838 if (ret)
1839 return ret;
1840 break;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001841 case NAND_ECC_NONE:
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001842 case NAND_ECC_SOFT:
1843 break;
1844 default:
1845 return -EINVAL;
1846 }
1847
1848 return 0;
1849}
1850
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001851static const struct nand_controller_ops sunxi_nand_controller_ops = {
1852 .attach_chip = sunxi_nand_attach_chip,
1853};
1854
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001855static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
1856 struct device_node *np)
1857{
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001858 struct sunxi_nand_chip *chip;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001859 struct mtd_info *mtd;
1860 struct nand_chip *nand;
1861 int nsels;
1862 int ret;
1863 int i;
1864 u32 tmp;
1865
1866 if (!of_get_property(np, "reg", &nsels))
1867 return -EINVAL;
1868
1869 nsels /= sizeof(u32);
1870 if (!nsels) {
1871 dev_err(dev, "invalid reg property size\n");
1872 return -EINVAL;
1873 }
1874
1875 chip = devm_kzalloc(dev,
1876 sizeof(*chip) +
1877 (nsels * sizeof(struct sunxi_nand_chip_sel)),
1878 GFP_KERNEL);
1879 if (!chip) {
1880 dev_err(dev, "could not allocate chip\n");
1881 return -ENOMEM;
1882 }
1883
1884 chip->nsels = nsels;
1885 chip->selected = -1;
1886
1887 for (i = 0; i < nsels; i++) {
1888 ret = of_property_read_u32_index(np, "reg", i, &tmp);
1889 if (ret) {
1890 dev_err(dev, "could not retrieve reg property: %d\n",
1891 ret);
1892 return ret;
1893 }
1894
1895 if (tmp > NFC_MAX_CS) {
1896 dev_err(dev,
1897 "invalid reg value: %u (max CS = 7)\n",
1898 tmp);
1899 return -EINVAL;
1900 }
1901
1902 if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
1903 dev_err(dev, "CS %d already assigned\n", tmp);
1904 return -EINVAL;
1905 }
1906
1907 chip->sels[i].cs = tmp;
1908
1909 if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
Boris Brezillonddd5ed32018-03-27 09:06:14 +02001910 tmp < 2)
1911 chip->sels[i].rb = tmp;
1912 else
1913 chip->sels[i].rb = -1;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001914 }
1915
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001916 nand = &chip->nand;
1917 /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
1918 nand->chip_delay = 200;
1919 nand->controller = &nfc->controller;
Miquel Raynal2a4d9c12018-07-20 17:15:13 +02001920 nand->controller->ops = &sunxi_nand_controller_ops;
1921
Boris BREZILLONa3d22a52015-09-02 10:30:25 +02001922 /*
1923 * Set the ECC mode to the default value in case nothing is specified
1924 * in the DT.
1925 */
1926 nand->ecc.mode = NAND_ECC_HW;
Brian Norris63752192015-10-30 20:33:23 -07001927 nand_set_flash_node(nand, np);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001928 nand->select_chip = sunxi_nfc_select_chip;
1929 nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
1930 nand->read_buf = sunxi_nfc_read_buf;
1931 nand->write_buf = sunxi_nfc_write_buf;
1932 nand->read_byte = sunxi_nfc_read_byte;
Sascha Hauer907f45f2016-09-15 10:32:51 +02001933 nand->setup_data_interface = sunxi_nfc_setup_data_interface;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001934
Boris BREZILLON32e9f2d2015-12-10 09:00:26 +01001935 mtd = nand_to_mtd(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001936 mtd->dev.parent = dev;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001937
Boris Brezillon00ad3782018-09-06 14:05:14 +02001938 ret = nand_scan(nand, nsels);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001939 if (ret)
1940 return ret;
1941
Brian Norrisa61ae812015-10-30 20:33:25 -07001942 ret = mtd_device_register(mtd, NULL, 0);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001943 if (ret) {
1944 dev_err(dev, "failed to register mtd device: %d\n", ret);
Boris Brezillon59ac2762018-09-06 14:05:15 +02001945 nand_release(nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001946 return ret;
1947 }
1948
1949 list_add_tail(&chip->node, &nfc->chips);
1950
1951 return 0;
1952}
1953
1954static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
1955{
1956 struct device_node *np = dev->of_node;
1957 struct device_node *nand_np;
1958 int nchips = of_get_child_count(np);
1959 int ret;
1960
1961 if (nchips > 8) {
1962 dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
1963 return -EINVAL;
1964 }
1965
1966 for_each_child_of_node(np, nand_np) {
1967 ret = sunxi_nand_chip_init(dev, nfc, nand_np);
Julia Lawalla81c0f02015-11-18 23:04:12 +01001968 if (ret) {
1969 of_node_put(nand_np);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001970 return ret;
Julia Lawalla81c0f02015-11-18 23:04:12 +01001971 }
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001972 }
1973
1974 return 0;
1975}
1976
1977static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
1978{
1979 struct sunxi_nand_chip *chip;
1980
1981 while (!list_empty(&nfc->chips)) {
1982 chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
1983 node);
Boris Brezillon59ac2762018-09-06 14:05:15 +02001984 nand_release(&chip->nand);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001985 sunxi_nand_ecc_cleanup(&chip->nand.ecc);
Boris BREZILLON8e375cc2015-09-13 18:14:43 +02001986 list_del(&chip->node);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02001987 }
1988}
1989
1990static int sunxi_nfc_probe(struct platform_device *pdev)
1991{
1992 struct device *dev = &pdev->dev;
1993 struct resource *r;
1994 struct sunxi_nfc *nfc;
1995 int irq;
1996 int ret;
1997
1998 nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
1999 if (!nfc)
2000 return -ENOMEM;
2001
2002 nfc->dev = dev;
Miquel Raynal7da45132018-07-17 09:08:02 +02002003 nand_controller_init(&nfc->controller);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002004 INIT_LIST_HEAD(&nfc->chips);
2005
2006 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2007 nfc->regs = devm_ioremap_resource(dev, r);
2008 if (IS_ERR(nfc->regs))
2009 return PTR_ERR(nfc->regs);
2010
2011 irq = platform_get_irq(pdev, 0);
2012 if (irq < 0) {
2013 dev_err(dev, "failed to retrieve irq\n");
2014 return irq;
2015 }
2016
2017 nfc->ahb_clk = devm_clk_get(dev, "ahb");
2018 if (IS_ERR(nfc->ahb_clk)) {
2019 dev_err(dev, "failed to retrieve ahb clk\n");
2020 return PTR_ERR(nfc->ahb_clk);
2021 }
2022
2023 ret = clk_prepare_enable(nfc->ahb_clk);
2024 if (ret)
2025 return ret;
2026
2027 nfc->mod_clk = devm_clk_get(dev, "mod");
2028 if (IS_ERR(nfc->mod_clk)) {
2029 dev_err(dev, "failed to retrieve mod clk\n");
2030 ret = PTR_ERR(nfc->mod_clk);
2031 goto out_ahb_clk_unprepare;
2032 }
2033
2034 ret = clk_prepare_enable(nfc->mod_clk);
2035 if (ret)
2036 goto out_ahb_clk_unprepare;
2037
Philipp Zabelfcf59f12017-07-19 17:25:46 +02002038 nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002039 if (IS_ERR(nfc->reset)) {
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002040 ret = PTR_ERR(nfc->reset);
2041 goto out_mod_clk_unprepare;
2042 }
2043
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002044 ret = reset_control_deassert(nfc->reset);
2045 if (ret) {
2046 dev_err(dev, "reset err %d\n", ret);
2047 goto out_mod_clk_unprepare;
2048 }
2049
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002050 ret = sunxi_nfc_rst(nfc);
2051 if (ret)
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002052 goto out_ahb_reset_reassert;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002053
2054 writel(0, nfc->regs + NFC_REG_INT);
2055 ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
2056 0, "sunxi-nand", nfc);
2057 if (ret)
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002058 goto out_ahb_reset_reassert;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002059
Boris Brezillon614049a2016-04-15 15:10:30 +02002060 nfc->dmac = dma_request_slave_channel(dev, "rxtx");
2061 if (nfc->dmac) {
2062 struct dma_slave_config dmac_cfg = { };
2063
2064 dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
2065 dmac_cfg.dst_addr = dmac_cfg.src_addr;
2066 dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2067 dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
2068 dmac_cfg.src_maxburst = 4;
2069 dmac_cfg.dst_maxburst = 4;
2070 dmaengine_slave_config(nfc->dmac, &dmac_cfg);
2071 } else {
2072 dev_warn(dev, "failed to request rxtx DMA channel\n");
2073 }
2074
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002075 platform_set_drvdata(pdev, nfc);
2076
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002077 ret = sunxi_nand_chips_init(dev, nfc);
2078 if (ret) {
2079 dev_err(dev, "failed to init nand chips\n");
Boris Brezillon614049a2016-04-15 15:10:30 +02002080 goto out_release_dmac;
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002081 }
2082
2083 return 0;
2084
Boris Brezillon614049a2016-04-15 15:10:30 +02002085out_release_dmac:
2086 if (nfc->dmac)
2087 dma_release_channel(nfc->dmac);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002088out_ahb_reset_reassert:
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002089 reset_control_assert(nfc->reset);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002090out_mod_clk_unprepare:
2091 clk_disable_unprepare(nfc->mod_clk);
2092out_ahb_clk_unprepare:
2093 clk_disable_unprepare(nfc->ahb_clk);
2094
2095 return ret;
2096}
2097
2098static int sunxi_nfc_remove(struct platform_device *pdev)
2099{
2100 struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
2101
2102 sunxi_nand_chips_cleanup(nfc);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002103
Philipp Zabel6b244bb2017-03-15 12:31:47 +01002104 reset_control_assert(nfc->reset);
Icenowy Zhengab9d6a72016-06-20 12:48:38 +08002105
Boris Brezillon614049a2016-04-15 15:10:30 +02002106 if (nfc->dmac)
2107 dma_release_channel(nfc->dmac);
Boris Brezillondd26a452016-03-04 18:26:40 +01002108 clk_disable_unprepare(nfc->mod_clk);
2109 clk_disable_unprepare(nfc->ahb_clk);
Boris BREZILLON1fef62c2014-10-21 15:08:41 +02002110
2111 return 0;
2112}
2113
2114static const struct of_device_id sunxi_nfc_ids[] = {
2115 { .compatible = "allwinner,sun4i-a10-nand" },
2116 { /* sentinel */ }
2117};
2118MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
2119
2120static struct platform_driver sunxi_nfc_driver = {
2121 .driver = {
2122 .name = "sunxi_nand",
2123 .of_match_table = sunxi_nfc_ids,
2124 },
2125 .probe = sunxi_nfc_probe,
2126 .remove = sunxi_nfc_remove,
2127};
2128module_platform_driver(sunxi_nfc_driver);
2129
2130MODULE_LICENSE("GPL v2");
2131MODULE_AUTHOR("Boris BREZILLON");
2132MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
2133MODULE_ALIAS("platform:sunxi_nand");