xref: /openbmc/linux/drivers/mtd/nand/raw/meson_nand.c (revision 46eeaa11bdd1bc9e077bdf741d32ca7235d263c6)
18fae856cSLiang Yang // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
28fae856cSLiang Yang /*
38fae856cSLiang Yang  * Amlogic Meson Nand Flash Controller Driver
48fae856cSLiang Yang  *
58fae856cSLiang Yang  * Copyright (c) 2018 Amlogic, inc.
68fae856cSLiang Yang  * Author: Liang Yang <liang.yang@amlogic.com>
78fae856cSLiang Yang  */
88fae856cSLiang Yang 
98fae856cSLiang Yang #include <linux/platform_device.h>
108fae856cSLiang Yang #include <linux/dma-mapping.h>
118fae856cSLiang Yang #include <linux/interrupt.h>
128fae856cSLiang Yang #include <linux/clk.h>
131e4d3ba6SLiang Yang #include <linux/clk-provider.h>
148fae856cSLiang Yang #include <linux/mtd/rawnand.h>
158fae856cSLiang Yang #include <linux/mtd/mtd.h>
168fae856cSLiang Yang #include <linux/mfd/syscon.h>
178fae856cSLiang Yang #include <linux/regmap.h>
188fae856cSLiang Yang #include <linux/slab.h>
198fae856cSLiang Yang #include <linux/module.h>
208fae856cSLiang Yang #include <linux/iopoll.h>
218fae856cSLiang Yang #include <linux/of.h>
228fae856cSLiang Yang #include <linux/sched/task_stack.h>
238fae856cSLiang Yang 
248fae856cSLiang Yang #define NFC_REG_CMD		0x00
258fae856cSLiang Yang #define NFC_CMD_IDLE		(0xc << 14)
268fae856cSLiang Yang #define NFC_CMD_CLE		(0x5 << 14)
278fae856cSLiang Yang #define NFC_CMD_ALE		(0x6 << 14)
288fae856cSLiang Yang #define NFC_CMD_ADL		((0 << 16) | (3 << 20))
298fae856cSLiang Yang #define NFC_CMD_ADH		((1 << 16) | (3 << 20))
308fae856cSLiang Yang #define NFC_CMD_AIL		((2 << 16) | (3 << 20))
318fae856cSLiang Yang #define NFC_CMD_AIH		((3 << 16) | (3 << 20))
328fae856cSLiang Yang #define NFC_CMD_SEED		((8 << 16) | (3 << 20))
338fae856cSLiang Yang #define NFC_CMD_M2N		((0 << 17) | (2 << 20))
348fae856cSLiang Yang #define NFC_CMD_N2M		((1 << 17) | (2 << 20))
358fae856cSLiang Yang #define NFC_CMD_RB		BIT(20)
368fae856cSLiang Yang #define NFC_CMD_SCRAMBLER_ENABLE	BIT(19)
378fae856cSLiang Yang #define NFC_CMD_SCRAMBLER_DISABLE	0
388fae856cSLiang Yang #define NFC_CMD_SHORTMODE_DISABLE	0
398fae856cSLiang Yang #define NFC_CMD_RB_INT		BIT(14)
40c17a90a4SArseniy Krasnov #define NFC_CMD_RB_INT_NO_PIN	((0xb << 10) | BIT(18) | BIT(16))
418fae856cSLiang Yang 
428fae856cSLiang Yang #define NFC_CMD_GET_SIZE(x)	(((x) >> 22) & GENMASK(4, 0))
438fae856cSLiang Yang 
448fae856cSLiang Yang #define NFC_REG_CFG		0x04
458fae856cSLiang Yang #define NFC_REG_DADR		0x08
468fae856cSLiang Yang #define NFC_REG_IADR		0x0c
478fae856cSLiang Yang #define NFC_REG_BUF		0x10
488fae856cSLiang Yang #define NFC_REG_INFO		0x14
498fae856cSLiang Yang #define NFC_REG_DC		0x18
508fae856cSLiang Yang #define NFC_REG_ADR		0x1c
518fae856cSLiang Yang #define NFC_REG_DL		0x20
528fae856cSLiang Yang #define NFC_REG_DH		0x24
538fae856cSLiang Yang #define NFC_REG_CADR		0x28
548fae856cSLiang Yang #define NFC_REG_SADR		0x2c
558fae856cSLiang Yang #define NFC_REG_PINS		0x30
568fae856cSLiang Yang #define NFC_REG_VER		0x38
578fae856cSLiang Yang 
588fae856cSLiang Yang #define NFC_RB_IRQ_EN		BIT(21)
598fae856cSLiang Yang 
601e4d3ba6SLiang Yang #define CLK_DIV_SHIFT		0
611e4d3ba6SLiang Yang #define CLK_DIV_WIDTH		6
621e4d3ba6SLiang Yang 
638fae856cSLiang Yang #define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages)	\
648fae856cSLiang Yang 	(								\
658fae856cSLiang Yang 		(cmd_dir)			|			\
66*d8ea3e78SArseniy Krasnov 		(ran)				|			\
678fae856cSLiang Yang 		((bch) << 14)			|			\
688fae856cSLiang Yang 		((short_mode) << 13)		|			\
698fae856cSLiang Yang 		(((page_size) & 0x7f) << 6)	|			\
708fae856cSLiang Yang 		((pages) & 0x3f)					\
718fae856cSLiang Yang 	)
728fae856cSLiang Yang 
738fae856cSLiang Yang #define GENCMDDADDRL(adl, addr)		((adl) | ((addr) & 0xffff))
748fae856cSLiang Yang #define GENCMDDADDRH(adh, addr)		((adh) | (((addr) >> 16) & 0xffff))
758fae856cSLiang Yang #define GENCMDIADDRL(ail, addr)		((ail) | ((addr) & 0xffff))
768fae856cSLiang Yang #define GENCMDIADDRH(aih, addr)		((aih) | (((addr) >> 16) & 0xffff))
778fae856cSLiang Yang 
788fae856cSLiang Yang #define DMA_DIR(dir)		((dir) ? NFC_CMD_N2M : NFC_CMD_M2N)
7998480a18SArseniy Krasnov #define DMA_ADDR_ALIGN		8
808fae856cSLiang Yang 
818fae856cSLiang Yang #define ECC_CHECK_RETURN_FF	(-1)
828fae856cSLiang Yang 
838fae856cSLiang Yang #define NAND_CE0		(0xe << 10)
848fae856cSLiang Yang #define NAND_CE1		(0xd << 10)
858fae856cSLiang Yang 
868fae856cSLiang Yang #define DMA_BUSY_TIMEOUT	0x100000
878fae856cSLiang Yang #define CMD_FIFO_EMPTY_TIMEOUT	1000
888fae856cSLiang Yang 
898fae856cSLiang Yang #define MAX_CE_NUM		2
908fae856cSLiang Yang 
918fae856cSLiang Yang /* eMMC clock register, misc control */
928fae856cSLiang Yang #define CLK_SELECT_NAND		BIT(31)
938fae856cSLiang Yang 
948fae856cSLiang Yang #define NFC_CLK_CYCLE		6
958fae856cSLiang Yang 
968fae856cSLiang Yang /* nand flash controller delay 3 ns */
978fae856cSLiang Yang #define NFC_DEFAULT_DELAY	3000
988fae856cSLiang Yang 
998fae856cSLiang Yang #define ROW_ADDER(page, index)	(((page) >> (8 * (index))) & 0xff)
1008fae856cSLiang Yang #define MAX_CYCLE_ADDRS		5
1018fae856cSLiang Yang #define DIRREAD			1
1028fae856cSLiang Yang #define DIRWRITE		0
1038fae856cSLiang Yang 
1048fae856cSLiang Yang #define ECC_PARITY_BCH8_512B	14
1058fae856cSLiang Yang #define ECC_COMPLETE            BIT(31)
1068fae856cSLiang Yang #define ECC_ERR_CNT(x)		(((x) >> 24) & GENMASK(5, 0))
1078fae856cSLiang Yang #define ECC_ZERO_CNT(x)		(((x) >> 16) & GENMASK(5, 0))
1088fae856cSLiang Yang #define ECC_UNCORRECTABLE	0x3f
1098fae856cSLiang Yang 
1108fae856cSLiang Yang #define PER_INFO_BYTE		8
1118fae856cSLiang Yang 
11246c37b99SArseniy Krasnov #define NFC_CMD_RAW_LEN	GENMASK(13, 0)
11346c37b99SArseniy Krasnov 
11430540a0dSArseniy Krasnov #define NFC_COLUMN_ADDR_0	0
11530540a0dSArseniy Krasnov #define NFC_COLUMN_ADDR_1	0
11630540a0dSArseniy Krasnov 
1178fae856cSLiang Yang struct meson_nfc_nand_chip {
1188fae856cSLiang Yang 	struct list_head node;
1198fae856cSLiang Yang 	struct nand_chip nand;
1208fae856cSLiang Yang 	unsigned long clk_rate;
1218fae856cSLiang Yang 	unsigned long level1_divider;
1228fae856cSLiang Yang 	u32 bus_timing;
1238fae856cSLiang Yang 	u32 twb;
1248fae856cSLiang Yang 	u32 tadl;
1258fae856cSLiang Yang 	u32 tbers_max;
1268fae856cSLiang Yang 
1278fae856cSLiang Yang 	u32 bch_mode;
1288fae856cSLiang Yang 	u8 *data_buf;
1298fae856cSLiang Yang 	__le64 *info_buf;
1308fae856cSLiang Yang 	u32 nsels;
13149f1c330SGustavo A. R. Silva 	u8 sels[];
1328fae856cSLiang Yang };
1338fae856cSLiang Yang 
1348fae856cSLiang Yang struct meson_nand_ecc {
1358fae856cSLiang Yang 	u32 bch;
1368fae856cSLiang Yang 	u32 strength;
1370e1db393SArseniy Krasnov 	u32 size;
1388fae856cSLiang Yang };
1398fae856cSLiang Yang 
1408fae856cSLiang Yang struct meson_nfc_data {
1418fae856cSLiang Yang 	const struct nand_ecc_caps *ecc_caps;
1428fae856cSLiang Yang };
1438fae856cSLiang Yang 
1448fae856cSLiang Yang struct meson_nfc_param {
1458fae856cSLiang Yang 	u32 chip_select;
1468fae856cSLiang Yang 	u32 rb_select;
1478fae856cSLiang Yang };
1488fae856cSLiang Yang 
1498fae856cSLiang Yang struct nand_rw_cmd {
1508fae856cSLiang Yang 	u32 cmd0;
1518fae856cSLiang Yang 	u32 addrs[MAX_CYCLE_ADDRS];
1528fae856cSLiang Yang 	u32 cmd1;
1538fae856cSLiang Yang };
1548fae856cSLiang Yang 
1558fae856cSLiang Yang struct nand_timing {
1568fae856cSLiang Yang 	u32 twb;
1578fae856cSLiang Yang 	u32 tadl;
1588fae856cSLiang Yang 	u32 tbers_max;
1598fae856cSLiang Yang };
1608fae856cSLiang Yang 
1618fae856cSLiang Yang struct meson_nfc {
1628fae856cSLiang Yang 	struct nand_controller controller;
1638fae856cSLiang Yang 	struct clk *core_clk;
1648fae856cSLiang Yang 	struct clk *device_clk;
1651e4d3ba6SLiang Yang 	struct clk *nand_clk;
1661e4d3ba6SLiang Yang 	struct clk_divider nand_divider;
1678fae856cSLiang Yang 
1688fae856cSLiang Yang 	unsigned long clk_rate;
1698fae856cSLiang Yang 	u32 bus_timing;
1708fae856cSLiang Yang 
1718fae856cSLiang Yang 	struct device *dev;
1728fae856cSLiang Yang 	void __iomem *reg_base;
1731e4d3ba6SLiang Yang 	void __iomem *reg_clk;
1748fae856cSLiang Yang 	struct completion completion;
1758fae856cSLiang Yang 	struct list_head chips;
1768fae856cSLiang Yang 	const struct meson_nfc_data *data;
1778fae856cSLiang Yang 	struct meson_nfc_param param;
1788fae856cSLiang Yang 	struct nand_timing timing;
1798fae856cSLiang Yang 	union {
1808fae856cSLiang Yang 		int cmd[32];
1818fae856cSLiang Yang 		struct nand_rw_cmd rw;
1828fae856cSLiang Yang 	} cmdfifo;
1838fae856cSLiang Yang 
1848fae856cSLiang Yang 	dma_addr_t daddr;
1858fae856cSLiang Yang 	dma_addr_t iaddr;
186e732e39eSArseniy Krasnov 	u32 info_bytes;
1878fae856cSLiang Yang 
1888fae856cSLiang Yang 	unsigned long assigned_cs;
189c17a90a4SArseniy Krasnov 	bool no_rb_pin;
1908fae856cSLiang Yang };
1918fae856cSLiang Yang 
1928fae856cSLiang Yang enum {
1930e1db393SArseniy Krasnov 	NFC_ECC_BCH8_512	= 1,
1940e1db393SArseniy Krasnov 	NFC_ECC_BCH8_1K,
1958fae856cSLiang Yang 	NFC_ECC_BCH24_1K,
1968fae856cSLiang Yang 	NFC_ECC_BCH30_1K,
1978fae856cSLiang Yang 	NFC_ECC_BCH40_1K,
1988fae856cSLiang Yang 	NFC_ECC_BCH50_1K,
1998fae856cSLiang Yang 	NFC_ECC_BCH60_1K,
2008fae856cSLiang Yang };
2018fae856cSLiang Yang 
2020e1db393SArseniy Krasnov #define MESON_ECC_DATA(b, s, sz)	{ .bch = (b), .strength = (s), .size = (sz) }
2038fae856cSLiang Yang 
2048fae856cSLiang Yang static struct meson_nand_ecc meson_ecc[] = {
2050e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH8_512, 8,  512),
2060e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH8_1K,  8,  1024),
2070e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24, 1024),
2080e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30, 1024),
2090e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40, 1024),
2100e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50, 1024),
2110e1db393SArseniy Krasnov 	MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60, 1024),
2128fae856cSLiang Yang };
2138fae856cSLiang Yang 
meson_nand_calc_ecc_bytes(int step_size,int strength)2148fae856cSLiang Yang static int meson_nand_calc_ecc_bytes(int step_size, int strength)
2158fae856cSLiang Yang {
2168fae856cSLiang Yang 	int ecc_bytes;
2178fae856cSLiang Yang 
2188fae856cSLiang Yang 	if (step_size == 512 && strength == 8)
2198fae856cSLiang Yang 		return ECC_PARITY_BCH8_512B;
2208fae856cSLiang Yang 
2218fae856cSLiang Yang 	ecc_bytes = DIV_ROUND_UP(strength * fls(step_size * 8), 8);
2228fae856cSLiang Yang 	ecc_bytes = ALIGN(ecc_bytes, 2);
2238fae856cSLiang Yang 
2248fae856cSLiang Yang 	return ecc_bytes;
2258fae856cSLiang Yang }
2268fae856cSLiang Yang 
2278fae856cSLiang Yang NAND_ECC_CAPS_SINGLE(meson_gxl_ecc_caps,
2288fae856cSLiang Yang 		     meson_nand_calc_ecc_bytes, 1024, 8, 24, 30, 40, 50, 60);
2290e1db393SArseniy Krasnov 
2300e1db393SArseniy Krasnov static const int axg_stepinfo_strengths[] = { 8 };
2314622daf4SArseniy Krasnov 
2324622daf4SArseniy Krasnov static const struct nand_ecc_step_info axg_stepinfo[] = {
2334622daf4SArseniy Krasnov 	{
2340e1db393SArseniy Krasnov 		.stepsize = 1024,
2350e1db393SArseniy Krasnov 		.strengths = axg_stepinfo_strengths,
2360e1db393SArseniy Krasnov 		.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
2374622daf4SArseniy Krasnov 	},
2384622daf4SArseniy Krasnov 	{
2390e1db393SArseniy Krasnov 		.stepsize = 512,
2400e1db393SArseniy Krasnov 		.strengths = axg_stepinfo_strengths,
2410e1db393SArseniy Krasnov 		.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
2424622daf4SArseniy Krasnov 	},
2430e1db393SArseniy Krasnov };
2440e1db393SArseniy Krasnov 
2450e1db393SArseniy Krasnov static const struct nand_ecc_caps meson_axg_ecc_caps = {
2460e1db393SArseniy Krasnov 	.stepinfos = axg_stepinfo,
2470e1db393SArseniy Krasnov 	.nstepinfos = ARRAY_SIZE(axg_stepinfo),
2480e1db393SArseniy Krasnov 	.calc_ecc_bytes = meson_nand_calc_ecc_bytes,
2490e1db393SArseniy Krasnov };
2508fae856cSLiang Yang 
to_meson_nand(struct nand_chip * nand)2518fae856cSLiang Yang static struct meson_nfc_nand_chip *to_meson_nand(struct nand_chip *nand)
2528fae856cSLiang Yang {
2538fae856cSLiang Yang 	return container_of(nand, struct meson_nfc_nand_chip, nand);
2548fae856cSLiang Yang }
2558fae856cSLiang Yang 
meson_nfc_select_chip(struct nand_chip * nand,int chip)2568fae856cSLiang Yang static void meson_nfc_select_chip(struct nand_chip *nand, int chip)
2578fae856cSLiang Yang {
2588fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
2598fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
2608fae856cSLiang Yang 	int ret, value;
2618fae856cSLiang Yang 
2628fae856cSLiang Yang 	if (chip < 0 || WARN_ON_ONCE(chip >= meson_chip->nsels))
2638fae856cSLiang Yang 		return;
2648fae856cSLiang Yang 
2658fae856cSLiang Yang 	nfc->param.chip_select = meson_chip->sels[chip] ? NAND_CE1 : NAND_CE0;
2668fae856cSLiang Yang 	nfc->param.rb_select = nfc->param.chip_select;
2678fae856cSLiang Yang 	nfc->timing.twb = meson_chip->twb;
2688fae856cSLiang Yang 	nfc->timing.tadl = meson_chip->tadl;
2698fae856cSLiang Yang 	nfc->timing.tbers_max = meson_chip->tbers_max;
2708fae856cSLiang Yang 
2718fae856cSLiang Yang 	if (nfc->clk_rate != meson_chip->clk_rate) {
2721e4d3ba6SLiang Yang 		ret = clk_set_rate(nfc->nand_clk, meson_chip->clk_rate);
2738fae856cSLiang Yang 		if (ret) {
2748fae856cSLiang Yang 			dev_err(nfc->dev, "failed to set clock rate\n");
2758fae856cSLiang Yang 			return;
2768fae856cSLiang Yang 		}
2778fae856cSLiang Yang 		nfc->clk_rate = meson_chip->clk_rate;
2788fae856cSLiang Yang 	}
2798fae856cSLiang Yang 	if (nfc->bus_timing != meson_chip->bus_timing) {
2808fae856cSLiang Yang 		value = (NFC_CLK_CYCLE - 1) | (meson_chip->bus_timing << 5);
2818fae856cSLiang Yang 		writel(value, nfc->reg_base + NFC_REG_CFG);
2828fae856cSLiang Yang 		writel((1 << 31), nfc->reg_base + NFC_REG_CMD);
2838fae856cSLiang Yang 		nfc->bus_timing =  meson_chip->bus_timing;
2848fae856cSLiang Yang 	}
2858fae856cSLiang Yang }
2868fae856cSLiang Yang 
meson_nfc_cmd_idle(struct meson_nfc * nfc,u32 time)2878fae856cSLiang Yang static void meson_nfc_cmd_idle(struct meson_nfc *nfc, u32 time)
2888fae856cSLiang Yang {
2898fae856cSLiang Yang 	writel(nfc->param.chip_select | NFC_CMD_IDLE | (time & 0x3ff),
2908fae856cSLiang Yang 	       nfc->reg_base + NFC_REG_CMD);
2918fae856cSLiang Yang }
2928fae856cSLiang Yang 
meson_nfc_cmd_seed(struct meson_nfc * nfc,u32 seed)2938fae856cSLiang Yang static void meson_nfc_cmd_seed(struct meson_nfc *nfc, u32 seed)
2948fae856cSLiang Yang {
2958fae856cSLiang Yang 	writel(NFC_CMD_SEED | (0xc2 + (seed & 0x7fff)),
2968fae856cSLiang Yang 	       nfc->reg_base + NFC_REG_CMD);
2978fae856cSLiang Yang }
2988fae856cSLiang Yang 
meson_nfc_cmd_access(struct nand_chip * nand,int raw,bool dir,int scrambler)2998fae856cSLiang Yang static void meson_nfc_cmd_access(struct nand_chip *nand, int raw, bool dir,
3008fae856cSLiang Yang 				 int scrambler)
3018fae856cSLiang Yang {
3028fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
3038fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
3048fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
3058fae856cSLiang Yang 	u32 bch = meson_chip->bch_mode, cmd;
3068fae856cSLiang Yang 	int len = mtd->writesize, pagesize, pages;
3078fae856cSLiang Yang 
3088fae856cSLiang Yang 	pagesize = nand->ecc.size;
3098fae856cSLiang Yang 
3108fae856cSLiang Yang 	if (raw) {
3118fae856cSLiang Yang 		len = mtd->writesize + mtd->oobsize;
31246c37b99SArseniy Krasnov 		cmd = len | scrambler | DMA_DIR(dir);
3138fae856cSLiang Yang 		writel(cmd, nfc->reg_base + NFC_REG_CMD);
3148fae856cSLiang Yang 		return;
3158fae856cSLiang Yang 	}
3168fae856cSLiang Yang 
3178fae856cSLiang Yang 	pages = len / nand->ecc.size;
3188fae856cSLiang Yang 
3198fae856cSLiang Yang 	cmd = CMDRWGEN(DMA_DIR(dir), scrambler, bch,
3208fae856cSLiang Yang 		       NFC_CMD_SHORTMODE_DISABLE, pagesize, pages);
3218fae856cSLiang Yang 
3228fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
3238fae856cSLiang Yang }
3248fae856cSLiang Yang 
meson_nfc_drain_cmd(struct meson_nfc * nfc)3258fae856cSLiang Yang static void meson_nfc_drain_cmd(struct meson_nfc *nfc)
3268fae856cSLiang Yang {
3278fae856cSLiang Yang 	/*
3288fae856cSLiang Yang 	 * Insert two commands to make sure all valid commands are finished.
3298fae856cSLiang Yang 	 *
3308fae856cSLiang Yang 	 * The Nand flash controller is designed as two stages pipleline -
3318fae856cSLiang Yang 	 *  a) fetch and b) excute.
3328fae856cSLiang Yang 	 * There might be cases when the driver see command queue is empty,
3338fae856cSLiang Yang 	 * but the Nand flash controller still has two commands buffered,
3348fae856cSLiang Yang 	 * one is fetched into NFC request queue (ready to run), and another
3358fae856cSLiang Yang 	 * is actively executing. So pushing 2 "IDLE" commands guarantees that
3368fae856cSLiang Yang 	 * the pipeline is emptied.
3378fae856cSLiang Yang 	 */
3388fae856cSLiang Yang 	meson_nfc_cmd_idle(nfc, 0);
3398fae856cSLiang Yang 	meson_nfc_cmd_idle(nfc, 0);
3408fae856cSLiang Yang }
3418fae856cSLiang Yang 
meson_nfc_wait_cmd_finish(struct meson_nfc * nfc,unsigned int timeout_ms)3428fae856cSLiang Yang static int meson_nfc_wait_cmd_finish(struct meson_nfc *nfc,
3438fae856cSLiang Yang 				     unsigned int timeout_ms)
3448fae856cSLiang Yang {
3458fae856cSLiang Yang 	u32 cmd_size = 0;
3468fae856cSLiang Yang 	int ret;
3478fae856cSLiang Yang 
3488fae856cSLiang Yang 	/* wait cmd fifo is empty */
3498fae856cSLiang Yang 	ret = readl_relaxed_poll_timeout(nfc->reg_base + NFC_REG_CMD, cmd_size,
3508fae856cSLiang Yang 					 !NFC_CMD_GET_SIZE(cmd_size),
3518fae856cSLiang Yang 					 10, timeout_ms * 1000);
3528fae856cSLiang Yang 	if (ret)
3538fae856cSLiang Yang 		dev_err(nfc->dev, "wait for empty CMD FIFO time out\n");
3548fae856cSLiang Yang 
3558fae856cSLiang Yang 	return ret;
3568fae856cSLiang Yang }
3578fae856cSLiang Yang 
meson_nfc_wait_dma_finish(struct meson_nfc * nfc)3588fae856cSLiang Yang static int meson_nfc_wait_dma_finish(struct meson_nfc *nfc)
3598fae856cSLiang Yang {
3608fae856cSLiang Yang 	meson_nfc_drain_cmd(nfc);
3618fae856cSLiang Yang 
3628fae856cSLiang Yang 	return meson_nfc_wait_cmd_finish(nfc, DMA_BUSY_TIMEOUT);
3638fae856cSLiang Yang }
3648fae856cSLiang Yang 
meson_nfc_oob_ptr(struct nand_chip * nand,int i)3658fae856cSLiang Yang static u8 *meson_nfc_oob_ptr(struct nand_chip *nand, int i)
3668fae856cSLiang Yang {
3678fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
3688fae856cSLiang Yang 	int len;
3698fae856cSLiang Yang 
3708fae856cSLiang Yang 	len = nand->ecc.size * (i + 1) + (nand->ecc.bytes + 2) * i;
3718fae856cSLiang Yang 
3728fae856cSLiang Yang 	return meson_chip->data_buf + len;
3738fae856cSLiang Yang }
3748fae856cSLiang Yang 
meson_nfc_data_ptr(struct nand_chip * nand,int i)3758fae856cSLiang Yang static u8 *meson_nfc_data_ptr(struct nand_chip *nand, int i)
3768fae856cSLiang Yang {
3778fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
3788fae856cSLiang Yang 	int len, temp;
3798fae856cSLiang Yang 
3808fae856cSLiang Yang 	temp = nand->ecc.size + nand->ecc.bytes;
3818fae856cSLiang Yang 	len = (temp + 2) * i;
3828fae856cSLiang Yang 
3838fae856cSLiang Yang 	return meson_chip->data_buf + len;
3848fae856cSLiang Yang }
3858fae856cSLiang Yang 
meson_nfc_get_data_oob(struct nand_chip * nand,u8 * buf,u8 * oobbuf)3868fae856cSLiang Yang static void meson_nfc_get_data_oob(struct nand_chip *nand,
3878fae856cSLiang Yang 				   u8 *buf, u8 *oobbuf)
3888fae856cSLiang Yang {
3898fae856cSLiang Yang 	int i, oob_len = 0;
3908fae856cSLiang Yang 	u8 *dsrc, *osrc;
3918fae856cSLiang Yang 
3928fae856cSLiang Yang 	oob_len = nand->ecc.bytes + 2;
3938fae856cSLiang Yang 	for (i = 0; i < nand->ecc.steps; i++) {
3948fae856cSLiang Yang 		if (buf) {
3958fae856cSLiang Yang 			dsrc = meson_nfc_data_ptr(nand, i);
3968fae856cSLiang Yang 			memcpy(buf, dsrc, nand->ecc.size);
3978fae856cSLiang Yang 			buf += nand->ecc.size;
3988fae856cSLiang Yang 		}
3998fae856cSLiang Yang 		osrc = meson_nfc_oob_ptr(nand, i);
4008fae856cSLiang Yang 		memcpy(oobbuf, osrc, oob_len);
4018fae856cSLiang Yang 		oobbuf += oob_len;
4028fae856cSLiang Yang 	}
4038fae856cSLiang Yang }
4048fae856cSLiang Yang 
meson_nfc_set_data_oob(struct nand_chip * nand,const u8 * buf,u8 * oobbuf)4058fae856cSLiang Yang static void meson_nfc_set_data_oob(struct nand_chip *nand,
4068fae856cSLiang Yang 				   const u8 *buf, u8 *oobbuf)
4078fae856cSLiang Yang {
4088fae856cSLiang Yang 	int i, oob_len = 0;
4098fae856cSLiang Yang 	u8 *dsrc, *osrc;
4108fae856cSLiang Yang 
4118fae856cSLiang Yang 	oob_len = nand->ecc.bytes + 2;
4128fae856cSLiang Yang 	for (i = 0; i < nand->ecc.steps; i++) {
4138fae856cSLiang Yang 		if (buf) {
4148fae856cSLiang Yang 			dsrc = meson_nfc_data_ptr(nand, i);
4158fae856cSLiang Yang 			memcpy(dsrc, buf, nand->ecc.size);
4168fae856cSLiang Yang 			buf += nand->ecc.size;
4178fae856cSLiang Yang 		}
4188fae856cSLiang Yang 		osrc = meson_nfc_oob_ptr(nand, i);
4198fae856cSLiang Yang 		memcpy(osrc, oobbuf, oob_len);
4208fae856cSLiang Yang 		oobbuf += oob_len;
4218fae856cSLiang Yang 	}
4228fae856cSLiang Yang }
4238fae856cSLiang Yang 
meson_nfc_wait_no_rb_pin(struct nand_chip * nand,int timeout_ms,bool need_cmd_read0)424cda24ab7SArseniy Krasnov static int meson_nfc_wait_no_rb_pin(struct nand_chip *nand, int timeout_ms,
425c17a90a4SArseniy Krasnov 				    bool need_cmd_read0)
426c17a90a4SArseniy Krasnov {
427cda24ab7SArseniy Krasnov 	struct meson_nfc *nfc = nand_get_controller_data(nand);
428c17a90a4SArseniy Krasnov 	u32 cmd, cfg;
429c17a90a4SArseniy Krasnov 
430c17a90a4SArseniy Krasnov 	meson_nfc_cmd_idle(nfc, nfc->timing.twb);
431c17a90a4SArseniy Krasnov 	meson_nfc_drain_cmd(nfc);
432c17a90a4SArseniy Krasnov 	meson_nfc_wait_cmd_finish(nfc, CMD_FIFO_EMPTY_TIMEOUT);
433c17a90a4SArseniy Krasnov 
434c17a90a4SArseniy Krasnov 	cfg = readl(nfc->reg_base + NFC_REG_CFG);
435c17a90a4SArseniy Krasnov 	cfg |= NFC_RB_IRQ_EN;
436c17a90a4SArseniy Krasnov 	writel(cfg, nfc->reg_base + NFC_REG_CFG);
437c17a90a4SArseniy Krasnov 
438c17a90a4SArseniy Krasnov 	reinit_completion(&nfc->completion);
439cda24ab7SArseniy Krasnov 	nand_status_op(nand, NULL);
440c17a90a4SArseniy Krasnov 
441c17a90a4SArseniy Krasnov 	/* use the max erase time as the maximum clock for waiting R/B */
442c17a90a4SArseniy Krasnov 	cmd = NFC_CMD_RB | NFC_CMD_RB_INT_NO_PIN | nfc->timing.tbers_max;
443c17a90a4SArseniy Krasnov 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
444c17a90a4SArseniy Krasnov 
445c17a90a4SArseniy Krasnov 	if (!wait_for_completion_timeout(&nfc->completion,
446c17a90a4SArseniy Krasnov 					 msecs_to_jiffies(timeout_ms)))
447c17a90a4SArseniy Krasnov 		return -ETIMEDOUT;
448c17a90a4SArseniy Krasnov 
449cda24ab7SArseniy Krasnov 	if (need_cmd_read0)
450cda24ab7SArseniy Krasnov 		nand_exit_status_op(nand);
451c17a90a4SArseniy Krasnov 
452c17a90a4SArseniy Krasnov 	return 0;
453c17a90a4SArseniy Krasnov }
454c17a90a4SArseniy Krasnov 
meson_nfc_wait_rb_pin(struct meson_nfc * nfc,int timeout_ms)455c17a90a4SArseniy Krasnov static int meson_nfc_wait_rb_pin(struct meson_nfc *nfc, int timeout_ms)
4568fae856cSLiang Yang {
4578fae856cSLiang Yang 	u32 cmd, cfg;
4588fae856cSLiang Yang 	int ret = 0;
4598fae856cSLiang Yang 
4608fae856cSLiang Yang 	meson_nfc_cmd_idle(nfc, nfc->timing.twb);
4618fae856cSLiang Yang 	meson_nfc_drain_cmd(nfc);
4628fae856cSLiang Yang 	meson_nfc_wait_cmd_finish(nfc, CMD_FIFO_EMPTY_TIMEOUT);
4638fae856cSLiang Yang 
4648fae856cSLiang Yang 	cfg = readl(nfc->reg_base + NFC_REG_CFG);
4658fae856cSLiang Yang 	cfg |= NFC_RB_IRQ_EN;
4668fae856cSLiang Yang 	writel(cfg, nfc->reg_base + NFC_REG_CFG);
4678fae856cSLiang Yang 
46839e01956SMartin Blumenstingl 	reinit_completion(&nfc->completion);
4698fae856cSLiang Yang 
4708fae856cSLiang Yang 	/* use the max erase time as the maximum clock for waiting R/B */
4718fae856cSLiang Yang 	cmd = NFC_CMD_RB | NFC_CMD_RB_INT
4728fae856cSLiang Yang 		| nfc->param.chip_select | nfc->timing.tbers_max;
4738fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
4748fae856cSLiang Yang 
4758fae856cSLiang Yang 	ret = wait_for_completion_timeout(&nfc->completion,
4768fae856cSLiang Yang 					  msecs_to_jiffies(timeout_ms));
4778fae856cSLiang Yang 	if (ret == 0)
4788fae856cSLiang Yang 		ret = -1;
4798fae856cSLiang Yang 
4808fae856cSLiang Yang 	return ret;
4818fae856cSLiang Yang }
4828fae856cSLiang Yang 
meson_nfc_queue_rb(struct nand_chip * nand,int timeout_ms,bool need_cmd_read0)483cda24ab7SArseniy Krasnov static int meson_nfc_queue_rb(struct nand_chip *nand, int timeout_ms,
484c17a90a4SArseniy Krasnov 			      bool need_cmd_read0)
485c17a90a4SArseniy Krasnov {
486cda24ab7SArseniy Krasnov 	struct meson_nfc *nfc = nand_get_controller_data(nand);
487cda24ab7SArseniy Krasnov 
488c17a90a4SArseniy Krasnov 	if (nfc->no_rb_pin) {
489c17a90a4SArseniy Krasnov 		/* This mode is used when there is no wired R/B pin.
490c17a90a4SArseniy Krasnov 		 * It works like 'nand_soft_waitrdy()', but instead of
491c17a90a4SArseniy Krasnov 		 * polling NAND_CMD_STATUS bit in the software loop,
492c17a90a4SArseniy Krasnov 		 * it will wait for interrupt - controllers checks IO
493c17a90a4SArseniy Krasnov 		 * bus and when it detects NAND_CMD_STATUS on it, it
494c17a90a4SArseniy Krasnov 		 * raises interrupt. After interrupt, NAND_CMD_READ0 is
495c17a90a4SArseniy Krasnov 		 * sent as terminator of the ready waiting procedure if
496c17a90a4SArseniy Krasnov 		 * needed (for all cases except page programming - this
497c17a90a4SArseniy Krasnov 		 * is reason of 'need_cmd_read0' flag).
498c17a90a4SArseniy Krasnov 		 */
499cda24ab7SArseniy Krasnov 		return meson_nfc_wait_no_rb_pin(nand, timeout_ms,
500c17a90a4SArseniy Krasnov 						need_cmd_read0);
501c17a90a4SArseniy Krasnov 	} else {
502c17a90a4SArseniy Krasnov 		return meson_nfc_wait_rb_pin(nfc, timeout_ms);
503c17a90a4SArseniy Krasnov 	}
504c17a90a4SArseniy Krasnov }
505c17a90a4SArseniy Krasnov 
meson_nfc_set_user_byte(struct nand_chip * nand,u8 * oob_buf)5068fae856cSLiang Yang static void meson_nfc_set_user_byte(struct nand_chip *nand, u8 *oob_buf)
5078fae856cSLiang Yang {
5088fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
5098fae856cSLiang Yang 	__le64 *info;
5108fae856cSLiang Yang 	int i, count;
5118fae856cSLiang Yang 
5128fae856cSLiang Yang 	for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) {
5138fae856cSLiang Yang 		info = &meson_chip->info_buf[i];
5148fae856cSLiang Yang 		*info |= oob_buf[count];
5158fae856cSLiang Yang 		*info |= oob_buf[count + 1] << 8;
5168fae856cSLiang Yang 	}
5178fae856cSLiang Yang }
5188fae856cSLiang Yang 
meson_nfc_get_user_byte(struct nand_chip * nand,u8 * oob_buf)5198fae856cSLiang Yang static void meson_nfc_get_user_byte(struct nand_chip *nand, u8 *oob_buf)
5208fae856cSLiang Yang {
5218fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
5228fae856cSLiang Yang 	__le64 *info;
5238fae856cSLiang Yang 	int i, count;
5248fae856cSLiang Yang 
5258fae856cSLiang Yang 	for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) {
5268fae856cSLiang Yang 		info = &meson_chip->info_buf[i];
5278fae856cSLiang Yang 		oob_buf[count] = *info;
5288fae856cSLiang Yang 		oob_buf[count + 1] = *info >> 8;
5298fae856cSLiang Yang 	}
5308fae856cSLiang Yang }
5318fae856cSLiang Yang 
meson_nfc_ecc_correct(struct nand_chip * nand,u32 * bitflips,u64 * correct_bitmap)5328fae856cSLiang Yang static int meson_nfc_ecc_correct(struct nand_chip *nand, u32 *bitflips,
5338fae856cSLiang Yang 				 u64 *correct_bitmap)
5348fae856cSLiang Yang {
5358fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
5368fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
5378fae856cSLiang Yang 	__le64 *info;
5388fae856cSLiang Yang 	int ret = 0, i;
5398fae856cSLiang Yang 
5408fae856cSLiang Yang 	for (i = 0; i < nand->ecc.steps; i++) {
5418fae856cSLiang Yang 		info = &meson_chip->info_buf[i];
5428fae856cSLiang Yang 		if (ECC_ERR_CNT(*info) != ECC_UNCORRECTABLE) {
5438fae856cSLiang Yang 			mtd->ecc_stats.corrected += ECC_ERR_CNT(*info);
5448fae856cSLiang Yang 			*bitflips = max_t(u32, *bitflips, ECC_ERR_CNT(*info));
5453e4ad321SDan Carpenter 			*correct_bitmap |= BIT_ULL(i);
5468fae856cSLiang Yang 			continue;
5478fae856cSLiang Yang 		}
5488fae856cSLiang Yang 		if ((nand->options & NAND_NEED_SCRAMBLING) &&
5498fae856cSLiang Yang 		    ECC_ZERO_CNT(*info) < nand->ecc.strength) {
5508fae856cSLiang Yang 			mtd->ecc_stats.corrected += ECC_ZERO_CNT(*info);
5518fae856cSLiang Yang 			*bitflips = max_t(u32, *bitflips,
5528fae856cSLiang Yang 					  ECC_ZERO_CNT(*info));
5538fae856cSLiang Yang 			ret = ECC_CHECK_RETURN_FF;
5548fae856cSLiang Yang 		} else {
5558fae856cSLiang Yang 			ret = -EBADMSG;
5568fae856cSLiang Yang 		}
5578fae856cSLiang Yang 	}
5588fae856cSLiang Yang 	return ret;
5598fae856cSLiang Yang }
5608fae856cSLiang Yang 
meson_nfc_dma_buffer_setup(struct nand_chip * nand,void * databuf,int datalen,void * infobuf,int infolen,enum dma_data_direction dir)561c96ffedfSMartin Blumenstingl static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf,
562c96ffedfSMartin Blumenstingl 				      int datalen, void *infobuf, int infolen,
5638fae856cSLiang Yang 				      enum dma_data_direction dir)
5648fae856cSLiang Yang {
5658fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
5668fae856cSLiang Yang 	u32 cmd;
5678fae856cSLiang Yang 	int ret = 0;
5688fae856cSLiang Yang 
569c96ffedfSMartin Blumenstingl 	nfc->daddr = dma_map_single(nfc->dev, databuf, datalen, dir);
5708fae856cSLiang Yang 	ret = dma_mapping_error(nfc->dev, nfc->daddr);
5718fae856cSLiang Yang 	if (ret) {
5728fae856cSLiang Yang 		dev_err(nfc->dev, "DMA mapping error\n");
5738fae856cSLiang Yang 		return ret;
5748fae856cSLiang Yang 	}
5758fae856cSLiang Yang 	cmd = GENCMDDADDRL(NFC_CMD_ADL, nfc->daddr);
5768fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
5778fae856cSLiang Yang 
5788fae856cSLiang Yang 	cmd = GENCMDDADDRH(NFC_CMD_ADH, nfc->daddr);
5798fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
5808fae856cSLiang Yang 
5818fae856cSLiang Yang 	if (infobuf) {
5828fae856cSLiang Yang 		nfc->iaddr = dma_map_single(nfc->dev, infobuf, infolen, dir);
5838fae856cSLiang Yang 		ret = dma_mapping_error(nfc->dev, nfc->iaddr);
5848fae856cSLiang Yang 		if (ret) {
5858fae856cSLiang Yang 			dev_err(nfc->dev, "DMA mapping error\n");
5868fae856cSLiang Yang 			dma_unmap_single(nfc->dev,
5878fae856cSLiang Yang 					 nfc->daddr, datalen, dir);
5888fae856cSLiang Yang 			return ret;
5898fae856cSLiang Yang 		}
590e732e39eSArseniy Krasnov 		nfc->info_bytes = infolen;
5918fae856cSLiang Yang 		cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr);
5928fae856cSLiang Yang 		writel(cmd, nfc->reg_base + NFC_REG_CMD);
5938fae856cSLiang Yang 
5948fae856cSLiang Yang 		cmd = GENCMDIADDRH(NFC_CMD_AIH, nfc->iaddr);
5958fae856cSLiang Yang 		writel(cmd, nfc->reg_base + NFC_REG_CMD);
5968fae856cSLiang Yang 	}
5978fae856cSLiang Yang 
5988fae856cSLiang Yang 	return ret;
5998fae856cSLiang Yang }
6008fae856cSLiang Yang 
meson_nfc_dma_buffer_release(struct nand_chip * nand,int datalen,int infolen,enum dma_data_direction dir)6018fae856cSLiang Yang static void meson_nfc_dma_buffer_release(struct nand_chip *nand,
602c13d845eSSergei Antonov 					 int datalen, int infolen,
6038fae856cSLiang Yang 					 enum dma_data_direction dir)
6048fae856cSLiang Yang {
6058fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
6068fae856cSLiang Yang 
6078fae856cSLiang Yang 	dma_unmap_single(nfc->dev, nfc->daddr, datalen, dir);
608e732e39eSArseniy Krasnov 	if (infolen) {
6098fae856cSLiang Yang 		dma_unmap_single(nfc->dev, nfc->iaddr, infolen, dir);
610e732e39eSArseniy Krasnov 		nfc->info_bytes = 0;
611e732e39eSArseniy Krasnov 	}
6128fae856cSLiang Yang }
6138fae856cSLiang Yang 
meson_nfc_read_buf(struct nand_chip * nand,u8 * buf,int len)6148fae856cSLiang Yang static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
6158fae856cSLiang Yang {
6168fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
6178fae856cSLiang Yang 	int ret = 0;
6188fae856cSLiang Yang 	u32 cmd;
6198fae856cSLiang Yang 	u8 *info;
6208fae856cSLiang Yang 
6218fae856cSLiang Yang 	info = kzalloc(PER_INFO_BYTE, GFP_KERNEL);
62291e9dd77SMartin Blumenstingl 	if (!info)
62391e9dd77SMartin Blumenstingl 		return -ENOMEM;
62491e9dd77SMartin Blumenstingl 
6258fae856cSLiang Yang 	ret = meson_nfc_dma_buffer_setup(nand, buf, len, info,
6268fae856cSLiang Yang 					 PER_INFO_BYTE, DMA_FROM_DEVICE);
6278fae856cSLiang Yang 	if (ret)
6286d50e9b6SMartin Blumenstingl 		goto out;
6298fae856cSLiang Yang 
63046c37b99SArseniy Krasnov 	cmd = NFC_CMD_N2M | len;
6318fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
6328fae856cSLiang Yang 
6338fae856cSLiang Yang 	meson_nfc_drain_cmd(nfc);
6348fae856cSLiang Yang 	meson_nfc_wait_cmd_finish(nfc, 1000);
6358fae856cSLiang Yang 	meson_nfc_dma_buffer_release(nand, len, PER_INFO_BYTE, DMA_FROM_DEVICE);
6366d50e9b6SMartin Blumenstingl 
6376d50e9b6SMartin Blumenstingl out:
6388fae856cSLiang Yang 	kfree(info);
6398fae856cSLiang Yang 
6408fae856cSLiang Yang 	return ret;
6418fae856cSLiang Yang }
6428fae856cSLiang Yang 
meson_nfc_write_buf(struct nand_chip * nand,u8 * buf,int len)6438fae856cSLiang Yang static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len)
6448fae856cSLiang Yang {
6458fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
6468fae856cSLiang Yang 	int ret = 0;
6478fae856cSLiang Yang 	u32 cmd;
6488fae856cSLiang Yang 
6498fae856cSLiang Yang 	ret = meson_nfc_dma_buffer_setup(nand, buf, len, NULL,
6508fae856cSLiang Yang 					 0, DMA_TO_DEVICE);
6518fae856cSLiang Yang 	if (ret)
6528fae856cSLiang Yang 		return ret;
6538fae856cSLiang Yang 
65446c37b99SArseniy Krasnov 	cmd = NFC_CMD_M2N | len;
6558fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
6568fae856cSLiang Yang 
6578fae856cSLiang Yang 	meson_nfc_drain_cmd(nfc);
6588fae856cSLiang Yang 	meson_nfc_wait_cmd_finish(nfc, 1000);
6598fae856cSLiang Yang 	meson_nfc_dma_buffer_release(nand, len, 0, DMA_TO_DEVICE);
6608fae856cSLiang Yang 
6618fae856cSLiang Yang 	return ret;
6628fae856cSLiang Yang }
6638fae856cSLiang Yang 
meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip * nand,int page,bool in)6648fae856cSLiang Yang static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
6658fae856cSLiang Yang 						int page, bool in)
6668fae856cSLiang Yang {
667e0160cd4SMiquel Raynal 	const struct nand_sdr_timings *sdr =
668e0160cd4SMiquel Raynal 		nand_get_sdr_timings(nand_get_interface_config(nand));
6698fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
6708fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
6718fae856cSLiang Yang 	u32 *addrs = nfc->cmdfifo.rw.addrs;
6728fae856cSLiang Yang 	u32 cs = nfc->param.chip_select;
6738fae856cSLiang Yang 	u32 cmd0, cmd_num, row_start;
67474a021a6SJason Wang 	int i;
6758fae856cSLiang Yang 
6768fae856cSLiang Yang 	cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int);
6778fae856cSLiang Yang 
6788fae856cSLiang Yang 	cmd0 = in ? NAND_CMD_READ0 : NAND_CMD_SEQIN;
6798fae856cSLiang Yang 	nfc->cmdfifo.rw.cmd0 = cs | NFC_CMD_CLE | cmd0;
6808fae856cSLiang Yang 
68130540a0dSArseniy Krasnov 	addrs[0] = cs | NFC_CMD_ALE | NFC_COLUMN_ADDR_0;
6828fae856cSLiang Yang 	if (mtd->writesize <= 512) {
6838fae856cSLiang Yang 		cmd_num--;
6848fae856cSLiang Yang 		row_start = 1;
6858fae856cSLiang Yang 	} else {
68630540a0dSArseniy Krasnov 		addrs[1] = cs | NFC_CMD_ALE | NFC_COLUMN_ADDR_1;
6878fae856cSLiang Yang 		row_start = 2;
6888fae856cSLiang Yang 	}
6898fae856cSLiang Yang 
6908fae856cSLiang Yang 	addrs[row_start] = cs | NFC_CMD_ALE | ROW_ADDER(page, 0);
6918fae856cSLiang Yang 	addrs[row_start + 1] = cs | NFC_CMD_ALE | ROW_ADDER(page, 1);
6928fae856cSLiang Yang 
6938fae856cSLiang Yang 	if (nand->options & NAND_ROW_ADDR_3)
6948fae856cSLiang Yang 		addrs[row_start + 2] =
6958fae856cSLiang Yang 			cs | NFC_CMD_ALE | ROW_ADDER(page, 2);
6968fae856cSLiang Yang 	else
6978fae856cSLiang Yang 		cmd_num--;
6988fae856cSLiang Yang 
6998fae856cSLiang Yang 	/* subtract cmd1 */
7008fae856cSLiang Yang 	cmd_num--;
7018fae856cSLiang Yang 
7028fae856cSLiang Yang 	for (i = 0; i < cmd_num; i++)
7038fae856cSLiang Yang 		writel_relaxed(nfc->cmdfifo.cmd[i],
7048fae856cSLiang Yang 			       nfc->reg_base + NFC_REG_CMD);
7058fae856cSLiang Yang 
7068fae856cSLiang Yang 	if (in) {
7078fae856cSLiang Yang 		nfc->cmdfifo.rw.cmd1 = cs | NFC_CMD_CLE | NAND_CMD_READSTART;
7088fae856cSLiang Yang 		writel(nfc->cmdfifo.rw.cmd1, nfc->reg_base + NFC_REG_CMD);
709cda24ab7SArseniy Krasnov 		meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tR_max), true);
7108fae856cSLiang Yang 	} else {
7118fae856cSLiang Yang 		meson_nfc_cmd_idle(nfc, nfc->timing.tadl);
7128fae856cSLiang Yang 	}
7138fae856cSLiang Yang 
71474a021a6SJason Wang 	return 0;
7158fae856cSLiang Yang }
7168fae856cSLiang Yang 
meson_nfc_write_page_sub(struct nand_chip * nand,int page,int raw)7178fae856cSLiang Yang static int meson_nfc_write_page_sub(struct nand_chip *nand,
7188fae856cSLiang Yang 				    int page, int raw)
7198fae856cSLiang Yang {
7208fae856cSLiang Yang 	const struct nand_sdr_timings *sdr =
721e0160cd4SMiquel Raynal 		nand_get_sdr_timings(nand_get_interface_config(nand));
722e0160cd4SMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(nand);
7238fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
7248fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
7258fae856cSLiang Yang 	int data_len, info_len;
7268fae856cSLiang Yang 	u32 cmd;
7278fae856cSLiang Yang 	int ret;
7288fae856cSLiang Yang 
7298fae856cSLiang Yang 	meson_nfc_select_chip(nand, nand->cur_cs);
7308fae856cSLiang Yang 
7318fae856cSLiang Yang 	data_len =  mtd->writesize + mtd->oobsize;
7328fae856cSLiang Yang 	info_len = nand->ecc.steps * PER_INFO_BYTE;
7338fae856cSLiang Yang 
7348fae856cSLiang Yang 	ret = meson_nfc_rw_cmd_prepare_and_execute(nand, page, DIRWRITE);
7358fae856cSLiang Yang 	if (ret)
7368fae856cSLiang Yang 		return ret;
7378fae856cSLiang Yang 
7388fae856cSLiang Yang 	ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
739c96ffedfSMartin Blumenstingl 					 data_len, meson_chip->info_buf,
7408fae856cSLiang Yang 					 info_len, DMA_TO_DEVICE);
7418fae856cSLiang Yang 	if (ret)
7428fae856cSLiang Yang 		return ret;
7438fae856cSLiang Yang 
7448fae856cSLiang Yang 	if (nand->options & NAND_NEED_SCRAMBLING) {
7458fae856cSLiang Yang 		meson_nfc_cmd_seed(nfc, page);
7468fae856cSLiang Yang 		meson_nfc_cmd_access(nand, raw, DIRWRITE,
7478fae856cSLiang Yang 				     NFC_CMD_SCRAMBLER_ENABLE);
7488fae856cSLiang Yang 	} else {
7498fae856cSLiang Yang 		meson_nfc_cmd_access(nand, raw, DIRWRITE,
7508fae856cSLiang Yang 				     NFC_CMD_SCRAMBLER_DISABLE);
7518fae856cSLiang Yang 	}
7528fae856cSLiang Yang 
7538fae856cSLiang Yang 	cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG;
7548fae856cSLiang Yang 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
755cda24ab7SArseniy Krasnov 	meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tPROG_max), false);
7568fae856cSLiang Yang 
7578fae856cSLiang Yang 	meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_TO_DEVICE);
7588fae856cSLiang Yang 
7598fae856cSLiang Yang 	return ret;
7608fae856cSLiang Yang }
7618fae856cSLiang Yang 
meson_nfc_write_page_raw(struct nand_chip * nand,const u8 * buf,int oob_required,int page)7628fae856cSLiang Yang static int meson_nfc_write_page_raw(struct nand_chip *nand, const u8 *buf,
7638fae856cSLiang Yang 				    int oob_required, int page)
7648fae856cSLiang Yang {
7658fae856cSLiang Yang 	u8 *oob_buf = nand->oob_poi;
7668fae856cSLiang Yang 
7678fae856cSLiang Yang 	meson_nfc_set_data_oob(nand, buf, oob_buf);
7688fae856cSLiang Yang 
7698fae856cSLiang Yang 	return meson_nfc_write_page_sub(nand, page, 1);
7708fae856cSLiang Yang }
7718fae856cSLiang Yang 
meson_nfc_write_page_hwecc(struct nand_chip * nand,const u8 * buf,int oob_required,int page)7728fae856cSLiang Yang static int meson_nfc_write_page_hwecc(struct nand_chip *nand,
7738fae856cSLiang Yang 				      const u8 *buf, int oob_required, int page)
7748fae856cSLiang Yang {
7758fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
7768fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
7778fae856cSLiang Yang 	u8 *oob_buf = nand->oob_poi;
7788fae856cSLiang Yang 
7798fae856cSLiang Yang 	memcpy(meson_chip->data_buf, buf, mtd->writesize);
7808fae856cSLiang Yang 	memset(meson_chip->info_buf, 0, nand->ecc.steps * PER_INFO_BYTE);
7818fae856cSLiang Yang 	meson_nfc_set_user_byte(nand, oob_buf);
7828fae856cSLiang Yang 
7838fae856cSLiang Yang 	return meson_nfc_write_page_sub(nand, page, 0);
7848fae856cSLiang Yang }
7858fae856cSLiang Yang 
meson_nfc_check_ecc_pages_valid(struct meson_nfc * nfc,struct nand_chip * nand,int raw)7868fae856cSLiang Yang static void meson_nfc_check_ecc_pages_valid(struct meson_nfc *nfc,
7878fae856cSLiang Yang 					    struct nand_chip *nand, int raw)
7888fae856cSLiang Yang {
7898fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
7908fae856cSLiang Yang 	__le64 *info;
7918fae856cSLiang Yang 	u32 neccpages;
7928fae856cSLiang Yang 	int ret;
7938fae856cSLiang Yang 
7948fae856cSLiang Yang 	neccpages = raw ? 1 : nand->ecc.steps;
7958fae856cSLiang Yang 	info = &meson_chip->info_buf[neccpages - 1];
7968fae856cSLiang Yang 	do {
7978fae856cSLiang Yang 		usleep_range(10, 15);
7988fae856cSLiang Yang 		/* info is updated by nfc dma engine*/
7998fae856cSLiang Yang 		smp_rmb();
800e732e39eSArseniy Krasnov 		dma_sync_single_for_cpu(nfc->dev, nfc->iaddr, nfc->info_bytes,
801e732e39eSArseniy Krasnov 					DMA_FROM_DEVICE);
8028fae856cSLiang Yang 		ret = *info & ECC_COMPLETE;
8038fae856cSLiang Yang 	} while (!ret);
8048fae856cSLiang Yang }
8058fae856cSLiang Yang 
meson_nfc_read_page_sub(struct nand_chip * nand,int page,int raw)8068fae856cSLiang Yang static int meson_nfc_read_page_sub(struct nand_chip *nand,
8078fae856cSLiang Yang 				   int page, int raw)
8088fae856cSLiang Yang {
8098fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
8108fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
8118fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
8128fae856cSLiang Yang 	int data_len, info_len;
8138fae856cSLiang Yang 	int ret;
8148fae856cSLiang Yang 
8158fae856cSLiang Yang 	meson_nfc_select_chip(nand, nand->cur_cs);
8168fae856cSLiang Yang 
8178fae856cSLiang Yang 	data_len =  mtd->writesize + mtd->oobsize;
8188fae856cSLiang Yang 	info_len = nand->ecc.steps * PER_INFO_BYTE;
8198fae856cSLiang Yang 
8208fae856cSLiang Yang 	ret = meson_nfc_rw_cmd_prepare_and_execute(nand, page, DIRREAD);
8218fae856cSLiang Yang 	if (ret)
8228fae856cSLiang Yang 		return ret;
8238fae856cSLiang Yang 
8248fae856cSLiang Yang 	ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
825c96ffedfSMartin Blumenstingl 					 data_len, meson_chip->info_buf,
8268fae856cSLiang Yang 					 info_len, DMA_FROM_DEVICE);
8278fae856cSLiang Yang 	if (ret)
8288fae856cSLiang Yang 		return ret;
8298fae856cSLiang Yang 
8308fae856cSLiang Yang 	if (nand->options & NAND_NEED_SCRAMBLING) {
8318fae856cSLiang Yang 		meson_nfc_cmd_seed(nfc, page);
8328fae856cSLiang Yang 		meson_nfc_cmd_access(nand, raw, DIRREAD,
8338fae856cSLiang Yang 				     NFC_CMD_SCRAMBLER_ENABLE);
8348fae856cSLiang Yang 	} else {
8358fae856cSLiang Yang 		meson_nfc_cmd_access(nand, raw, DIRREAD,
8368fae856cSLiang Yang 				     NFC_CMD_SCRAMBLER_DISABLE);
8378fae856cSLiang Yang 	}
8388fae856cSLiang Yang 
8398fae856cSLiang Yang 	ret = meson_nfc_wait_dma_finish(nfc);
8408fae856cSLiang Yang 	meson_nfc_check_ecc_pages_valid(nfc, nand, raw);
8418fae856cSLiang Yang 
8428fae856cSLiang Yang 	meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_FROM_DEVICE);
8438fae856cSLiang Yang 
8448fae856cSLiang Yang 	return ret;
8458fae856cSLiang Yang }
8468fae856cSLiang Yang 
meson_nfc_read_page_raw(struct nand_chip * nand,u8 * buf,int oob_required,int page)8478fae856cSLiang Yang static int meson_nfc_read_page_raw(struct nand_chip *nand, u8 *buf,
8488fae856cSLiang Yang 				   int oob_required, int page)
8498fae856cSLiang Yang {
8508fae856cSLiang Yang 	u8 *oob_buf = nand->oob_poi;
8518fae856cSLiang Yang 	int ret;
8528fae856cSLiang Yang 
8538fae856cSLiang Yang 	ret = meson_nfc_read_page_sub(nand, page, 1);
8548fae856cSLiang Yang 	if (ret)
8558fae856cSLiang Yang 		return ret;
8568fae856cSLiang Yang 
8578fae856cSLiang Yang 	meson_nfc_get_data_oob(nand, buf, oob_buf);
8588fae856cSLiang Yang 
8598fae856cSLiang Yang 	return 0;
8608fae856cSLiang Yang }
8618fae856cSLiang Yang 
meson_nfc_read_page_hwecc(struct nand_chip * nand,u8 * buf,int oob_required,int page)8628fae856cSLiang Yang static int meson_nfc_read_page_hwecc(struct nand_chip *nand, u8 *buf,
8638fae856cSLiang Yang 				     int oob_required, int page)
8648fae856cSLiang Yang {
8658fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
8668fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
8678fae856cSLiang Yang 	struct nand_ecc_ctrl *ecc = &nand->ecc;
8688fae856cSLiang Yang 	u64 correct_bitmap = 0;
8698fae856cSLiang Yang 	u32 bitflips = 0;
8708fae856cSLiang Yang 	u8 *oob_buf = nand->oob_poi;
8718fae856cSLiang Yang 	int ret, i;
8728fae856cSLiang Yang 
8738fae856cSLiang Yang 	ret = meson_nfc_read_page_sub(nand, page, 0);
8748fae856cSLiang Yang 	if (ret)
8758fae856cSLiang Yang 		return ret;
8768fae856cSLiang Yang 
8778fae856cSLiang Yang 	meson_nfc_get_user_byte(nand, oob_buf);
8788fae856cSLiang Yang 	ret = meson_nfc_ecc_correct(nand, &bitflips, &correct_bitmap);
8798fae856cSLiang Yang 	if (ret == ECC_CHECK_RETURN_FF) {
8808fae856cSLiang Yang 		if (buf)
8818fae856cSLiang Yang 			memset(buf, 0xff, mtd->writesize);
8828fae856cSLiang Yang 		memset(oob_buf, 0xff, mtd->oobsize);
8838fae856cSLiang Yang 	} else if (ret < 0) {
8848fae856cSLiang Yang 		if ((nand->options & NAND_NEED_SCRAMBLING) || !buf) {
8858fae856cSLiang Yang 			mtd->ecc_stats.failed++;
8868fae856cSLiang Yang 			return bitflips;
8878fae856cSLiang Yang 		}
8888fae856cSLiang Yang 		ret  = meson_nfc_read_page_raw(nand, buf, 0, page);
8898fae856cSLiang Yang 		if (ret)
8908fae856cSLiang Yang 			return ret;
8918fae856cSLiang Yang 
8928fae856cSLiang Yang 		for (i = 0; i < nand->ecc.steps ; i++) {
8938fae856cSLiang Yang 			u8 *data = buf + i * ecc->size;
8948fae856cSLiang Yang 			u8 *oob = nand->oob_poi + i * (ecc->bytes + 2);
8958fae856cSLiang Yang 
8963e4ad321SDan Carpenter 			if (correct_bitmap & BIT_ULL(i))
8978fae856cSLiang Yang 				continue;
8988fae856cSLiang Yang 			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
8998fae856cSLiang Yang 							  oob, ecc->bytes + 2,
9008fae856cSLiang Yang 							  NULL, 0,
9018fae856cSLiang Yang 							  ecc->strength);
9028fae856cSLiang Yang 			if (ret < 0) {
9038fae856cSLiang Yang 				mtd->ecc_stats.failed++;
9048fae856cSLiang Yang 			} else {
9058fae856cSLiang Yang 				mtd->ecc_stats.corrected += ret;
9068fae856cSLiang Yang 				bitflips =  max_t(u32, bitflips, ret);
9078fae856cSLiang Yang 			}
9088fae856cSLiang Yang 		}
9098fae856cSLiang Yang 	} else if (buf && buf != meson_chip->data_buf) {
9108fae856cSLiang Yang 		memcpy(buf, meson_chip->data_buf, mtd->writesize);
9118fae856cSLiang Yang 	}
9128fae856cSLiang Yang 
9138fae856cSLiang Yang 	return bitflips;
9148fae856cSLiang Yang }
9158fae856cSLiang Yang 
meson_nfc_read_oob_raw(struct nand_chip * nand,int page)9168fae856cSLiang Yang static int meson_nfc_read_oob_raw(struct nand_chip *nand, int page)
9178fae856cSLiang Yang {
9188fae856cSLiang Yang 	return meson_nfc_read_page_raw(nand, NULL, 1, page);
9198fae856cSLiang Yang }
9208fae856cSLiang Yang 
meson_nfc_read_oob(struct nand_chip * nand,int page)9218fae856cSLiang Yang static int meson_nfc_read_oob(struct nand_chip *nand, int page)
9228fae856cSLiang Yang {
9238fae856cSLiang Yang 	return meson_nfc_read_page_hwecc(nand, NULL, 1, page);
9248fae856cSLiang Yang }
9258fae856cSLiang Yang 
meson_nfc_is_buffer_dma_safe(const void * buffer)9268fae856cSLiang Yang static bool meson_nfc_is_buffer_dma_safe(const void *buffer)
9278fae856cSLiang Yang {
92898480a18SArseniy Krasnov 	if ((uintptr_t)buffer % DMA_ADDR_ALIGN)
92998480a18SArseniy Krasnov 		return false;
93098480a18SArseniy Krasnov 
9318fae856cSLiang Yang 	if (virt_addr_valid(buffer) && (!object_is_on_stack(buffer)))
9328fae856cSLiang Yang 		return true;
9338fae856cSLiang Yang 	return false;
9348fae856cSLiang Yang }
9358fae856cSLiang Yang 
9368fae856cSLiang Yang static void *
meson_nand_op_get_dma_safe_input_buf(const struct nand_op_instr * instr)9378fae856cSLiang Yang meson_nand_op_get_dma_safe_input_buf(const struct nand_op_instr *instr)
9388fae856cSLiang Yang {
9398fae856cSLiang Yang 	if (WARN_ON(instr->type != NAND_OP_DATA_IN_INSTR))
9408fae856cSLiang Yang 		return NULL;
9418fae856cSLiang Yang 
9428fae856cSLiang Yang 	if (meson_nfc_is_buffer_dma_safe(instr->ctx.data.buf.in))
9438fae856cSLiang Yang 		return instr->ctx.data.buf.in;
9448fae856cSLiang Yang 
9458fae856cSLiang Yang 	return kzalloc(instr->ctx.data.len, GFP_KERNEL);
9468fae856cSLiang Yang }
9478fae856cSLiang Yang 
9488fae856cSLiang Yang static void
meson_nand_op_put_dma_safe_input_buf(const struct nand_op_instr * instr,void * buf)9498fae856cSLiang Yang meson_nand_op_put_dma_safe_input_buf(const struct nand_op_instr *instr,
9508fae856cSLiang Yang 				     void *buf)
9518fae856cSLiang Yang {
9528fae856cSLiang Yang 	if (WARN_ON(instr->type != NAND_OP_DATA_IN_INSTR) ||
9538fae856cSLiang Yang 	    WARN_ON(!buf))
9548fae856cSLiang Yang 		return;
9558fae856cSLiang Yang 
9568fae856cSLiang Yang 	if (buf == instr->ctx.data.buf.in)
9578fae856cSLiang Yang 		return;
9588fae856cSLiang Yang 
9598fae856cSLiang Yang 	memcpy(instr->ctx.data.buf.in, buf, instr->ctx.data.len);
9608fae856cSLiang Yang 	kfree(buf);
9618fae856cSLiang Yang }
9628fae856cSLiang Yang 
9638fae856cSLiang Yang static void *
meson_nand_op_get_dma_safe_output_buf(const struct nand_op_instr * instr)9648fae856cSLiang Yang meson_nand_op_get_dma_safe_output_buf(const struct nand_op_instr *instr)
9658fae856cSLiang Yang {
9668fae856cSLiang Yang 	if (WARN_ON(instr->type != NAND_OP_DATA_OUT_INSTR))
9678fae856cSLiang Yang 		return NULL;
9688fae856cSLiang Yang 
9698fae856cSLiang Yang 	if (meson_nfc_is_buffer_dma_safe(instr->ctx.data.buf.out))
9708fae856cSLiang Yang 		return (void *)instr->ctx.data.buf.out;
9718fae856cSLiang Yang 
9728fae856cSLiang Yang 	return kmemdup(instr->ctx.data.buf.out,
9738fae856cSLiang Yang 		       instr->ctx.data.len, GFP_KERNEL);
9748fae856cSLiang Yang }
9758fae856cSLiang Yang 
9768fae856cSLiang Yang static void
meson_nand_op_put_dma_safe_output_buf(const struct nand_op_instr * instr,const void * buf)9778fae856cSLiang Yang meson_nand_op_put_dma_safe_output_buf(const struct nand_op_instr *instr,
9788fae856cSLiang Yang 				      const void *buf)
9798fae856cSLiang Yang {
9808fae856cSLiang Yang 	if (WARN_ON(instr->type != NAND_OP_DATA_OUT_INSTR) ||
9818fae856cSLiang Yang 	    WARN_ON(!buf))
9828fae856cSLiang Yang 		return;
9838fae856cSLiang Yang 
9848fae856cSLiang Yang 	if (buf != instr->ctx.data.buf.out)
9858fae856cSLiang Yang 		kfree(buf);
9868fae856cSLiang Yang }
9878fae856cSLiang Yang 
meson_nfc_check_op(struct nand_chip * chip,const struct nand_operation * op)98846c37b99SArseniy Krasnov static int meson_nfc_check_op(struct nand_chip *chip,
98946c37b99SArseniy Krasnov 			      const struct nand_operation *op)
99046c37b99SArseniy Krasnov {
99146c37b99SArseniy Krasnov 	int op_id;
99246c37b99SArseniy Krasnov 
99346c37b99SArseniy Krasnov 	for (op_id = 0; op_id < op->ninstrs; op_id++) {
99446c37b99SArseniy Krasnov 		const struct nand_op_instr *instr;
99546c37b99SArseniy Krasnov 
99646c37b99SArseniy Krasnov 		instr = &op->instrs[op_id];
99746c37b99SArseniy Krasnov 
99846c37b99SArseniy Krasnov 		switch (instr->type) {
99946c37b99SArseniy Krasnov 		case NAND_OP_DATA_IN_INSTR:
100046c37b99SArseniy Krasnov 		case NAND_OP_DATA_OUT_INSTR:
100146c37b99SArseniy Krasnov 			if (instr->ctx.data.len > NFC_CMD_RAW_LEN)
100246c37b99SArseniy Krasnov 				return -ENOTSUPP;
100346c37b99SArseniy Krasnov 
100446c37b99SArseniy Krasnov 			break;
100546c37b99SArseniy Krasnov 		default:
100646c37b99SArseniy Krasnov 			break;
100746c37b99SArseniy Krasnov 		}
100846c37b99SArseniy Krasnov 	}
100946c37b99SArseniy Krasnov 
101046c37b99SArseniy Krasnov 	return 0;
101146c37b99SArseniy Krasnov }
101246c37b99SArseniy Krasnov 
meson_nfc_exec_op(struct nand_chip * nand,const struct nand_operation * op,bool check_only)10138fae856cSLiang Yang static int meson_nfc_exec_op(struct nand_chip *nand,
10148fae856cSLiang Yang 			     const struct nand_operation *op, bool check_only)
10158fae856cSLiang Yang {
10168fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
10178fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
10188fae856cSLiang Yang 	const struct nand_op_instr *instr = NULL;
10198fae856cSLiang Yang 	void *buf;
10208fae856cSLiang Yang 	u32 op_id, delay_idle, cmd;
102146c37b99SArseniy Krasnov 	int err;
10228fae856cSLiang Yang 	int i;
10238fae856cSLiang Yang 
102446c37b99SArseniy Krasnov 	err = meson_nfc_check_op(nand, op);
102546c37b99SArseniy Krasnov 	if (err)
102646c37b99SArseniy Krasnov 		return err;
102746c37b99SArseniy Krasnov 
1028ce446b4bSBoris Brezillon 	if (check_only)
1029ce446b4bSBoris Brezillon 		return 0;
1030ce446b4bSBoris Brezillon 
10318fae856cSLiang Yang 	meson_nfc_select_chip(nand, op->cs);
10328fae856cSLiang Yang 	for (op_id = 0; op_id < op->ninstrs; op_id++) {
10338fae856cSLiang Yang 		instr = &op->instrs[op_id];
10348fae856cSLiang Yang 		delay_idle = DIV_ROUND_UP(PSEC_TO_NSEC(instr->delay_ns),
10358fae856cSLiang Yang 					  meson_chip->level1_divider *
10368fae856cSLiang Yang 					  NFC_CLK_CYCLE);
10378fae856cSLiang Yang 		switch (instr->type) {
10388fae856cSLiang Yang 		case NAND_OP_CMD_INSTR:
10398fae856cSLiang Yang 			cmd = nfc->param.chip_select | NFC_CMD_CLE;
10408fae856cSLiang Yang 			cmd |= instr->ctx.cmd.opcode & 0xff;
10418fae856cSLiang Yang 			writel(cmd, nfc->reg_base + NFC_REG_CMD);
10428fae856cSLiang Yang 			meson_nfc_cmd_idle(nfc, delay_idle);
10438fae856cSLiang Yang 			break;
10448fae856cSLiang Yang 
10458fae856cSLiang Yang 		case NAND_OP_ADDR_INSTR:
10468fae856cSLiang Yang 			for (i = 0; i < instr->ctx.addr.naddrs; i++) {
10478fae856cSLiang Yang 				cmd = nfc->param.chip_select | NFC_CMD_ALE;
10488fae856cSLiang Yang 				cmd |= instr->ctx.addr.addrs[i] & 0xff;
10498fae856cSLiang Yang 				writel(cmd, nfc->reg_base + NFC_REG_CMD);
10508fae856cSLiang Yang 			}
10518fae856cSLiang Yang 			meson_nfc_cmd_idle(nfc, delay_idle);
10528fae856cSLiang Yang 			break;
10538fae856cSLiang Yang 
10548fae856cSLiang Yang 		case NAND_OP_DATA_IN_INSTR:
10558fae856cSLiang Yang 			buf = meson_nand_op_get_dma_safe_input_buf(instr);
10568fae856cSLiang Yang 			if (!buf)
10578fae856cSLiang Yang 				return -ENOMEM;
10588fae856cSLiang Yang 			meson_nfc_read_buf(nand, buf, instr->ctx.data.len);
10598fae856cSLiang Yang 			meson_nand_op_put_dma_safe_input_buf(instr, buf);
10608fae856cSLiang Yang 			break;
10618fae856cSLiang Yang 
10628fae856cSLiang Yang 		case NAND_OP_DATA_OUT_INSTR:
10638fae856cSLiang Yang 			buf = meson_nand_op_get_dma_safe_output_buf(instr);
10648fae856cSLiang Yang 			if (!buf)
10658fae856cSLiang Yang 				return -ENOMEM;
10668fae856cSLiang Yang 			meson_nfc_write_buf(nand, buf, instr->ctx.data.len);
10678fae856cSLiang Yang 			meson_nand_op_put_dma_safe_output_buf(instr, buf);
10688fae856cSLiang Yang 			break;
10698fae856cSLiang Yang 
10708fae856cSLiang Yang 		case NAND_OP_WAITRDY_INSTR:
1071cda24ab7SArseniy Krasnov 			meson_nfc_queue_rb(nand, instr->ctx.waitrdy.timeout_ms,
1072c17a90a4SArseniy Krasnov 					   true);
10738fae856cSLiang Yang 			if (instr->delay_ns)
10748fae856cSLiang Yang 				meson_nfc_cmd_idle(nfc, delay_idle);
10758fae856cSLiang Yang 			break;
10768fae856cSLiang Yang 		}
10778fae856cSLiang Yang 	}
10788fae856cSLiang Yang 	meson_nfc_wait_cmd_finish(nfc, 1000);
10798fae856cSLiang Yang 	return 0;
10808fae856cSLiang Yang }
10818fae856cSLiang Yang 
meson_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)10828fae856cSLiang Yang static int meson_ooblayout_ecc(struct mtd_info *mtd, int section,
10838fae856cSLiang Yang 			       struct mtd_oob_region *oobregion)
10848fae856cSLiang Yang {
10858fae856cSLiang Yang 	struct nand_chip *nand = mtd_to_nand(mtd);
10868fae856cSLiang Yang 
10878fae856cSLiang Yang 	if (section >= nand->ecc.steps)
10888fae856cSLiang Yang 		return -ERANGE;
10898fae856cSLiang Yang 
10908fae856cSLiang Yang 	oobregion->offset =  2 + (section * (2 + nand->ecc.bytes));
10918fae856cSLiang Yang 	oobregion->length = nand->ecc.bytes;
10928fae856cSLiang Yang 
10938fae856cSLiang Yang 	return 0;
10948fae856cSLiang Yang }
10958fae856cSLiang Yang 
meson_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)10968fae856cSLiang Yang static int meson_ooblayout_free(struct mtd_info *mtd, int section,
10978fae856cSLiang Yang 				struct mtd_oob_region *oobregion)
10988fae856cSLiang Yang {
10998fae856cSLiang Yang 	struct nand_chip *nand = mtd_to_nand(mtd);
11008fae856cSLiang Yang 
11018fae856cSLiang Yang 	if (section >= nand->ecc.steps)
11028fae856cSLiang Yang 		return -ERANGE;
11038fae856cSLiang Yang 
11048fae856cSLiang Yang 	oobregion->offset = section * (2 + nand->ecc.bytes);
11058fae856cSLiang Yang 	oobregion->length = 2;
11068fae856cSLiang Yang 
11078fae856cSLiang Yang 	return 0;
11088fae856cSLiang Yang }
11098fae856cSLiang Yang 
11108fae856cSLiang Yang static const struct mtd_ooblayout_ops meson_ooblayout_ops = {
11118fae856cSLiang Yang 	.ecc = meson_ooblayout_ecc,
11128fae856cSLiang Yang 	.free = meson_ooblayout_free,
11138fae856cSLiang Yang };
11148fae856cSLiang Yang 
meson_nfc_clk_init(struct meson_nfc * nfc)11158fae856cSLiang Yang static int meson_nfc_clk_init(struct meson_nfc *nfc)
11168fae856cSLiang Yang {
11174ce341deSArseniy Krasnov 	struct clk_parent_data nfc_divider_parent_data[1] = {0};
11181e4d3ba6SLiang Yang 	struct clk_init_data init = {0};
11198fae856cSLiang Yang 	int ret;
11208fae856cSLiang Yang 
11218fae856cSLiang Yang 	/* request core clock */
11228fae856cSLiang Yang 	nfc->core_clk = devm_clk_get(nfc->dev, "core");
11238fae856cSLiang Yang 	if (IS_ERR(nfc->core_clk)) {
11248fae856cSLiang Yang 		dev_err(nfc->dev, "failed to get core clock\n");
11258fae856cSLiang Yang 		return PTR_ERR(nfc->core_clk);
11268fae856cSLiang Yang 	}
11278fae856cSLiang Yang 
11288fae856cSLiang Yang 	nfc->device_clk = devm_clk_get(nfc->dev, "device");
11298fae856cSLiang Yang 	if (IS_ERR(nfc->device_clk)) {
11308fae856cSLiang Yang 		dev_err(nfc->dev, "failed to get device clock\n");
11318fae856cSLiang Yang 		return PTR_ERR(nfc->device_clk);
11328fae856cSLiang Yang 	}
11338fae856cSLiang Yang 
11341e4d3ba6SLiang Yang 	init.name = devm_kasprintf(nfc->dev,
11351e4d3ba6SLiang Yang 				   GFP_KERNEL, "%s#div",
11361e4d3ba6SLiang Yang 				   dev_name(nfc->dev));
11374cdc83beSYi Yang 	if (!init.name)
11384cdc83beSYi Yang 		return -ENOMEM;
11394cdc83beSYi Yang 
11401e4d3ba6SLiang Yang 	init.ops = &clk_divider_ops;
11411e4d3ba6SLiang Yang 	nfc_divider_parent_data[0].fw_name = "device";
11421e4d3ba6SLiang Yang 	init.parent_data = nfc_divider_parent_data;
11431e4d3ba6SLiang Yang 	init.num_parents = 1;
11441e4d3ba6SLiang Yang 	nfc->nand_divider.reg = nfc->reg_clk;
11451e4d3ba6SLiang Yang 	nfc->nand_divider.shift = CLK_DIV_SHIFT;
11461e4d3ba6SLiang Yang 	nfc->nand_divider.width = CLK_DIV_WIDTH;
11471e4d3ba6SLiang Yang 	nfc->nand_divider.hw.init = &init;
11481e4d3ba6SLiang Yang 	nfc->nand_divider.flags = CLK_DIVIDER_ONE_BASED |
11491e4d3ba6SLiang Yang 				  CLK_DIVIDER_ROUND_CLOSEST |
11501e4d3ba6SLiang Yang 				  CLK_DIVIDER_ALLOW_ZERO;
11518fae856cSLiang Yang 
11521e4d3ba6SLiang Yang 	nfc->nand_clk = devm_clk_register(nfc->dev, &nfc->nand_divider.hw);
11531e4d3ba6SLiang Yang 	if (IS_ERR(nfc->nand_clk))
11541e4d3ba6SLiang Yang 		return PTR_ERR(nfc->nand_clk);
11558fae856cSLiang Yang 
11568fae856cSLiang Yang 	/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
11571e4d3ba6SLiang Yang 	writel(CLK_SELECT_NAND | readl(nfc->reg_clk),
11581e4d3ba6SLiang Yang 	       nfc->reg_clk);
11598fae856cSLiang Yang 
11608fae856cSLiang Yang 	ret = clk_prepare_enable(nfc->core_clk);
11618fae856cSLiang Yang 	if (ret) {
11628fae856cSLiang Yang 		dev_err(nfc->dev, "failed to enable core clock\n");
11638fae856cSLiang Yang 		return ret;
11648fae856cSLiang Yang 	}
11658fae856cSLiang Yang 
11668fae856cSLiang Yang 	ret = clk_prepare_enable(nfc->device_clk);
11678fae856cSLiang Yang 	if (ret) {
11688fae856cSLiang Yang 		dev_err(nfc->dev, "failed to enable device clock\n");
11698fae856cSLiang Yang 		goto err_device_clk;
11708fae856cSLiang Yang 	}
11718fae856cSLiang Yang 
11721e4d3ba6SLiang Yang 	ret = clk_prepare_enable(nfc->nand_clk);
11738fae856cSLiang Yang 	if (ret) {
11741e4d3ba6SLiang Yang 		dev_err(nfc->dev, "pre enable NFC divider fail\n");
11751e4d3ba6SLiang Yang 		goto err_nand_clk;
11768fae856cSLiang Yang 	}
11778fae856cSLiang Yang 
11781e4d3ba6SLiang Yang 	ret = clk_set_rate(nfc->nand_clk, 24000000);
11798fae856cSLiang Yang 	if (ret)
11801e4d3ba6SLiang Yang 		goto err_disable_clk;
11818fae856cSLiang Yang 
11828fae856cSLiang Yang 	return 0;
1183ad8566d3SDan Carpenter 
11841e4d3ba6SLiang Yang err_disable_clk:
11851e4d3ba6SLiang Yang 	clk_disable_unprepare(nfc->nand_clk);
11861e4d3ba6SLiang Yang err_nand_clk:
11878fae856cSLiang Yang 	clk_disable_unprepare(nfc->device_clk);
11888fae856cSLiang Yang err_device_clk:
11898fae856cSLiang Yang 	clk_disable_unprepare(nfc->core_clk);
11908fae856cSLiang Yang 	return ret;
11918fae856cSLiang Yang }
11928fae856cSLiang Yang 
meson_nfc_disable_clk(struct meson_nfc * nfc)11938fae856cSLiang Yang static void meson_nfc_disable_clk(struct meson_nfc *nfc)
11948fae856cSLiang Yang {
11951e4d3ba6SLiang Yang 	clk_disable_unprepare(nfc->nand_clk);
11968fae856cSLiang Yang 	clk_disable_unprepare(nfc->device_clk);
11978fae856cSLiang Yang 	clk_disable_unprepare(nfc->core_clk);
11988fae856cSLiang Yang }
11998fae856cSLiang Yang 
meson_nfc_free_buffer(struct nand_chip * nand)12008fae856cSLiang Yang static void meson_nfc_free_buffer(struct nand_chip *nand)
12018fae856cSLiang Yang {
12028fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
12038fae856cSLiang Yang 
12048fae856cSLiang Yang 	kfree(meson_chip->info_buf);
12058fae856cSLiang Yang 	kfree(meson_chip->data_buf);
12068fae856cSLiang Yang }
12078fae856cSLiang Yang 
meson_chip_buffer_init(struct nand_chip * nand)12088fae856cSLiang Yang static int meson_chip_buffer_init(struct nand_chip *nand)
12098fae856cSLiang Yang {
12108fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
12118fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
12128fae856cSLiang Yang 	u32 page_bytes, info_bytes, nsectors;
12138fae856cSLiang Yang 
12148fae856cSLiang Yang 	nsectors = mtd->writesize / nand->ecc.size;
12158fae856cSLiang Yang 
12168fae856cSLiang Yang 	page_bytes =  mtd->writesize + mtd->oobsize;
12178fae856cSLiang Yang 	info_bytes = nsectors * PER_INFO_BYTE;
12188fae856cSLiang Yang 
12198fae856cSLiang Yang 	meson_chip->data_buf = kmalloc(page_bytes, GFP_KERNEL);
12208fae856cSLiang Yang 	if (!meson_chip->data_buf)
12218fae856cSLiang Yang 		return -ENOMEM;
12228fae856cSLiang Yang 
12238fae856cSLiang Yang 	meson_chip->info_buf = kmalloc(info_bytes, GFP_KERNEL);
12248fae856cSLiang Yang 	if (!meson_chip->info_buf) {
12258fae856cSLiang Yang 		kfree(meson_chip->data_buf);
12268fae856cSLiang Yang 		return -ENOMEM;
12278fae856cSLiang Yang 	}
12288fae856cSLiang Yang 
12298fae856cSLiang Yang 	return 0;
12308fae856cSLiang Yang }
12318fae856cSLiang Yang 
12328fae856cSLiang Yang static
meson_nfc_setup_interface(struct nand_chip * nand,int csline,const struct nand_interface_config * conf)12334c46667bSMiquel Raynal int meson_nfc_setup_interface(struct nand_chip *nand, int csline,
12344c46667bSMiquel Raynal 			      const struct nand_interface_config *conf)
12358fae856cSLiang Yang {
12368fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
12378fae856cSLiang Yang 	const struct nand_sdr_timings *timings;
12388fae856cSLiang Yang 	u32 div, bt_min, bt_max, tbers_clocks;
12398fae856cSLiang Yang 
12408fae856cSLiang Yang 	timings = nand_get_sdr_timings(conf);
12418fae856cSLiang Yang 	if (IS_ERR(timings))
12428fae856cSLiang Yang 		return -ENOTSUPP;
12438fae856cSLiang Yang 
12448fae856cSLiang Yang 	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
12458fae856cSLiang Yang 		return 0;
12468fae856cSLiang Yang 
12478fae856cSLiang Yang 	div = DIV_ROUND_UP((timings->tRC_min / 1000), NFC_CLK_CYCLE);
12488fae856cSLiang Yang 	bt_min = (timings->tREA_max + NFC_DEFAULT_DELAY) / div;
12498fae856cSLiang Yang 	bt_max = (NFC_DEFAULT_DELAY + timings->tRHOH_min +
12508fae856cSLiang Yang 		  timings->tRC_min / 2) / div;
12518fae856cSLiang Yang 
12528fae856cSLiang Yang 	meson_chip->twb = DIV_ROUND_UP(PSEC_TO_NSEC(timings->tWB_max),
12538fae856cSLiang Yang 				       div * NFC_CLK_CYCLE);
12548fae856cSLiang Yang 	meson_chip->tadl = DIV_ROUND_UP(PSEC_TO_NSEC(timings->tADL_min),
12558fae856cSLiang Yang 					div * NFC_CLK_CYCLE);
12568fae856cSLiang Yang 	tbers_clocks = DIV_ROUND_UP_ULL(PSEC_TO_NSEC(timings->tBERS_max),
12578fae856cSLiang Yang 					div * NFC_CLK_CYCLE);
12588fae856cSLiang Yang 	meson_chip->tbers_max = ilog2(tbers_clocks);
12598fae856cSLiang Yang 	if (!is_power_of_2(tbers_clocks))
12608fae856cSLiang Yang 		meson_chip->tbers_max++;
12618fae856cSLiang Yang 
12628fae856cSLiang Yang 	bt_min = DIV_ROUND_UP(bt_min, 1000);
12638fae856cSLiang Yang 	bt_max = DIV_ROUND_UP(bt_max, 1000);
12648fae856cSLiang Yang 
12658fae856cSLiang Yang 	if (bt_max < bt_min)
12668fae856cSLiang Yang 		return -EINVAL;
12678fae856cSLiang Yang 
12688fae856cSLiang Yang 	meson_chip->level1_divider = div;
12698fae856cSLiang Yang 	meson_chip->clk_rate = 1000000000 / meson_chip->level1_divider;
12708fae856cSLiang Yang 	meson_chip->bus_timing = (bt_min + bt_max) / 2 + 1;
12718fae856cSLiang Yang 
12728fae856cSLiang Yang 	return 0;
12738fae856cSLiang Yang }
12748fae856cSLiang Yang 
meson_nand_bch_mode(struct nand_chip * nand)12758fae856cSLiang Yang static int meson_nand_bch_mode(struct nand_chip *nand)
12768fae856cSLiang Yang {
12778fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
12788fae856cSLiang Yang 	int i;
12798fae856cSLiang Yang 
12808fae856cSLiang Yang 	if (nand->ecc.strength > 60 || nand->ecc.strength < 8)
12818fae856cSLiang Yang 		return -EINVAL;
12828fae856cSLiang Yang 
12838fae856cSLiang Yang 	for (i = 0; i < ARRAY_SIZE(meson_ecc); i++) {
12840e1db393SArseniy Krasnov 		if (meson_ecc[i].strength == nand->ecc.strength &&
12850e1db393SArseniy Krasnov 		    meson_ecc[i].size == nand->ecc.size) {
12868fae856cSLiang Yang 			meson_chip->bch_mode = meson_ecc[i].bch;
12878fae856cSLiang Yang 			return 0;
12888fae856cSLiang Yang 		}
12898fae856cSLiang Yang 	}
12908fae856cSLiang Yang 
12918fae856cSLiang Yang 	return -EINVAL;
12928fae856cSLiang Yang }
12938fae856cSLiang Yang 
meson_nand_detach_chip(struct nand_chip * nand)12948fae856cSLiang Yang static void meson_nand_detach_chip(struct nand_chip *nand)
12958fae856cSLiang Yang {
12968fae856cSLiang Yang 	meson_nfc_free_buffer(nand);
12978fae856cSLiang Yang }
12988fae856cSLiang Yang 
meson_nand_attach_chip(struct nand_chip * nand)12998fae856cSLiang Yang static int meson_nand_attach_chip(struct nand_chip *nand)
13008fae856cSLiang Yang {
13018fae856cSLiang Yang 	struct meson_nfc *nfc = nand_get_controller_data(nand);
13028fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
13038fae856cSLiang Yang 	struct mtd_info *mtd = nand_to_mtd(nand);
130446c37b99SArseniy Krasnov 	int raw_writesize;
13058fae856cSLiang Yang 	int ret;
13068fae856cSLiang Yang 
13078fae856cSLiang Yang 	if (!mtd->name) {
13088fae856cSLiang Yang 		mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
13098fae856cSLiang Yang 					   "%s:nand%d",
13108fae856cSLiang Yang 					   dev_name(nfc->dev),
13118fae856cSLiang Yang 					   meson_chip->sels[0]);
13128fae856cSLiang Yang 		if (!mtd->name)
13138fae856cSLiang Yang 			return -ENOMEM;
13148fae856cSLiang Yang 	}
13158fae856cSLiang Yang 
131646c37b99SArseniy Krasnov 	raw_writesize = mtd->writesize + mtd->oobsize;
131746c37b99SArseniy Krasnov 	if (raw_writesize > NFC_CMD_RAW_LEN) {
131846c37b99SArseniy Krasnov 		dev_err(nfc->dev, "too big write size in raw mode: %d > %ld\n",
131946c37b99SArseniy Krasnov 			raw_writesize, NFC_CMD_RAW_LEN);
132046c37b99SArseniy Krasnov 		return -EINVAL;
132146c37b99SArseniy Krasnov 	}
132246c37b99SArseniy Krasnov 
13238fae856cSLiang Yang 	if (nand->bbt_options & NAND_BBT_USE_FLASH)
13248fae856cSLiang Yang 		nand->bbt_options |= NAND_BBT_NO_OOB;
13258fae856cSLiang Yang 
13268fae856cSLiang Yang 	nand->options |= NAND_NO_SUBPAGE_WRITE;
13278fae856cSLiang Yang 
13288fae856cSLiang Yang 	ret = nand_ecc_choose_conf(nand, nfc->data->ecc_caps,
13297e6b04f9SArseniy Krasnov 				   mtd->oobsize - 2);
13308fae856cSLiang Yang 	if (ret) {
13318fae856cSLiang Yang 		dev_err(nfc->dev, "failed to ECC init\n");
13328fae856cSLiang Yang 		return -EINVAL;
13338fae856cSLiang Yang 	}
13348fae856cSLiang Yang 
1335d090c250SLiang Yang 	mtd_set_ooblayout(mtd, &meson_ooblayout_ops);
1336d090c250SLiang Yang 
13378fae856cSLiang Yang 	ret = meson_nand_bch_mode(nand);
13388fae856cSLiang Yang 	if (ret)
13398fae856cSLiang Yang 		return -EINVAL;
13408fae856cSLiang Yang 
1341bace41f8SMiquel Raynal 	nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
13428fae856cSLiang Yang 	nand->ecc.write_page_raw = meson_nfc_write_page_raw;
13438fae856cSLiang Yang 	nand->ecc.write_page = meson_nfc_write_page_hwecc;
13448fae856cSLiang Yang 	nand->ecc.write_oob_raw = nand_write_oob_std;
13458fae856cSLiang Yang 	nand->ecc.write_oob = nand_write_oob_std;
13468fae856cSLiang Yang 
13478fae856cSLiang Yang 	nand->ecc.read_page_raw = meson_nfc_read_page_raw;
13488fae856cSLiang Yang 	nand->ecc.read_page = meson_nfc_read_page_hwecc;
13498fae856cSLiang Yang 	nand->ecc.read_oob_raw = meson_nfc_read_oob_raw;
13508fae856cSLiang Yang 	nand->ecc.read_oob = meson_nfc_read_oob;
13518fae856cSLiang Yang 
13528fae856cSLiang Yang 	if (nand->options & NAND_BUSWIDTH_16) {
13538fae856cSLiang Yang 		dev_err(nfc->dev, "16bits bus width not supported");
13548fae856cSLiang Yang 		return -EINVAL;
13558fae856cSLiang Yang 	}
13568fae856cSLiang Yang 	ret = meson_chip_buffer_init(nand);
13578fae856cSLiang Yang 	if (ret)
13588fae856cSLiang Yang 		return -ENOMEM;
13598fae856cSLiang Yang 
13608fae856cSLiang Yang 	return ret;
13618fae856cSLiang Yang }
13628fae856cSLiang Yang 
13638fae856cSLiang Yang static const struct nand_controller_ops meson_nand_controller_ops = {
13648fae856cSLiang Yang 	.attach_chip = meson_nand_attach_chip,
13658fae856cSLiang Yang 	.detach_chip = meson_nand_detach_chip,
13664c46667bSMiquel Raynal 	.setup_interface = meson_nfc_setup_interface,
13678fae856cSLiang Yang 	.exec_op = meson_nfc_exec_op,
13688fae856cSLiang Yang };
13698fae856cSLiang Yang 
13708fae856cSLiang Yang static int
meson_nfc_nand_chip_init(struct device * dev,struct meson_nfc * nfc,struct device_node * np)13718fae856cSLiang Yang meson_nfc_nand_chip_init(struct device *dev,
13728fae856cSLiang Yang 			 struct meson_nfc *nfc, struct device_node *np)
13738fae856cSLiang Yang {
13748fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip;
13758fae856cSLiang Yang 	struct nand_chip *nand;
13768fae856cSLiang Yang 	struct mtd_info *mtd;
13778fae856cSLiang Yang 	int ret, i;
13788fae856cSLiang Yang 	u32 tmp, nsels;
1379c17a90a4SArseniy Krasnov 	u32 nand_rb_val = 0;
13808fae856cSLiang Yang 
13812d8ffbf5SMartin Blumenstingl 	nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
13828fae856cSLiang Yang 	if (!nsels || nsels > MAX_CE_NUM) {
13838fae856cSLiang Yang 		dev_err(dev, "invalid register property size\n");
13848fae856cSLiang Yang 		return -EINVAL;
13858fae856cSLiang Yang 	}
13868fae856cSLiang Yang 
13875f73f240SMartin Blumenstingl 	meson_chip = devm_kzalloc(dev, struct_size(meson_chip, sels, nsels),
13888fae856cSLiang Yang 				  GFP_KERNEL);
13898fae856cSLiang Yang 	if (!meson_chip)
13908fae856cSLiang Yang 		return -ENOMEM;
13918fae856cSLiang Yang 
13928fae856cSLiang Yang 	meson_chip->nsels = nsels;
13938fae856cSLiang Yang 
13948fae856cSLiang Yang 	for (i = 0; i < nsels; i++) {
13958fae856cSLiang Yang 		ret = of_property_read_u32_index(np, "reg", i, &tmp);
13968fae856cSLiang Yang 		if (ret) {
13978fae856cSLiang Yang 			dev_err(dev, "could not retrieve register property: %d\n",
13988fae856cSLiang Yang 				ret);
13998fae856cSLiang Yang 			return ret;
14008fae856cSLiang Yang 		}
14018fae856cSLiang Yang 
14028fae856cSLiang Yang 		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
14038fae856cSLiang Yang 			dev_err(dev, "CS %d already assigned\n", tmp);
14048fae856cSLiang Yang 			return -EINVAL;
14058fae856cSLiang Yang 		}
14068fae856cSLiang Yang 	}
14078fae856cSLiang Yang 
14088fae856cSLiang Yang 	nand = &meson_chip->nand;
14098fae856cSLiang Yang 	nand->controller = &nfc->controller;
14108fae856cSLiang Yang 	nand->controller->ops = &meson_nand_controller_ops;
14118fae856cSLiang Yang 	nand_set_flash_node(nand, np);
14128fae856cSLiang Yang 	nand_set_controller_data(nand, nfc);
14138fae856cSLiang Yang 
1414ce8148d7SMiquel Raynal 	nand->options |= NAND_USES_DMA;
14158fae856cSLiang Yang 	mtd = nand_to_mtd(nand);
14168fae856cSLiang Yang 	mtd->owner = THIS_MODULE;
14178fae856cSLiang Yang 	mtd->dev.parent = dev;
14188fae856cSLiang Yang 
1419c17a90a4SArseniy Krasnov 	ret = of_property_read_u32(np, "nand-rb", &nand_rb_val);
1420c17a90a4SArseniy Krasnov 	if (ret == -EINVAL)
1421c17a90a4SArseniy Krasnov 		nfc->no_rb_pin = true;
1422c17a90a4SArseniy Krasnov 	else if (ret)
1423c17a90a4SArseniy Krasnov 		return ret;
1424c17a90a4SArseniy Krasnov 
1425c17a90a4SArseniy Krasnov 	if (nand_rb_val)
1426c17a90a4SArseniy Krasnov 		return -EINVAL;
1427c17a90a4SArseniy Krasnov 
14288fae856cSLiang Yang 	ret = nand_scan(nand, nsels);
14298fae856cSLiang Yang 	if (ret)
14308fae856cSLiang Yang 		return ret;
14318fae856cSLiang Yang 
14328fae856cSLiang Yang 	ret = mtd_device_register(mtd, NULL, 0);
14338fae856cSLiang Yang 	if (ret) {
14348fae856cSLiang Yang 		dev_err(dev, "failed to register MTD device: %d\n", ret);
14358fae856cSLiang Yang 		nand_cleanup(nand);
14368fae856cSLiang Yang 		return ret;
14378fae856cSLiang Yang 	}
14388fae856cSLiang Yang 
14398fae856cSLiang Yang 	list_add_tail(&meson_chip->node, &nfc->chips);
14408fae856cSLiang Yang 
14418fae856cSLiang Yang 	return 0;
14428fae856cSLiang Yang }
14438fae856cSLiang Yang 
meson_nfc_nand_chip_cleanup(struct meson_nfc * nfc)14447beae694SUwe Kleine-König static void meson_nfc_nand_chip_cleanup(struct meson_nfc *nfc)
14458fae856cSLiang Yang {
14468fae856cSLiang Yang 	struct meson_nfc_nand_chip *meson_chip;
14478fae856cSLiang Yang 	struct mtd_info *mtd;
14488fae856cSLiang Yang 
14498fae856cSLiang Yang 	while (!list_empty(&nfc->chips)) {
14508fae856cSLiang Yang 		meson_chip = list_first_entry(&nfc->chips,
14518fae856cSLiang Yang 					      struct meson_nfc_nand_chip, node);
14528fae856cSLiang Yang 		mtd = nand_to_mtd(&meson_chip->nand);
14537beae694SUwe Kleine-König 		WARN_ON(mtd_device_unregister(mtd));
14548fae856cSLiang Yang 
14558fae856cSLiang Yang 		nand_cleanup(&meson_chip->nand);
14568fae856cSLiang Yang 		list_del(&meson_chip->node);
14578fae856cSLiang Yang 	}
14588fae856cSLiang Yang }
14598fae856cSLiang Yang 
meson_nfc_nand_chips_init(struct device * dev,struct meson_nfc * nfc)14608fae856cSLiang Yang static int meson_nfc_nand_chips_init(struct device *dev,
14618fae856cSLiang Yang 				     struct meson_nfc *nfc)
14628fae856cSLiang Yang {
14638fae856cSLiang Yang 	struct device_node *np = dev->of_node;
14648fae856cSLiang Yang 	struct device_node *nand_np;
14658fae856cSLiang Yang 	int ret;
14668fae856cSLiang Yang 
14678fae856cSLiang Yang 	for_each_child_of_node(np, nand_np) {
14688fae856cSLiang Yang 		ret = meson_nfc_nand_chip_init(dev, nfc, nand_np);
14698fae856cSLiang Yang 		if (ret) {
14708fae856cSLiang Yang 			meson_nfc_nand_chip_cleanup(nfc);
147160be51f4SNishka Dasgupta 			of_node_put(nand_np);
14728fae856cSLiang Yang 			return ret;
14738fae856cSLiang Yang 		}
14748fae856cSLiang Yang 	}
14758fae856cSLiang Yang 
14768fae856cSLiang Yang 	return 0;
14778fae856cSLiang Yang }
14788fae856cSLiang Yang 
meson_nfc_irq(int irq,void * id)14798fae856cSLiang Yang static irqreturn_t meson_nfc_irq(int irq, void *id)
14808fae856cSLiang Yang {
14818fae856cSLiang Yang 	struct meson_nfc *nfc = id;
14828fae856cSLiang Yang 	u32 cfg;
14838fae856cSLiang Yang 
14848fae856cSLiang Yang 	cfg = readl(nfc->reg_base + NFC_REG_CFG);
14858fae856cSLiang Yang 	if (!(cfg & NFC_RB_IRQ_EN))
14868fae856cSLiang Yang 		return IRQ_NONE;
14878fae856cSLiang Yang 
14888fae856cSLiang Yang 	cfg &= ~(NFC_RB_IRQ_EN);
14898fae856cSLiang Yang 	writel(cfg, nfc->reg_base + NFC_REG_CFG);
14908fae856cSLiang Yang 
14918fae856cSLiang Yang 	complete(&nfc->completion);
14928fae856cSLiang Yang 	return IRQ_HANDLED;
14938fae856cSLiang Yang }
14948fae856cSLiang Yang 
14958fae856cSLiang Yang static const struct meson_nfc_data meson_gxl_data = {
14968fae856cSLiang Yang 	.ecc_caps = &meson_gxl_ecc_caps,
14978fae856cSLiang Yang };
14988fae856cSLiang Yang 
14998fae856cSLiang Yang static const struct meson_nfc_data meson_axg_data = {
15008fae856cSLiang Yang 	.ecc_caps = &meson_axg_ecc_caps,
15018fae856cSLiang Yang };
15028fae856cSLiang Yang 
15038fae856cSLiang Yang static const struct of_device_id meson_nfc_id_table[] = {
15048fae856cSLiang Yang 	{
15058fae856cSLiang Yang 		.compatible = "amlogic,meson-gxl-nfc",
15068fae856cSLiang Yang 		.data = &meson_gxl_data,
15078fae856cSLiang Yang 	}, {
15088fae856cSLiang Yang 		.compatible = "amlogic,meson-axg-nfc",
15098fae856cSLiang Yang 		.data = &meson_axg_data,
15108fae856cSLiang Yang 	},
15118fae856cSLiang Yang 	{}
15128fae856cSLiang Yang };
15138fae856cSLiang Yang MODULE_DEVICE_TABLE(of, meson_nfc_id_table);
15148fae856cSLiang Yang 
meson_nfc_probe(struct platform_device * pdev)15158fae856cSLiang Yang static int meson_nfc_probe(struct platform_device *pdev)
15168fae856cSLiang Yang {
15178fae856cSLiang Yang 	struct device *dev = &pdev->dev;
15188fae856cSLiang Yang 	struct meson_nfc *nfc;
15198fae856cSLiang Yang 	int ret, irq;
15208fae856cSLiang Yang 
15218fae856cSLiang Yang 	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
15228fae856cSLiang Yang 	if (!nfc)
15238fae856cSLiang Yang 		return -ENOMEM;
15248fae856cSLiang Yang 
15258fae856cSLiang Yang 	nfc->data = of_device_get_match_data(&pdev->dev);
15268fae856cSLiang Yang 	if (!nfc->data)
15278fae856cSLiang Yang 		return -ENODEV;
15288fae856cSLiang Yang 
15298fae856cSLiang Yang 	nand_controller_init(&nfc->controller);
15308fae856cSLiang Yang 	INIT_LIST_HEAD(&nfc->chips);
153139e01956SMartin Blumenstingl 	init_completion(&nfc->completion);
15328fae856cSLiang Yang 
15338fae856cSLiang Yang 	nfc->dev = dev;
15348fae856cSLiang Yang 
15355d53c615SLiang Yang 	nfc->reg_base = devm_platform_ioremap_resource_byname(pdev, "nfc");
15368fae856cSLiang Yang 	if (IS_ERR(nfc->reg_base))
15378fae856cSLiang Yang 		return PTR_ERR(nfc->reg_base);
15388fae856cSLiang Yang 
15391e4d3ba6SLiang Yang 	nfc->reg_clk = devm_platform_ioremap_resource_byname(pdev, "emmc");
15401e4d3ba6SLiang Yang 	if (IS_ERR(nfc->reg_clk))
15418fae856cSLiang Yang 		return PTR_ERR(nfc->reg_clk);
15428fae856cSLiang Yang 
15438fae856cSLiang Yang 	irq = platform_get_irq(pdev, 0);
1544aab478caSStephen Boyd 	if (irq < 0)
15458fae856cSLiang Yang 		return -EINVAL;
15468fae856cSLiang Yang 
15478fae856cSLiang Yang 	ret = meson_nfc_clk_init(nfc);
15488fae856cSLiang Yang 	if (ret) {
15498fae856cSLiang Yang 		dev_err(dev, "failed to initialize NAND clock\n");
15508fae856cSLiang Yang 		return ret;
15518fae856cSLiang Yang 	}
15528fae856cSLiang Yang 
15538fae856cSLiang Yang 	writel(0, nfc->reg_base + NFC_REG_CFG);
15548fae856cSLiang Yang 	ret = devm_request_irq(dev, irq, meson_nfc_irq, 0, dev_name(dev), nfc);
15558fae856cSLiang Yang 	if (ret) {
15568fae856cSLiang Yang 		dev_err(dev, "failed to request NFC IRQ\n");
15578fae856cSLiang Yang 		ret = -EINVAL;
15588fae856cSLiang Yang 		goto err_clk;
15598fae856cSLiang Yang 	}
15608fae856cSLiang Yang 
15618fae856cSLiang Yang 	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
15628fae856cSLiang Yang 	if (ret) {
15638fae856cSLiang Yang 		dev_err(dev, "failed to set DMA mask\n");
15648fae856cSLiang Yang 		goto err_clk;
15658fae856cSLiang Yang 	}
15668fae856cSLiang Yang 
15678fae856cSLiang Yang 	platform_set_drvdata(pdev, nfc);
15688fae856cSLiang Yang 
15698fae856cSLiang Yang 	ret = meson_nfc_nand_chips_init(dev, nfc);
15708fae856cSLiang Yang 	if (ret) {
15718fae856cSLiang Yang 		dev_err(dev, "failed to init NAND chips\n");
15728fae856cSLiang Yang 		goto err_clk;
15738fae856cSLiang Yang 	}
15748fae856cSLiang Yang 
15758fae856cSLiang Yang 	return 0;
15768fae856cSLiang Yang err_clk:
15778fae856cSLiang Yang 	meson_nfc_disable_clk(nfc);
15788fae856cSLiang Yang 	return ret;
15798fae856cSLiang Yang }
15808fae856cSLiang Yang 
meson_nfc_remove(struct platform_device * pdev)1581ec185b18SUwe Kleine-König static void meson_nfc_remove(struct platform_device *pdev)
15828fae856cSLiang Yang {
15838fae856cSLiang Yang 	struct meson_nfc *nfc = platform_get_drvdata(pdev);
15848fae856cSLiang Yang 
15857beae694SUwe Kleine-König 	meson_nfc_nand_chip_cleanup(nfc);
15868fae856cSLiang Yang 
15878fae856cSLiang Yang 	meson_nfc_disable_clk(nfc);
15888fae856cSLiang Yang }
15898fae856cSLiang Yang 
15908fae856cSLiang Yang static struct platform_driver meson_nfc_driver = {
15918fae856cSLiang Yang 	.probe  = meson_nfc_probe,
1592ec185b18SUwe Kleine-König 	.remove_new = meson_nfc_remove,
15938fae856cSLiang Yang 	.driver = {
15948fae856cSLiang Yang 		.name  = "meson-nand",
15958fae856cSLiang Yang 		.of_match_table = meson_nfc_id_table,
15968fae856cSLiang Yang 	},
15978fae856cSLiang Yang };
15988fae856cSLiang Yang module_platform_driver(meson_nfc_driver);
15998fae856cSLiang Yang 
16008fae856cSLiang Yang MODULE_LICENSE("Dual MIT/GPL");
16018fae856cSLiang Yang MODULE_AUTHOR("Liang Yang <liang.yang@amlogic.com>");
16028fae856cSLiang Yang MODULE_DESCRIPTION("Amlogic's Meson NAND Flash Controller driver");
1603