11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon  * Copyright © 2010-2015 Broadcom Corporation
493db446aSBoris Brezillon  */
593db446aSBoris Brezillon 
693db446aSBoris Brezillon #include <linux/clk.h>
793db446aSBoris Brezillon #include <linux/module.h>
893db446aSBoris Brezillon #include <linux/init.h>
993db446aSBoris Brezillon #include <linux/delay.h>
1093db446aSBoris Brezillon #include <linux/device.h>
1193db446aSBoris Brezillon #include <linux/platform_device.h>
1293db446aSBoris Brezillon #include <linux/err.h>
1393db446aSBoris Brezillon #include <linux/completion.h>
1493db446aSBoris Brezillon #include <linux/interrupt.h>
1593db446aSBoris Brezillon #include <linux/spinlock.h>
1693db446aSBoris Brezillon #include <linux/dma-mapping.h>
1793db446aSBoris Brezillon #include <linux/ioport.h>
1893db446aSBoris Brezillon #include <linux/bug.h>
1993db446aSBoris Brezillon #include <linux/kernel.h>
2093db446aSBoris Brezillon #include <linux/bitops.h>
2193db446aSBoris Brezillon #include <linux/mm.h>
2293db446aSBoris Brezillon #include <linux/mtd/mtd.h>
2393db446aSBoris Brezillon #include <linux/mtd/rawnand.h>
2493db446aSBoris Brezillon #include <linux/mtd/partitions.h>
2593db446aSBoris Brezillon #include <linux/of.h>
2693db446aSBoris Brezillon #include <linux/of_platform.h>
2793db446aSBoris Brezillon #include <linux/slab.h>
2893db446aSBoris Brezillon #include <linux/list.h>
2993db446aSBoris Brezillon #include <linux/log2.h>
3093db446aSBoris Brezillon 
3193db446aSBoris Brezillon #include "brcmnand.h"
3293db446aSBoris Brezillon 
3393db446aSBoris Brezillon /*
3493db446aSBoris Brezillon  * This flag controls if WP stays on between erase/write commands to mitigate
3593db446aSBoris Brezillon  * flash corruption due to power glitches. Values:
3693db446aSBoris Brezillon  * 0: NAND_WP is not used or not available
3793db446aSBoris Brezillon  * 1: NAND_WP is set by default, cleared for erase/write operations
3893db446aSBoris Brezillon  * 2: NAND_WP is always cleared
3993db446aSBoris Brezillon  */
4093db446aSBoris Brezillon static int wp_on = 1;
4193db446aSBoris Brezillon module_param(wp_on, int, 0444);
4293db446aSBoris Brezillon 
4393db446aSBoris Brezillon /***********************************************************************
4493db446aSBoris Brezillon  * Definitions
4593db446aSBoris Brezillon  ***********************************************************************/
4693db446aSBoris Brezillon 
4793db446aSBoris Brezillon #define DRV_NAME			"brcmnand"
4893db446aSBoris Brezillon 
4993db446aSBoris Brezillon #define CMD_NULL			0x00
5093db446aSBoris Brezillon #define CMD_PAGE_READ			0x01
5193db446aSBoris Brezillon #define CMD_SPARE_AREA_READ		0x02
5293db446aSBoris Brezillon #define CMD_STATUS_READ			0x03
5393db446aSBoris Brezillon #define CMD_PROGRAM_PAGE		0x04
5493db446aSBoris Brezillon #define CMD_PROGRAM_SPARE_AREA		0x05
5593db446aSBoris Brezillon #define CMD_COPY_BACK			0x06
5693db446aSBoris Brezillon #define CMD_DEVICE_ID_READ		0x07
5793db446aSBoris Brezillon #define CMD_BLOCK_ERASE			0x08
5893db446aSBoris Brezillon #define CMD_FLASH_RESET			0x09
5993db446aSBoris Brezillon #define CMD_BLOCKS_LOCK			0x0a
6093db446aSBoris Brezillon #define CMD_BLOCKS_LOCK_DOWN		0x0b
6193db446aSBoris Brezillon #define CMD_BLOCKS_UNLOCK		0x0c
6293db446aSBoris Brezillon #define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
6393db446aSBoris Brezillon #define CMD_PARAMETER_READ		0x0e
6493db446aSBoris Brezillon #define CMD_PARAMETER_CHANGE_COL	0x0f
6593db446aSBoris Brezillon #define CMD_LOW_LEVEL_OP		0x10
6693db446aSBoris Brezillon 
6793db446aSBoris Brezillon struct brcm_nand_dma_desc {
6893db446aSBoris Brezillon 	u32 next_desc;
6993db446aSBoris Brezillon 	u32 next_desc_ext;
7093db446aSBoris Brezillon 	u32 cmd_irq;
7193db446aSBoris Brezillon 	u32 dram_addr;
7293db446aSBoris Brezillon 	u32 dram_addr_ext;
7393db446aSBoris Brezillon 	u32 tfr_len;
7493db446aSBoris Brezillon 	u32 total_len;
7593db446aSBoris Brezillon 	u32 flash_addr;
7693db446aSBoris Brezillon 	u32 flash_addr_ext;
7793db446aSBoris Brezillon 	u32 cs;
7893db446aSBoris Brezillon 	u32 pad2[5];
7993db446aSBoris Brezillon 	u32 status_valid;
8093db446aSBoris Brezillon } __packed;
8193db446aSBoris Brezillon 
8293db446aSBoris Brezillon /* Bitfields for brcm_nand_dma_desc::status_valid */
8393db446aSBoris Brezillon #define FLASH_DMA_ECC_ERROR	(1 << 8)
8493db446aSBoris Brezillon #define FLASH_DMA_CORR_ERROR	(1 << 9)
8593db446aSBoris Brezillon 
860c06da57SKamal Dasu /* Bitfields for DMA_MODE */
870c06da57SKamal Dasu #define FLASH_DMA_MODE_STOP_ON_ERROR	BIT(1) /* stop in Uncorr ECC error */
880c06da57SKamal Dasu #define FLASH_DMA_MODE_MODE		BIT(0) /* link list */
890c06da57SKamal Dasu #define FLASH_DMA_MODE_MASK		(FLASH_DMA_MODE_STOP_ON_ERROR |	\
900c06da57SKamal Dasu 						FLASH_DMA_MODE_MODE)
910c06da57SKamal Dasu 
9293db446aSBoris Brezillon /* 512B flash cache in the NAND controller HW */
9393db446aSBoris Brezillon #define FC_SHIFT		9U
9493db446aSBoris Brezillon #define FC_BYTES		512U
9593db446aSBoris Brezillon #define FC_WORDS		(FC_BYTES >> 2)
9693db446aSBoris Brezillon 
9793db446aSBoris Brezillon #define BRCMNAND_MIN_PAGESIZE	512
9893db446aSBoris Brezillon #define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
9993db446aSBoris Brezillon #define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
10093db446aSBoris Brezillon 
10193db446aSBoris Brezillon #define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
10293db446aSBoris Brezillon #define NAND_POLL_STATUS_TIMEOUT_MS	100
10393db446aSBoris Brezillon 
104a5d53ad2SKamal Dasu #define EDU_CMD_WRITE          0x00
105a5d53ad2SKamal Dasu #define EDU_CMD_READ           0x01
106a5d53ad2SKamal Dasu #define EDU_STATUS_ACTIVE      BIT(0)
107a5d53ad2SKamal Dasu #define EDU_ERR_STATUS_ERRACK  BIT(0)
108a5d53ad2SKamal Dasu #define EDU_DONE_MASK		GENMASK(1, 0)
109a5d53ad2SKamal Dasu 
110a5d53ad2SKamal Dasu #define EDU_CONFIG_MODE_NAND   BIT(0)
111a5d53ad2SKamal Dasu #define EDU_CONFIG_SWAP_BYTE   BIT(1)
112a5d53ad2SKamal Dasu #ifdef CONFIG_CPU_BIG_ENDIAN
113a5d53ad2SKamal Dasu #define EDU_CONFIG_SWAP_CFG     EDU_CONFIG_SWAP_BYTE
114a5d53ad2SKamal Dasu #else
115a5d53ad2SKamal Dasu #define EDU_CONFIG_SWAP_CFG     0
116a5d53ad2SKamal Dasu #endif
117a5d53ad2SKamal Dasu 
118a5d53ad2SKamal Dasu /* edu registers */
119a5d53ad2SKamal Dasu enum edu_reg {
120a5d53ad2SKamal Dasu 	EDU_CONFIG = 0,
121a5d53ad2SKamal Dasu 	EDU_DRAM_ADDR,
122a5d53ad2SKamal Dasu 	EDU_EXT_ADDR,
123a5d53ad2SKamal Dasu 	EDU_LENGTH,
124a5d53ad2SKamal Dasu 	EDU_CMD,
125a5d53ad2SKamal Dasu 	EDU_STOP,
126a5d53ad2SKamal Dasu 	EDU_STATUS,
127a5d53ad2SKamal Dasu 	EDU_DONE,
128a5d53ad2SKamal Dasu 	EDU_ERR_STATUS,
129a5d53ad2SKamal Dasu };
130a5d53ad2SKamal Dasu 
131a5d53ad2SKamal Dasu static const u16  edu_regs[] = {
132a5d53ad2SKamal Dasu 	[EDU_CONFIG] = 0x00,
133a5d53ad2SKamal Dasu 	[EDU_DRAM_ADDR] = 0x04,
134a5d53ad2SKamal Dasu 	[EDU_EXT_ADDR] = 0x08,
135a5d53ad2SKamal Dasu 	[EDU_LENGTH] = 0x0c,
136a5d53ad2SKamal Dasu 	[EDU_CMD] = 0x10,
137a5d53ad2SKamal Dasu 	[EDU_STOP] = 0x14,
138a5d53ad2SKamal Dasu 	[EDU_STATUS] = 0x18,
139a5d53ad2SKamal Dasu 	[EDU_DONE] = 0x1c,
140a5d53ad2SKamal Dasu 	[EDU_ERR_STATUS] = 0x20,
141a5d53ad2SKamal Dasu };
142a5d53ad2SKamal Dasu 
1430c06da57SKamal Dasu /* flash_dma registers */
1440c06da57SKamal Dasu enum flash_dma_reg {
1450c06da57SKamal Dasu 	FLASH_DMA_REVISION = 0,
1460c06da57SKamal Dasu 	FLASH_DMA_FIRST_DESC,
1470c06da57SKamal Dasu 	FLASH_DMA_FIRST_DESC_EXT,
1480c06da57SKamal Dasu 	FLASH_DMA_CTRL,
1490c06da57SKamal Dasu 	FLASH_DMA_MODE,
1500c06da57SKamal Dasu 	FLASH_DMA_STATUS,
1510c06da57SKamal Dasu 	FLASH_DMA_INTERRUPT_DESC,
1520c06da57SKamal Dasu 	FLASH_DMA_INTERRUPT_DESC_EXT,
1530c06da57SKamal Dasu 	FLASH_DMA_ERROR_STATUS,
1540c06da57SKamal Dasu 	FLASH_DMA_CURRENT_DESC,
1550c06da57SKamal Dasu 	FLASH_DMA_CURRENT_DESC_EXT,
1560c06da57SKamal Dasu };
1570c06da57SKamal Dasu 
15883156c1cSKamal Dasu /* flash_dma registers v0*/
15983156c1cSKamal Dasu static const u16 flash_dma_regs_v0[] = {
16083156c1cSKamal Dasu 	[FLASH_DMA_REVISION]		= 0x00,
16183156c1cSKamal Dasu 	[FLASH_DMA_FIRST_DESC]		= 0x04,
16283156c1cSKamal Dasu 	[FLASH_DMA_CTRL]		= 0x08,
16383156c1cSKamal Dasu 	[FLASH_DMA_MODE]		= 0x0c,
16483156c1cSKamal Dasu 	[FLASH_DMA_STATUS]		= 0x10,
16583156c1cSKamal Dasu 	[FLASH_DMA_INTERRUPT_DESC]	= 0x14,
16683156c1cSKamal Dasu 	[FLASH_DMA_ERROR_STATUS]	= 0x18,
16783156c1cSKamal Dasu 	[FLASH_DMA_CURRENT_DESC]	= 0x1c,
16883156c1cSKamal Dasu };
16983156c1cSKamal Dasu 
1700c06da57SKamal Dasu /* flash_dma registers v1*/
1710c06da57SKamal Dasu static const u16 flash_dma_regs_v1[] = {
1720c06da57SKamal Dasu 	[FLASH_DMA_REVISION]		= 0x00,
1730c06da57SKamal Dasu 	[FLASH_DMA_FIRST_DESC]		= 0x04,
1740c06da57SKamal Dasu 	[FLASH_DMA_FIRST_DESC_EXT]	= 0x08,
1750c06da57SKamal Dasu 	[FLASH_DMA_CTRL]		= 0x0c,
1760c06da57SKamal Dasu 	[FLASH_DMA_MODE]		= 0x10,
1770c06da57SKamal Dasu 	[FLASH_DMA_STATUS]		= 0x14,
1780c06da57SKamal Dasu 	[FLASH_DMA_INTERRUPT_DESC]	= 0x18,
1790c06da57SKamal Dasu 	[FLASH_DMA_INTERRUPT_DESC_EXT]	= 0x1c,
1800c06da57SKamal Dasu 	[FLASH_DMA_ERROR_STATUS]	= 0x20,
1810c06da57SKamal Dasu 	[FLASH_DMA_CURRENT_DESC]	= 0x24,
1820c06da57SKamal Dasu 	[FLASH_DMA_CURRENT_DESC_EXT]	= 0x28,
1830c06da57SKamal Dasu };
1840c06da57SKamal Dasu 
1850c06da57SKamal Dasu /* flash_dma registers v4 */
1860c06da57SKamal Dasu static const u16 flash_dma_regs_v4[] = {
1870c06da57SKamal Dasu 	[FLASH_DMA_REVISION]		= 0x00,
1880c06da57SKamal Dasu 	[FLASH_DMA_FIRST_DESC]		= 0x08,
1890c06da57SKamal Dasu 	[FLASH_DMA_FIRST_DESC_EXT]	= 0x0c,
1900c06da57SKamal Dasu 	[FLASH_DMA_CTRL]		= 0x10,
1910c06da57SKamal Dasu 	[FLASH_DMA_MODE]		= 0x14,
1920c06da57SKamal Dasu 	[FLASH_DMA_STATUS]		= 0x18,
1930c06da57SKamal Dasu 	[FLASH_DMA_INTERRUPT_DESC]	= 0x20,
1940c06da57SKamal Dasu 	[FLASH_DMA_INTERRUPT_DESC_EXT]	= 0x24,
1950c06da57SKamal Dasu 	[FLASH_DMA_ERROR_STATUS]	= 0x28,
1960c06da57SKamal Dasu 	[FLASH_DMA_CURRENT_DESC]	= 0x30,
1970c06da57SKamal Dasu 	[FLASH_DMA_CURRENT_DESC_EXT]	= 0x34,
1980c06da57SKamal Dasu };
1990c06da57SKamal Dasu 
20093db446aSBoris Brezillon /* Controller feature flags */
20193db446aSBoris Brezillon enum {
20293db446aSBoris Brezillon 	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
20393db446aSBoris Brezillon 	BRCMNAND_HAS_PREFETCH			= BIT(1),
20493db446aSBoris Brezillon 	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
20593db446aSBoris Brezillon 	BRCMNAND_HAS_WP				= BIT(3),
20693db446aSBoris Brezillon };
20793db446aSBoris Brezillon 
208a5d53ad2SKamal Dasu struct brcmnand_host;
209a5d53ad2SKamal Dasu 
21093db446aSBoris Brezillon struct brcmnand_controller {
21193db446aSBoris Brezillon 	struct device		*dev;
2127da45139SMiquel Raynal 	struct nand_controller	controller;
21393db446aSBoris Brezillon 	void __iomem		*nand_base;
21493db446aSBoris Brezillon 	void __iomem		*nand_fc; /* flash cache */
21593db446aSBoris Brezillon 	void __iomem		*flash_dma_base;
21693db446aSBoris Brezillon 	unsigned int		irq;
21793db446aSBoris Brezillon 	unsigned int		dma_irq;
21893db446aSBoris Brezillon 	int			nand_version;
21993db446aSBoris Brezillon 
22093db446aSBoris Brezillon 	/* Some SoCs provide custom interrupt status register(s) */
22193db446aSBoris Brezillon 	struct brcmnand_soc	*soc;
22293db446aSBoris Brezillon 
22393db446aSBoris Brezillon 	/* Some SoCs have a gateable clock for the controller */
22493db446aSBoris Brezillon 	struct clk		*clk;
22593db446aSBoris Brezillon 
22693db446aSBoris Brezillon 	int			cmd_pending;
22793db446aSBoris Brezillon 	bool			dma_pending;
228a5d53ad2SKamal Dasu 	bool                    edu_pending;
22993db446aSBoris Brezillon 	struct completion	done;
23093db446aSBoris Brezillon 	struct completion	dma_done;
231a5d53ad2SKamal Dasu 	struct completion       edu_done;
23293db446aSBoris Brezillon 
23393db446aSBoris Brezillon 	/* List of NAND hosts (one for each chip-select) */
23493db446aSBoris Brezillon 	struct list_head host_list;
23593db446aSBoris Brezillon 
236a5d53ad2SKamal Dasu 	/* EDU info, per-transaction */
237a5d53ad2SKamal Dasu 	const u16               *edu_offsets;
238a5d53ad2SKamal Dasu 	void __iomem            *edu_base;
239a5d53ad2SKamal Dasu 	int			edu_irq;
240a5d53ad2SKamal Dasu 	int                     edu_count;
241a5d53ad2SKamal Dasu 	u64                     edu_dram_addr;
242a5d53ad2SKamal Dasu 	u32                     edu_ext_addr;
243a5d53ad2SKamal Dasu 	u32                     edu_cmd;
244a5d53ad2SKamal Dasu 	u32                     edu_config;
245a5d53ad2SKamal Dasu 
2460c06da57SKamal Dasu 	/* flash_dma reg */
2470c06da57SKamal Dasu 	const u16		*flash_dma_offsets;
24893db446aSBoris Brezillon 	struct brcm_nand_dma_desc *dma_desc;
24993db446aSBoris Brezillon 	dma_addr_t		dma_pa;
25093db446aSBoris Brezillon 
251a5d53ad2SKamal Dasu 	int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf,
252a5d53ad2SKamal Dasu 			 u32 len, u8 dma_cmd);
253a5d53ad2SKamal Dasu 
25493db446aSBoris Brezillon 	/* in-memory cache of the FLASH_CACHE, used only for some commands */
25593db446aSBoris Brezillon 	u8			flash_cache[FC_BYTES];
25693db446aSBoris Brezillon 
25793db446aSBoris Brezillon 	/* Controller revision details */
25893db446aSBoris Brezillon 	const u16		*reg_offsets;
25993db446aSBoris Brezillon 	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
26093db446aSBoris Brezillon 	const u8		*cs_offsets; /* within each chip-select */
26193db446aSBoris Brezillon 	const u8		*cs0_offsets; /* within CS0, if different */
26293db446aSBoris Brezillon 	unsigned int		max_block_size;
26393db446aSBoris Brezillon 	const unsigned int	*block_sizes;
26493db446aSBoris Brezillon 	unsigned int		max_page_size;
26593db446aSBoris Brezillon 	const unsigned int	*page_sizes;
26693db446aSBoris Brezillon 	unsigned int		max_oob;
26793db446aSBoris Brezillon 	u32			features;
26893db446aSBoris Brezillon 
26993db446aSBoris Brezillon 	/* for low-power standby/resume only */
27093db446aSBoris Brezillon 	u32			nand_cs_nand_select;
27193db446aSBoris Brezillon 	u32			nand_cs_nand_xor;
27293db446aSBoris Brezillon 	u32			corr_stat_threshold;
27393db446aSBoris Brezillon 	u32			flash_dma_mode;
274a5d53ad2SKamal Dasu 	u32                     flash_edu_mode;
275c1ac2dc3SKamal Dasu 	bool			pio_poll_mode;
27693db446aSBoris Brezillon };
27793db446aSBoris Brezillon 
27893db446aSBoris Brezillon struct brcmnand_cfg {
27993db446aSBoris Brezillon 	u64			device_size;
28093db446aSBoris Brezillon 	unsigned int		block_size;
28193db446aSBoris Brezillon 	unsigned int		page_size;
28293db446aSBoris Brezillon 	unsigned int		spare_area_size;
28393db446aSBoris Brezillon 	unsigned int		device_width;
28493db446aSBoris Brezillon 	unsigned int		col_adr_bytes;
28593db446aSBoris Brezillon 	unsigned int		blk_adr_bytes;
28693db446aSBoris Brezillon 	unsigned int		ful_adr_bytes;
28793db446aSBoris Brezillon 	unsigned int		sector_size_1k;
28893db446aSBoris Brezillon 	unsigned int		ecc_level;
28993db446aSBoris Brezillon 	/* use for low-power standby/resume only */
29093db446aSBoris Brezillon 	u32			acc_control;
29193db446aSBoris Brezillon 	u32			config;
29293db446aSBoris Brezillon 	u32			config_ext;
29393db446aSBoris Brezillon 	u32			timing_1;
29493db446aSBoris Brezillon 	u32			timing_2;
29593db446aSBoris Brezillon };
29693db446aSBoris Brezillon 
29793db446aSBoris Brezillon struct brcmnand_host {
29893db446aSBoris Brezillon 	struct list_head	node;
29993db446aSBoris Brezillon 
30093db446aSBoris Brezillon 	struct nand_chip	chip;
30193db446aSBoris Brezillon 	struct platform_device	*pdev;
30293db446aSBoris Brezillon 	int			cs;
30393db446aSBoris Brezillon 
30493db446aSBoris Brezillon 	unsigned int		last_cmd;
30593db446aSBoris Brezillon 	unsigned int		last_byte;
30693db446aSBoris Brezillon 	u64			last_addr;
30793db446aSBoris Brezillon 	struct brcmnand_cfg	hwcfg;
30893db446aSBoris Brezillon 	struct brcmnand_controller *ctrl;
30993db446aSBoris Brezillon };
31093db446aSBoris Brezillon 
31193db446aSBoris Brezillon enum brcmnand_reg {
31293db446aSBoris Brezillon 	BRCMNAND_CMD_START = 0,
31393db446aSBoris Brezillon 	BRCMNAND_CMD_EXT_ADDRESS,
31493db446aSBoris Brezillon 	BRCMNAND_CMD_ADDRESS,
31593db446aSBoris Brezillon 	BRCMNAND_INTFC_STATUS,
31693db446aSBoris Brezillon 	BRCMNAND_CS_SELECT,
31793db446aSBoris Brezillon 	BRCMNAND_CS_XOR,
31893db446aSBoris Brezillon 	BRCMNAND_LL_OP,
31993db446aSBoris Brezillon 	BRCMNAND_CS0_BASE,
32093db446aSBoris Brezillon 	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
32193db446aSBoris Brezillon 	BRCMNAND_CORR_THRESHOLD,
32293db446aSBoris Brezillon 	BRCMNAND_CORR_THRESHOLD_EXT,
32393db446aSBoris Brezillon 	BRCMNAND_UNCORR_COUNT,
32493db446aSBoris Brezillon 	BRCMNAND_CORR_COUNT,
32593db446aSBoris Brezillon 	BRCMNAND_CORR_EXT_ADDR,
32693db446aSBoris Brezillon 	BRCMNAND_CORR_ADDR,
32793db446aSBoris Brezillon 	BRCMNAND_UNCORR_EXT_ADDR,
32893db446aSBoris Brezillon 	BRCMNAND_UNCORR_ADDR,
32993db446aSBoris Brezillon 	BRCMNAND_SEMAPHORE,
33093db446aSBoris Brezillon 	BRCMNAND_ID,
33193db446aSBoris Brezillon 	BRCMNAND_ID_EXT,
33293db446aSBoris Brezillon 	BRCMNAND_LL_RDATA,
33393db446aSBoris Brezillon 	BRCMNAND_OOB_READ_BASE,
33493db446aSBoris Brezillon 	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
33593db446aSBoris Brezillon 	BRCMNAND_OOB_WRITE_BASE,
33693db446aSBoris Brezillon 	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
33793db446aSBoris Brezillon 	BRCMNAND_FC_BASE,
33893db446aSBoris Brezillon };
33993db446aSBoris Brezillon 
34093db446aSBoris Brezillon /* BRCMNAND v4.0 */
34193db446aSBoris Brezillon static const u16 brcmnand_regs_v40[] = {
34293db446aSBoris Brezillon 	[BRCMNAND_CMD_START]		=  0x04,
34393db446aSBoris Brezillon 	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
34493db446aSBoris Brezillon 	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
34593db446aSBoris Brezillon 	[BRCMNAND_INTFC_STATUS]		=  0x6c,
34693db446aSBoris Brezillon 	[BRCMNAND_CS_SELECT]		=  0x14,
34793db446aSBoris Brezillon 	[BRCMNAND_CS_XOR]		=  0x18,
34893db446aSBoris Brezillon 	[BRCMNAND_LL_OP]		= 0x178,
34993db446aSBoris Brezillon 	[BRCMNAND_CS0_BASE]		=  0x40,
35093db446aSBoris Brezillon 	[BRCMNAND_CS1_BASE]		=  0xd0,
35193db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
35293db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
35393db446aSBoris Brezillon 	[BRCMNAND_UNCORR_COUNT]		=     0,
35493db446aSBoris Brezillon 	[BRCMNAND_CORR_COUNT]		=     0,
35593db446aSBoris Brezillon 	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
35693db446aSBoris Brezillon 	[BRCMNAND_CORR_ADDR]		=  0x74,
35793db446aSBoris Brezillon 	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
35893db446aSBoris Brezillon 	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
35993db446aSBoris Brezillon 	[BRCMNAND_SEMAPHORE]		=  0x58,
36093db446aSBoris Brezillon 	[BRCMNAND_ID]			=  0x60,
36193db446aSBoris Brezillon 	[BRCMNAND_ID_EXT]		=  0x64,
36293db446aSBoris Brezillon 	[BRCMNAND_LL_RDATA]		= 0x17c,
36393db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_BASE]	=  0x20,
36493db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
36593db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
36693db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
36793db446aSBoris Brezillon 	[BRCMNAND_FC_BASE]		= 0x200,
36893db446aSBoris Brezillon };
36993db446aSBoris Brezillon 
37093db446aSBoris Brezillon /* BRCMNAND v5.0 */
37193db446aSBoris Brezillon static const u16 brcmnand_regs_v50[] = {
37293db446aSBoris Brezillon 	[BRCMNAND_CMD_START]		=  0x04,
37393db446aSBoris Brezillon 	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
37493db446aSBoris Brezillon 	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
37593db446aSBoris Brezillon 	[BRCMNAND_INTFC_STATUS]		=  0x6c,
37693db446aSBoris Brezillon 	[BRCMNAND_CS_SELECT]		=  0x14,
37793db446aSBoris Brezillon 	[BRCMNAND_CS_XOR]		=  0x18,
37893db446aSBoris Brezillon 	[BRCMNAND_LL_OP]		= 0x178,
37993db446aSBoris Brezillon 	[BRCMNAND_CS0_BASE]		=  0x40,
38093db446aSBoris Brezillon 	[BRCMNAND_CS1_BASE]		=  0xd0,
38193db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
38293db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
38393db446aSBoris Brezillon 	[BRCMNAND_UNCORR_COUNT]		=     0,
38493db446aSBoris Brezillon 	[BRCMNAND_CORR_COUNT]		=     0,
38593db446aSBoris Brezillon 	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
38693db446aSBoris Brezillon 	[BRCMNAND_CORR_ADDR]		=  0x74,
38793db446aSBoris Brezillon 	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
38893db446aSBoris Brezillon 	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
38993db446aSBoris Brezillon 	[BRCMNAND_SEMAPHORE]		=  0x58,
39093db446aSBoris Brezillon 	[BRCMNAND_ID]			=  0x60,
39193db446aSBoris Brezillon 	[BRCMNAND_ID_EXT]		=  0x64,
39293db446aSBoris Brezillon 	[BRCMNAND_LL_RDATA]		= 0x17c,
39393db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_BASE]	=  0x20,
39493db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
39593db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
39693db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
39793db446aSBoris Brezillon 	[BRCMNAND_FC_BASE]		= 0x200,
39893db446aSBoris Brezillon };
39993db446aSBoris Brezillon 
40093db446aSBoris Brezillon /* BRCMNAND v6.0 - v7.1 */
40193db446aSBoris Brezillon static const u16 brcmnand_regs_v60[] = {
40293db446aSBoris Brezillon 	[BRCMNAND_CMD_START]		=  0x04,
40393db446aSBoris Brezillon 	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
40493db446aSBoris Brezillon 	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
40593db446aSBoris Brezillon 	[BRCMNAND_INTFC_STATUS]		=  0x14,
40693db446aSBoris Brezillon 	[BRCMNAND_CS_SELECT]		=  0x18,
40793db446aSBoris Brezillon 	[BRCMNAND_CS_XOR]		=  0x1c,
40893db446aSBoris Brezillon 	[BRCMNAND_LL_OP]		=  0x20,
40993db446aSBoris Brezillon 	[BRCMNAND_CS0_BASE]		=  0x50,
41093db446aSBoris Brezillon 	[BRCMNAND_CS1_BASE]		=     0,
41193db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
41293db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
41393db446aSBoris Brezillon 	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
41493db446aSBoris Brezillon 	[BRCMNAND_CORR_COUNT]		= 0x100,
41593db446aSBoris Brezillon 	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
41693db446aSBoris Brezillon 	[BRCMNAND_CORR_ADDR]		= 0x110,
41793db446aSBoris Brezillon 	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
41893db446aSBoris Brezillon 	[BRCMNAND_UNCORR_ADDR]		= 0x118,
41993db446aSBoris Brezillon 	[BRCMNAND_SEMAPHORE]		= 0x150,
42093db446aSBoris Brezillon 	[BRCMNAND_ID]			= 0x194,
42193db446aSBoris Brezillon 	[BRCMNAND_ID_EXT]		= 0x198,
42293db446aSBoris Brezillon 	[BRCMNAND_LL_RDATA]		= 0x19c,
42393db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_BASE]	= 0x200,
42493db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_10_BASE]	=     0,
42593db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
42693db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
42793db446aSBoris Brezillon 	[BRCMNAND_FC_BASE]		= 0x400,
42893db446aSBoris Brezillon };
42993db446aSBoris Brezillon 
43093db446aSBoris Brezillon /* BRCMNAND v7.1 */
43193db446aSBoris Brezillon static const u16 brcmnand_regs_v71[] = {
43293db446aSBoris Brezillon 	[BRCMNAND_CMD_START]		=  0x04,
43393db446aSBoris Brezillon 	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
43493db446aSBoris Brezillon 	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
43593db446aSBoris Brezillon 	[BRCMNAND_INTFC_STATUS]		=  0x14,
43693db446aSBoris Brezillon 	[BRCMNAND_CS_SELECT]		=  0x18,
43793db446aSBoris Brezillon 	[BRCMNAND_CS_XOR]		=  0x1c,
43893db446aSBoris Brezillon 	[BRCMNAND_LL_OP]		=  0x20,
43993db446aSBoris Brezillon 	[BRCMNAND_CS0_BASE]		=  0x50,
44093db446aSBoris Brezillon 	[BRCMNAND_CS1_BASE]		=     0,
44193db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
44293db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
44393db446aSBoris Brezillon 	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
44493db446aSBoris Brezillon 	[BRCMNAND_CORR_COUNT]		= 0x100,
44593db446aSBoris Brezillon 	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
44693db446aSBoris Brezillon 	[BRCMNAND_CORR_ADDR]		= 0x110,
44793db446aSBoris Brezillon 	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
44893db446aSBoris Brezillon 	[BRCMNAND_UNCORR_ADDR]		= 0x118,
44993db446aSBoris Brezillon 	[BRCMNAND_SEMAPHORE]		= 0x150,
45093db446aSBoris Brezillon 	[BRCMNAND_ID]			= 0x194,
45193db446aSBoris Brezillon 	[BRCMNAND_ID_EXT]		= 0x198,
45293db446aSBoris Brezillon 	[BRCMNAND_LL_RDATA]		= 0x19c,
45393db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_BASE]	= 0x200,
45493db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_10_BASE]	=     0,
45593db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
45693db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
45793db446aSBoris Brezillon 	[BRCMNAND_FC_BASE]		= 0x400,
45893db446aSBoris Brezillon };
45993db446aSBoris Brezillon 
46093db446aSBoris Brezillon /* BRCMNAND v7.2 */
46193db446aSBoris Brezillon static const u16 brcmnand_regs_v72[] = {
46293db446aSBoris Brezillon 	[BRCMNAND_CMD_START]		=  0x04,
46393db446aSBoris Brezillon 	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
46493db446aSBoris Brezillon 	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
46593db446aSBoris Brezillon 	[BRCMNAND_INTFC_STATUS]		=  0x14,
46693db446aSBoris Brezillon 	[BRCMNAND_CS_SELECT]		=  0x18,
46793db446aSBoris Brezillon 	[BRCMNAND_CS_XOR]		=  0x1c,
46893db446aSBoris Brezillon 	[BRCMNAND_LL_OP]		=  0x20,
46993db446aSBoris Brezillon 	[BRCMNAND_CS0_BASE]		=  0x50,
47093db446aSBoris Brezillon 	[BRCMNAND_CS1_BASE]		=     0,
47193db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
47293db446aSBoris Brezillon 	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
47393db446aSBoris Brezillon 	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
47493db446aSBoris Brezillon 	[BRCMNAND_CORR_COUNT]		= 0x100,
47593db446aSBoris Brezillon 	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
47693db446aSBoris Brezillon 	[BRCMNAND_CORR_ADDR]		= 0x110,
47793db446aSBoris Brezillon 	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
47893db446aSBoris Brezillon 	[BRCMNAND_UNCORR_ADDR]		= 0x118,
47993db446aSBoris Brezillon 	[BRCMNAND_SEMAPHORE]		= 0x150,
48093db446aSBoris Brezillon 	[BRCMNAND_ID]			= 0x194,
48193db446aSBoris Brezillon 	[BRCMNAND_ID_EXT]		= 0x198,
48293db446aSBoris Brezillon 	[BRCMNAND_LL_RDATA]		= 0x19c,
48393db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_BASE]	= 0x200,
48493db446aSBoris Brezillon 	[BRCMNAND_OOB_READ_10_BASE]	=     0,
48593db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
48693db446aSBoris Brezillon 	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
48793db446aSBoris Brezillon 	[BRCMNAND_FC_BASE]		= 0x600,
48893db446aSBoris Brezillon };
48993db446aSBoris Brezillon 
49093db446aSBoris Brezillon enum brcmnand_cs_reg {
49193db446aSBoris Brezillon 	BRCMNAND_CS_CFG_EXT = 0,
49293db446aSBoris Brezillon 	BRCMNAND_CS_CFG,
49393db446aSBoris Brezillon 	BRCMNAND_CS_ACC_CONTROL,
49493db446aSBoris Brezillon 	BRCMNAND_CS_TIMING1,
49593db446aSBoris Brezillon 	BRCMNAND_CS_TIMING2,
49693db446aSBoris Brezillon };
49793db446aSBoris Brezillon 
49893db446aSBoris Brezillon /* Per chip-select offsets for v7.1 */
49993db446aSBoris Brezillon static const u8 brcmnand_cs_offsets_v71[] = {
50093db446aSBoris Brezillon 	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
50193db446aSBoris Brezillon 	[BRCMNAND_CS_CFG_EXT]		= 0x04,
50293db446aSBoris Brezillon 	[BRCMNAND_CS_CFG]		= 0x08,
50393db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING1]		= 0x0c,
50493db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING2]		= 0x10,
50593db446aSBoris Brezillon };
50693db446aSBoris Brezillon 
50793db446aSBoris Brezillon /* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
50893db446aSBoris Brezillon static const u8 brcmnand_cs_offsets[] = {
50993db446aSBoris Brezillon 	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
51093db446aSBoris Brezillon 	[BRCMNAND_CS_CFG_EXT]		= 0x04,
51193db446aSBoris Brezillon 	[BRCMNAND_CS_CFG]		= 0x04,
51293db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING1]		= 0x08,
51393db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING2]		= 0x0c,
51493db446aSBoris Brezillon };
51593db446aSBoris Brezillon 
51693db446aSBoris Brezillon /* Per chip-select offset for <= v5.0 on CS0 only */
51793db446aSBoris Brezillon static const u8 brcmnand_cs_offsets_cs0[] = {
51893db446aSBoris Brezillon 	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
51993db446aSBoris Brezillon 	[BRCMNAND_CS_CFG_EXT]		= 0x08,
52093db446aSBoris Brezillon 	[BRCMNAND_CS_CFG]		= 0x08,
52193db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING1]		= 0x10,
52293db446aSBoris Brezillon 	[BRCMNAND_CS_TIMING2]		= 0x14,
52393db446aSBoris Brezillon };
52493db446aSBoris Brezillon 
52593db446aSBoris Brezillon /*
52693db446aSBoris Brezillon  * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
52793db446aSBoris Brezillon  * one config register, but once the bitfields overflowed, newer controllers
52893db446aSBoris Brezillon  * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
52993db446aSBoris Brezillon  */
53093db446aSBoris Brezillon enum {
53193db446aSBoris Brezillon 	CFG_BLK_ADR_BYTES_SHIFT		= 8,
53293db446aSBoris Brezillon 	CFG_COL_ADR_BYTES_SHIFT		= 12,
53393db446aSBoris Brezillon 	CFG_FUL_ADR_BYTES_SHIFT		= 16,
53493db446aSBoris Brezillon 	CFG_BUS_WIDTH_SHIFT		= 23,
53593db446aSBoris Brezillon 	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
53693db446aSBoris Brezillon 	CFG_DEVICE_SIZE_SHIFT		= 24,
53793db446aSBoris Brezillon 
53893db446aSBoris Brezillon 	/* Only for pre-v7.1 (with no CFG_EXT register) */
53993db446aSBoris Brezillon 	CFG_PAGE_SIZE_SHIFT		= 20,
54093db446aSBoris Brezillon 	CFG_BLK_SIZE_SHIFT		= 28,
54193db446aSBoris Brezillon 
54293db446aSBoris Brezillon 	/* Only for v7.1+ (with CFG_EXT register) */
54393db446aSBoris Brezillon 	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
54493db446aSBoris Brezillon 	CFG_EXT_BLK_SIZE_SHIFT		= 4,
54593db446aSBoris Brezillon };
54693db446aSBoris Brezillon 
54793db446aSBoris Brezillon /* BRCMNAND_INTFC_STATUS */
54893db446aSBoris Brezillon enum {
54993db446aSBoris Brezillon 	INTFC_FLASH_STATUS		= GENMASK(7, 0),
55093db446aSBoris Brezillon 
55193db446aSBoris Brezillon 	INTFC_ERASED			= BIT(27),
55293db446aSBoris Brezillon 	INTFC_OOB_VALID			= BIT(28),
55393db446aSBoris Brezillon 	INTFC_CACHE_VALID		= BIT(29),
55493db446aSBoris Brezillon 	INTFC_FLASH_READY		= BIT(30),
55593db446aSBoris Brezillon 	INTFC_CTLR_READY		= BIT(31),
55693db446aSBoris Brezillon };
55793db446aSBoris Brezillon 
55893db446aSBoris Brezillon static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
55993db446aSBoris Brezillon {
56093db446aSBoris Brezillon 	return brcmnand_readl(ctrl->nand_base + offs);
56193db446aSBoris Brezillon }
56293db446aSBoris Brezillon 
56393db446aSBoris Brezillon static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
56493db446aSBoris Brezillon 				 u32 val)
56593db446aSBoris Brezillon {
56693db446aSBoris Brezillon 	brcmnand_writel(val, ctrl->nand_base + offs);
56793db446aSBoris Brezillon }
56893db446aSBoris Brezillon 
56993db446aSBoris Brezillon static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
57093db446aSBoris Brezillon {
57193db446aSBoris Brezillon 	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
57293db446aSBoris Brezillon 	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
57393db446aSBoris Brezillon 	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
57493db446aSBoris Brezillon 
57593db446aSBoris Brezillon 	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
57693db446aSBoris Brezillon 
57793db446aSBoris Brezillon 	/* Only support v4.0+? */
57893db446aSBoris Brezillon 	if (ctrl->nand_version < 0x0400) {
57993db446aSBoris Brezillon 		dev_err(ctrl->dev, "version %#x not supported\n",
58093db446aSBoris Brezillon 			ctrl->nand_version);
58193db446aSBoris Brezillon 		return -ENODEV;
58293db446aSBoris Brezillon 	}
58393db446aSBoris Brezillon 
58493db446aSBoris Brezillon 	/* Register offsets */
58593db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0702)
58693db446aSBoris Brezillon 		ctrl->reg_offsets = brcmnand_regs_v72;
5870c06da57SKamal Dasu 	else if (ctrl->nand_version == 0x0701)
58893db446aSBoris Brezillon 		ctrl->reg_offsets = brcmnand_regs_v71;
58993db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0600)
59093db446aSBoris Brezillon 		ctrl->reg_offsets = brcmnand_regs_v60;
59193db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0500)
59293db446aSBoris Brezillon 		ctrl->reg_offsets = brcmnand_regs_v50;
59393db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0400)
59493db446aSBoris Brezillon 		ctrl->reg_offsets = brcmnand_regs_v40;
59593db446aSBoris Brezillon 
59693db446aSBoris Brezillon 	/* Chip-select stride */
59793db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0701)
59893db446aSBoris Brezillon 		ctrl->reg_spacing = 0x14;
59993db446aSBoris Brezillon 	else
60093db446aSBoris Brezillon 		ctrl->reg_spacing = 0x10;
60193db446aSBoris Brezillon 
60293db446aSBoris Brezillon 	/* Per chip-select registers */
60393db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0701) {
60493db446aSBoris Brezillon 		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
60593db446aSBoris Brezillon 	} else {
60693db446aSBoris Brezillon 		ctrl->cs_offsets = brcmnand_cs_offsets;
60793db446aSBoris Brezillon 
60893db446aSBoris Brezillon 		/* v5.0 and earlier has a different CS0 offset layout */
60993db446aSBoris Brezillon 		if (ctrl->nand_version <= 0x0500)
61093db446aSBoris Brezillon 			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
61193db446aSBoris Brezillon 	}
61293db446aSBoris Brezillon 
61393db446aSBoris Brezillon 	/* Page / block sizes */
61493db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0701) {
61593db446aSBoris Brezillon 		/* >= v7.1 use nice power-of-2 values! */
61693db446aSBoris Brezillon 		ctrl->max_page_size = 16 * 1024;
61793db446aSBoris Brezillon 		ctrl->max_block_size = 2 * 1024 * 1024;
61893db446aSBoris Brezillon 	} else {
61993db446aSBoris Brezillon 		ctrl->page_sizes = page_sizes;
62093db446aSBoris Brezillon 		if (ctrl->nand_version >= 0x0600)
62193db446aSBoris Brezillon 			ctrl->block_sizes = block_sizes_v6;
62293db446aSBoris Brezillon 		else
62393db446aSBoris Brezillon 			ctrl->block_sizes = block_sizes_v4;
62493db446aSBoris Brezillon 
62593db446aSBoris Brezillon 		if (ctrl->nand_version < 0x0400) {
62693db446aSBoris Brezillon 			ctrl->max_page_size = 4096;
62793db446aSBoris Brezillon 			ctrl->max_block_size = 512 * 1024;
62893db446aSBoris Brezillon 		}
62993db446aSBoris Brezillon 	}
63093db446aSBoris Brezillon 
63193db446aSBoris Brezillon 	/* Maximum spare area sector size (per 512B) */
6320c06da57SKamal Dasu 	if (ctrl->nand_version == 0x0702)
63393db446aSBoris Brezillon 		ctrl->max_oob = 128;
63493db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0600)
63593db446aSBoris Brezillon 		ctrl->max_oob = 64;
63693db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0500)
63793db446aSBoris Brezillon 		ctrl->max_oob = 32;
63893db446aSBoris Brezillon 	else
63993db446aSBoris Brezillon 		ctrl->max_oob = 16;
64093db446aSBoris Brezillon 
64193db446aSBoris Brezillon 	/* v6.0 and newer (except v6.1) have prefetch support */
64293db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
64393db446aSBoris Brezillon 		ctrl->features |= BRCMNAND_HAS_PREFETCH;
64493db446aSBoris Brezillon 
64593db446aSBoris Brezillon 	/*
64693db446aSBoris Brezillon 	 * v6.x has cache mode, but it's implemented differently. Ignore it for
64793db446aSBoris Brezillon 	 * now.
64893db446aSBoris Brezillon 	 */
64993db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0700)
65093db446aSBoris Brezillon 		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
65193db446aSBoris Brezillon 
65293db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0500)
65393db446aSBoris Brezillon 		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
65493db446aSBoris Brezillon 
65593db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0700)
65693db446aSBoris Brezillon 		ctrl->features |= BRCMNAND_HAS_WP;
65793db446aSBoris Brezillon 	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
65893db446aSBoris Brezillon 		ctrl->features |= BRCMNAND_HAS_WP;
65993db446aSBoris Brezillon 
66093db446aSBoris Brezillon 	return 0;
66193db446aSBoris Brezillon }
66293db446aSBoris Brezillon 
6630c06da57SKamal Dasu static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl)
6640c06da57SKamal Dasu {
6650c06da57SKamal Dasu 	/* flash_dma register offsets */
6660c06da57SKamal Dasu 	if (ctrl->nand_version >= 0x0703)
6670c06da57SKamal Dasu 		ctrl->flash_dma_offsets = flash_dma_regs_v4;
66883156c1cSKamal Dasu 	else if (ctrl->nand_version == 0x0602)
66983156c1cSKamal Dasu 		ctrl->flash_dma_offsets = flash_dma_regs_v0;
6700c06da57SKamal Dasu 	else
6710c06da57SKamal Dasu 		ctrl->flash_dma_offsets = flash_dma_regs_v1;
6720c06da57SKamal Dasu }
6730c06da57SKamal Dasu 
67493db446aSBoris Brezillon static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
67593db446aSBoris Brezillon 		enum brcmnand_reg reg)
67693db446aSBoris Brezillon {
67793db446aSBoris Brezillon 	u16 offs = ctrl->reg_offsets[reg];
67893db446aSBoris Brezillon 
67993db446aSBoris Brezillon 	if (offs)
68093db446aSBoris Brezillon 		return nand_readreg(ctrl, offs);
68193db446aSBoris Brezillon 	else
68293db446aSBoris Brezillon 		return 0;
68393db446aSBoris Brezillon }
68493db446aSBoris Brezillon 
68593db446aSBoris Brezillon static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
68693db446aSBoris Brezillon 				      enum brcmnand_reg reg, u32 val)
68793db446aSBoris Brezillon {
68893db446aSBoris Brezillon 	u16 offs = ctrl->reg_offsets[reg];
68993db446aSBoris Brezillon 
69093db446aSBoris Brezillon 	if (offs)
69193db446aSBoris Brezillon 		nand_writereg(ctrl, offs, val);
69293db446aSBoris Brezillon }
69393db446aSBoris Brezillon 
69493db446aSBoris Brezillon static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
69593db446aSBoris Brezillon 				    enum brcmnand_reg reg, u32 mask, unsigned
69693db446aSBoris Brezillon 				    int shift, u32 val)
69793db446aSBoris Brezillon {
69893db446aSBoris Brezillon 	u32 tmp = brcmnand_read_reg(ctrl, reg);
69993db446aSBoris Brezillon 
70093db446aSBoris Brezillon 	tmp &= ~mask;
70193db446aSBoris Brezillon 	tmp |= val << shift;
70293db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, reg, tmp);
70393db446aSBoris Brezillon }
70493db446aSBoris Brezillon 
70593db446aSBoris Brezillon static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
70693db446aSBoris Brezillon {
70793db446aSBoris Brezillon 	return __raw_readl(ctrl->nand_fc + word * 4);
70893db446aSBoris Brezillon }
70993db446aSBoris Brezillon 
71093db446aSBoris Brezillon static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
71193db446aSBoris Brezillon 				     int word, u32 val)
71293db446aSBoris Brezillon {
71393db446aSBoris Brezillon 	__raw_writel(val, ctrl->nand_fc + word * 4);
71493db446aSBoris Brezillon }
71593db446aSBoris Brezillon 
716a5d53ad2SKamal Dasu static inline void edu_writel(struct brcmnand_controller *ctrl,
717a5d53ad2SKamal Dasu 			      enum edu_reg reg, u32 val)
718a5d53ad2SKamal Dasu {
719a5d53ad2SKamal Dasu 	u16 offs = ctrl->edu_offsets[reg];
720a5d53ad2SKamal Dasu 
721a5d53ad2SKamal Dasu 	brcmnand_writel(val, ctrl->edu_base + offs);
722a5d53ad2SKamal Dasu }
723a5d53ad2SKamal Dasu 
724a5d53ad2SKamal Dasu static inline u32 edu_readl(struct brcmnand_controller *ctrl,
725a5d53ad2SKamal Dasu 			    enum edu_reg reg)
726a5d53ad2SKamal Dasu {
727a5d53ad2SKamal Dasu 	u16 offs = ctrl->edu_offsets[reg];
728a5d53ad2SKamal Dasu 
729a5d53ad2SKamal Dasu 	return brcmnand_readl(ctrl->edu_base + offs);
730a5d53ad2SKamal Dasu }
731a5d53ad2SKamal Dasu 
7323c7c1e45SKamal Dasu static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl)
7333c7c1e45SKamal Dasu {
7343c7c1e45SKamal Dasu 
7353c7c1e45SKamal Dasu 	/* Clear error addresses */
7363c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
7373c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
7383c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
7393c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
7403c7c1e45SKamal Dasu }
7413c7c1e45SKamal Dasu 
7423c7c1e45SKamal Dasu static u64 brcmnand_get_uncorrecc_addr(struct brcmnand_controller *ctrl)
7433c7c1e45SKamal Dasu {
7443c7c1e45SKamal Dasu 	u64 err_addr;
7453c7c1e45SKamal Dasu 
7463c7c1e45SKamal Dasu 	err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR);
7473c7c1e45SKamal Dasu 	err_addr |= ((u64)(brcmnand_read_reg(ctrl,
7483c7c1e45SKamal Dasu 					     BRCMNAND_UNCORR_EXT_ADDR)
7493c7c1e45SKamal Dasu 					     & 0xffff) << 32);
7503c7c1e45SKamal Dasu 
7513c7c1e45SKamal Dasu 	return err_addr;
7523c7c1e45SKamal Dasu }
7533c7c1e45SKamal Dasu 
7543c7c1e45SKamal Dasu static u64 brcmnand_get_correcc_addr(struct brcmnand_controller *ctrl)
7553c7c1e45SKamal Dasu {
7563c7c1e45SKamal Dasu 	u64 err_addr;
7573c7c1e45SKamal Dasu 
7583c7c1e45SKamal Dasu 	err_addr = brcmnand_read_reg(ctrl, BRCMNAND_CORR_ADDR);
7593c7c1e45SKamal Dasu 	err_addr |= ((u64)(brcmnand_read_reg(ctrl,
7603c7c1e45SKamal Dasu 					     BRCMNAND_CORR_EXT_ADDR)
7613c7c1e45SKamal Dasu 					     & 0xffff) << 32);
7623c7c1e45SKamal Dasu 
7633c7c1e45SKamal Dasu 	return err_addr;
7643c7c1e45SKamal Dasu }
7653c7c1e45SKamal Dasu 
7663c7c1e45SKamal Dasu static void brcmnand_set_cmd_addr(struct mtd_info *mtd, u64 addr)
7673c7c1e45SKamal Dasu {
7683c7c1e45SKamal Dasu 	struct nand_chip *chip =  mtd_to_nand(mtd);
7693c7c1e45SKamal Dasu 	struct brcmnand_host *host = nand_get_controller_data(chip);
7703c7c1e45SKamal Dasu 	struct brcmnand_controller *ctrl = host->ctrl;
7713c7c1e45SKamal Dasu 
7723c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
7733c7c1e45SKamal Dasu 			   (host->cs << 16) | ((addr >> 32) & 0xffff));
7743c7c1e45SKamal Dasu 	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
7753c7c1e45SKamal Dasu 	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
7763c7c1e45SKamal Dasu 			   lower_32_bits(addr));
7773c7c1e45SKamal Dasu 	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
7783c7c1e45SKamal Dasu }
7793c7c1e45SKamal Dasu 
78093db446aSBoris Brezillon static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
78193db446aSBoris Brezillon 				     enum brcmnand_cs_reg reg)
78293db446aSBoris Brezillon {
78393db446aSBoris Brezillon 	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
78493db446aSBoris Brezillon 	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
78593db446aSBoris Brezillon 	u8 cs_offs;
78693db446aSBoris Brezillon 
78793db446aSBoris Brezillon 	if (cs == 0 && ctrl->cs0_offsets)
78893db446aSBoris Brezillon 		cs_offs = ctrl->cs0_offsets[reg];
78993db446aSBoris Brezillon 	else
79093db446aSBoris Brezillon 		cs_offs = ctrl->cs_offsets[reg];
79193db446aSBoris Brezillon 
79293db446aSBoris Brezillon 	if (cs && offs_cs1)
79393db446aSBoris Brezillon 		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
79493db446aSBoris Brezillon 
79593db446aSBoris Brezillon 	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
79693db446aSBoris Brezillon }
79793db446aSBoris Brezillon 
79893db446aSBoris Brezillon static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
79993db446aSBoris Brezillon {
80093db446aSBoris Brezillon 	if (ctrl->nand_version < 0x0600)
80193db446aSBoris Brezillon 		return 1;
80293db446aSBoris Brezillon 	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
80393db446aSBoris Brezillon }
80493db446aSBoris Brezillon 
80593db446aSBoris Brezillon static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
80693db446aSBoris Brezillon {
80793db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
80893db446aSBoris Brezillon 	unsigned int shift = 0, bits;
80993db446aSBoris Brezillon 	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
81093db446aSBoris Brezillon 	int cs = host->cs;
81193db446aSBoris Brezillon 
8120c06da57SKamal Dasu 	if (ctrl->nand_version == 0x0702)
81393db446aSBoris Brezillon 		bits = 7;
81493db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0600)
81593db446aSBoris Brezillon 		bits = 6;
81693db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0500)
81793db446aSBoris Brezillon 		bits = 5;
81893db446aSBoris Brezillon 	else
81993db446aSBoris Brezillon 		bits = 4;
82093db446aSBoris Brezillon 
82193db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0702) {
82293db446aSBoris Brezillon 		if (cs >= 4)
82393db446aSBoris Brezillon 			reg = BRCMNAND_CORR_THRESHOLD_EXT;
82493db446aSBoris Brezillon 		shift = (cs % 4) * bits;
82593db446aSBoris Brezillon 	} else if (ctrl->nand_version >= 0x0600) {
82693db446aSBoris Brezillon 		if (cs >= 5)
82793db446aSBoris Brezillon 			reg = BRCMNAND_CORR_THRESHOLD_EXT;
82893db446aSBoris Brezillon 		shift = (cs % 5) * bits;
82993db446aSBoris Brezillon 	}
83093db446aSBoris Brezillon 	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
83193db446aSBoris Brezillon }
83293db446aSBoris Brezillon 
83393db446aSBoris Brezillon static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
83493db446aSBoris Brezillon {
83593db446aSBoris Brezillon 	if (ctrl->nand_version < 0x0602)
83693db446aSBoris Brezillon 		return 24;
83793db446aSBoris Brezillon 	return 0;
83893db446aSBoris Brezillon }
83993db446aSBoris Brezillon 
84093db446aSBoris Brezillon /***********************************************************************
84193db446aSBoris Brezillon  * NAND ACC CONTROL bitfield
84293db446aSBoris Brezillon  *
84393db446aSBoris Brezillon  * Some bits have remained constant throughout hardware revision, while
84493db446aSBoris Brezillon  * others have shifted around.
84593db446aSBoris Brezillon  ***********************************************************************/
84693db446aSBoris Brezillon 
84793db446aSBoris Brezillon /* Constant for all versions (where supported) */
84893db446aSBoris Brezillon enum {
84993db446aSBoris Brezillon 	/* See BRCMNAND_HAS_CACHE_MODE */
85093db446aSBoris Brezillon 	ACC_CONTROL_CACHE_MODE				= BIT(22),
85193db446aSBoris Brezillon 
85293db446aSBoris Brezillon 	/* See BRCMNAND_HAS_PREFETCH */
85393db446aSBoris Brezillon 	ACC_CONTROL_PREFETCH				= BIT(23),
85493db446aSBoris Brezillon 
85593db446aSBoris Brezillon 	ACC_CONTROL_PAGE_HIT				= BIT(24),
85693db446aSBoris Brezillon 	ACC_CONTROL_WR_PREEMPT				= BIT(25),
85793db446aSBoris Brezillon 	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
85893db446aSBoris Brezillon 	ACC_CONTROL_RD_ERASED				= BIT(27),
85993db446aSBoris Brezillon 	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
86093db446aSBoris Brezillon 	ACC_CONTROL_WR_ECC				= BIT(30),
86193db446aSBoris Brezillon 	ACC_CONTROL_RD_ECC				= BIT(31),
86293db446aSBoris Brezillon };
86393db446aSBoris Brezillon 
86493db446aSBoris Brezillon static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
86593db446aSBoris Brezillon {
8660c06da57SKamal Dasu 	if (ctrl->nand_version == 0x0702)
86793db446aSBoris Brezillon 		return GENMASK(7, 0);
86893db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0600)
86993db446aSBoris Brezillon 		return GENMASK(6, 0);
87093db446aSBoris Brezillon 	else
87193db446aSBoris Brezillon 		return GENMASK(5, 0);
87293db446aSBoris Brezillon }
87393db446aSBoris Brezillon 
87493db446aSBoris Brezillon #define NAND_ACC_CONTROL_ECC_SHIFT	16
87593db446aSBoris Brezillon #define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
87693db446aSBoris Brezillon 
87793db446aSBoris Brezillon static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
87893db446aSBoris Brezillon {
87993db446aSBoris Brezillon 	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
88093db446aSBoris Brezillon 
88193db446aSBoris Brezillon 	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
88293db446aSBoris Brezillon 
88393db446aSBoris Brezillon 	/* v7.2 includes additional ECC levels */
88493db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0702)
88593db446aSBoris Brezillon 		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
88693db446aSBoris Brezillon 
88793db446aSBoris Brezillon 	return mask;
88893db446aSBoris Brezillon }
88993db446aSBoris Brezillon 
89093db446aSBoris Brezillon static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
89193db446aSBoris Brezillon {
89293db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
89393db446aSBoris Brezillon 	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
89493db446aSBoris Brezillon 	u32 acc_control = nand_readreg(ctrl, offs);
89593db446aSBoris Brezillon 	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
89693db446aSBoris Brezillon 
89793db446aSBoris Brezillon 	if (en) {
89893db446aSBoris Brezillon 		acc_control |= ecc_flags; /* enable RD/WR ECC */
89993db446aSBoris Brezillon 		acc_control |= host->hwcfg.ecc_level
90093db446aSBoris Brezillon 			       << NAND_ACC_CONTROL_ECC_SHIFT;
90193db446aSBoris Brezillon 	} else {
90293db446aSBoris Brezillon 		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
90393db446aSBoris Brezillon 		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
90493db446aSBoris Brezillon 	}
90593db446aSBoris Brezillon 
90693db446aSBoris Brezillon 	nand_writereg(ctrl, offs, acc_control);
90793db446aSBoris Brezillon }
90893db446aSBoris Brezillon 
90993db446aSBoris Brezillon static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
91093db446aSBoris Brezillon {
91193db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0702)
91293db446aSBoris Brezillon 		return 9;
91393db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0600)
91493db446aSBoris Brezillon 		return 7;
91593db446aSBoris Brezillon 	else if (ctrl->nand_version >= 0x0500)
91693db446aSBoris Brezillon 		return 6;
91793db446aSBoris Brezillon 	else
91893db446aSBoris Brezillon 		return -1;
91993db446aSBoris Brezillon }
92093db446aSBoris Brezillon 
92193db446aSBoris Brezillon static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
92293db446aSBoris Brezillon {
92393db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
92493db446aSBoris Brezillon 	int shift = brcmnand_sector_1k_shift(ctrl);
92593db446aSBoris Brezillon 	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
92693db446aSBoris Brezillon 						  BRCMNAND_CS_ACC_CONTROL);
92793db446aSBoris Brezillon 
92893db446aSBoris Brezillon 	if (shift < 0)
92993db446aSBoris Brezillon 		return 0;
93093db446aSBoris Brezillon 
93193db446aSBoris Brezillon 	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
93293db446aSBoris Brezillon }
93393db446aSBoris Brezillon 
93493db446aSBoris Brezillon static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
93593db446aSBoris Brezillon {
93693db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
93793db446aSBoris Brezillon 	int shift = brcmnand_sector_1k_shift(ctrl);
93893db446aSBoris Brezillon 	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
93993db446aSBoris Brezillon 						  BRCMNAND_CS_ACC_CONTROL);
94093db446aSBoris Brezillon 	u32 tmp;
94193db446aSBoris Brezillon 
94293db446aSBoris Brezillon 	if (shift < 0)
94393db446aSBoris Brezillon 		return;
94493db446aSBoris Brezillon 
94593db446aSBoris Brezillon 	tmp = nand_readreg(ctrl, acc_control_offs);
94693db446aSBoris Brezillon 	tmp &= ~(1 << shift);
94793db446aSBoris Brezillon 	tmp |= (!!val) << shift;
94893db446aSBoris Brezillon 	nand_writereg(ctrl, acc_control_offs, tmp);
94993db446aSBoris Brezillon }
95093db446aSBoris Brezillon 
95193db446aSBoris Brezillon /***********************************************************************
95293db446aSBoris Brezillon  * CS_NAND_SELECT
95393db446aSBoris Brezillon  ***********************************************************************/
95493db446aSBoris Brezillon 
95593db446aSBoris Brezillon enum {
95693db446aSBoris Brezillon 	CS_SELECT_NAND_WP			= BIT(29),
95793db446aSBoris Brezillon 	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
95893db446aSBoris Brezillon };
95993db446aSBoris Brezillon 
96093db446aSBoris Brezillon static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
96193db446aSBoris Brezillon 				    u32 mask, u32 expected_val,
96293db446aSBoris Brezillon 				    unsigned long timeout_ms)
96393db446aSBoris Brezillon {
96493db446aSBoris Brezillon 	unsigned long limit;
96593db446aSBoris Brezillon 	u32 val;
96693db446aSBoris Brezillon 
96793db446aSBoris Brezillon 	if (!timeout_ms)
96893db446aSBoris Brezillon 		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
96993db446aSBoris Brezillon 
97093db446aSBoris Brezillon 	limit = jiffies + msecs_to_jiffies(timeout_ms);
97193db446aSBoris Brezillon 	do {
97293db446aSBoris Brezillon 		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
97393db446aSBoris Brezillon 		if ((val & mask) == expected_val)
97493db446aSBoris Brezillon 			return 0;
97593db446aSBoris Brezillon 
97693db446aSBoris Brezillon 		cpu_relax();
97793db446aSBoris Brezillon 	} while (time_after(limit, jiffies));
97893db446aSBoris Brezillon 
97993db446aSBoris Brezillon 	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
98093db446aSBoris Brezillon 		 expected_val, val & mask);
98193db446aSBoris Brezillon 
98293db446aSBoris Brezillon 	return -ETIMEDOUT;
98393db446aSBoris Brezillon }
98493db446aSBoris Brezillon 
98593db446aSBoris Brezillon static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
98693db446aSBoris Brezillon {
98793db446aSBoris Brezillon 	u32 val = en ? CS_SELECT_NAND_WP : 0;
98893db446aSBoris Brezillon 
98993db446aSBoris Brezillon 	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
99093db446aSBoris Brezillon }
99193db446aSBoris Brezillon 
99293db446aSBoris Brezillon /***********************************************************************
99393db446aSBoris Brezillon  * Flash DMA
99493db446aSBoris Brezillon  ***********************************************************************/
99593db446aSBoris Brezillon 
99693db446aSBoris Brezillon static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
99793db446aSBoris Brezillon {
99893db446aSBoris Brezillon 	return ctrl->flash_dma_base;
99993db446aSBoris Brezillon }
100093db446aSBoris Brezillon 
1001a5d53ad2SKamal Dasu static inline bool has_edu(struct brcmnand_controller *ctrl)
1002a5d53ad2SKamal Dasu {
1003a5d53ad2SKamal Dasu 	return ctrl->edu_base;
1004a5d53ad2SKamal Dasu }
1005a5d53ad2SKamal Dasu 
1006a5d53ad2SKamal Dasu static inline bool use_dma(struct brcmnand_controller *ctrl)
1007a5d53ad2SKamal Dasu {
1008a5d53ad2SKamal Dasu 	return has_flash_dma(ctrl) || has_edu(ctrl);
1009a5d53ad2SKamal Dasu }
1010a5d53ad2SKamal Dasu 
1011c1ac2dc3SKamal Dasu static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl)
1012c1ac2dc3SKamal Dasu {
1013c1ac2dc3SKamal Dasu 	if (ctrl->pio_poll_mode)
1014c1ac2dc3SKamal Dasu 		return;
1015c1ac2dc3SKamal Dasu 
1016c1ac2dc3SKamal Dasu 	if (has_flash_dma(ctrl)) {
10170e04b2ffSFlorian Fainelli 		ctrl->flash_dma_base = NULL;
1018c1ac2dc3SKamal Dasu 		disable_irq(ctrl->dma_irq);
1019c1ac2dc3SKamal Dasu 	}
1020c1ac2dc3SKamal Dasu 
1021c1ac2dc3SKamal Dasu 	disable_irq(ctrl->irq);
1022c1ac2dc3SKamal Dasu 	ctrl->pio_poll_mode = true;
1023c1ac2dc3SKamal Dasu }
1024c1ac2dc3SKamal Dasu 
102593db446aSBoris Brezillon static inline bool flash_dma_buf_ok(const void *buf)
102693db446aSBoris Brezillon {
102793db446aSBoris Brezillon 	return buf && !is_vmalloc_addr(buf) &&
102893db446aSBoris Brezillon 		likely(IS_ALIGNED((uintptr_t)buf, 4));
102993db446aSBoris Brezillon }
103093db446aSBoris Brezillon 
10310c06da57SKamal Dasu static inline void flash_dma_writel(struct brcmnand_controller *ctrl,
10320c06da57SKamal Dasu 				    enum flash_dma_reg dma_reg, u32 val)
103393db446aSBoris Brezillon {
10340c06da57SKamal Dasu 	u16 offs = ctrl->flash_dma_offsets[dma_reg];
10350c06da57SKamal Dasu 
103693db446aSBoris Brezillon 	brcmnand_writel(val, ctrl->flash_dma_base + offs);
103793db446aSBoris Brezillon }
103893db446aSBoris Brezillon 
10390c06da57SKamal Dasu static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl,
10400c06da57SKamal Dasu 				  enum flash_dma_reg dma_reg)
104193db446aSBoris Brezillon {
10420c06da57SKamal Dasu 	u16 offs = ctrl->flash_dma_offsets[dma_reg];
10430c06da57SKamal Dasu 
104493db446aSBoris Brezillon 	return brcmnand_readl(ctrl->flash_dma_base + offs);
104593db446aSBoris Brezillon }
104693db446aSBoris Brezillon 
104793db446aSBoris Brezillon /* Low-level operation types: command, address, write, or read */
104893db446aSBoris Brezillon enum brcmnand_llop_type {
104993db446aSBoris Brezillon 	LL_OP_CMD,
105093db446aSBoris Brezillon 	LL_OP_ADDR,
105193db446aSBoris Brezillon 	LL_OP_WR,
105293db446aSBoris Brezillon 	LL_OP_RD,
105393db446aSBoris Brezillon };
105493db446aSBoris Brezillon 
105593db446aSBoris Brezillon /***********************************************************************
105693db446aSBoris Brezillon  * Internal support functions
105793db446aSBoris Brezillon  ***********************************************************************/
105893db446aSBoris Brezillon 
105993db446aSBoris Brezillon static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
106093db446aSBoris Brezillon 				  struct brcmnand_cfg *cfg)
106193db446aSBoris Brezillon {
106293db446aSBoris Brezillon 	if (ctrl->nand_version <= 0x0701)
106393db446aSBoris Brezillon 		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
106493db446aSBoris Brezillon 			cfg->ecc_level == 15;
106593db446aSBoris Brezillon 	else
106693db446aSBoris Brezillon 		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
106793db446aSBoris Brezillon 			cfg->ecc_level == 15) ||
106893db446aSBoris Brezillon 			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
106993db446aSBoris Brezillon }
107093db446aSBoris Brezillon 
107193db446aSBoris Brezillon /*
107293db446aSBoris Brezillon  * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
107393db446aSBoris Brezillon  * the layout/configuration.
107493db446aSBoris Brezillon  * Returns -ERRCODE on failure.
107593db446aSBoris Brezillon  */
107693db446aSBoris Brezillon static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
107793db446aSBoris Brezillon 					  struct mtd_oob_region *oobregion)
107893db446aSBoris Brezillon {
107993db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
108093db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
108193db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
108293db446aSBoris Brezillon 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
108393db446aSBoris Brezillon 	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
108493db446aSBoris Brezillon 
108593db446aSBoris Brezillon 	if (section >= sectors)
108693db446aSBoris Brezillon 		return -ERANGE;
108793db446aSBoris Brezillon 
108893db446aSBoris Brezillon 	oobregion->offset = (section * sas) + 6;
108993db446aSBoris Brezillon 	oobregion->length = 3;
109093db446aSBoris Brezillon 
109193db446aSBoris Brezillon 	return 0;
109293db446aSBoris Brezillon }
109393db446aSBoris Brezillon 
109493db446aSBoris Brezillon static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
109593db446aSBoris Brezillon 					   struct mtd_oob_region *oobregion)
109693db446aSBoris Brezillon {
109793db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
109893db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
109993db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
110093db446aSBoris Brezillon 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
110193db446aSBoris Brezillon 	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
110293db446aSBoris Brezillon 
110393db446aSBoris Brezillon 	if (section >= sectors * 2)
110493db446aSBoris Brezillon 		return -ERANGE;
110593db446aSBoris Brezillon 
110693db446aSBoris Brezillon 	oobregion->offset = (section / 2) * sas;
110793db446aSBoris Brezillon 
110893db446aSBoris Brezillon 	if (section & 1) {
110993db446aSBoris Brezillon 		oobregion->offset += 9;
111093db446aSBoris Brezillon 		oobregion->length = 7;
111193db446aSBoris Brezillon 	} else {
111293db446aSBoris Brezillon 		oobregion->length = 6;
111393db446aSBoris Brezillon 
111493db446aSBoris Brezillon 		/* First sector of each page may have BBI */
111593db446aSBoris Brezillon 		if (!section) {
111693db446aSBoris Brezillon 			/*
111793db446aSBoris Brezillon 			 * Small-page NAND use byte 6 for BBI while large-page
1118130bbde4SÁlvaro Fernández Rojas 			 * NAND use bytes 0 and 1.
111993db446aSBoris Brezillon 			 */
1120130bbde4SÁlvaro Fernández Rojas 			if (cfg->page_size > 512) {
1121130bbde4SÁlvaro Fernández Rojas 				oobregion->offset += 2;
1122130bbde4SÁlvaro Fernández Rojas 				oobregion->length -= 2;
1123130bbde4SÁlvaro Fernández Rojas 			} else {
112493db446aSBoris Brezillon 				oobregion->length--;
112593db446aSBoris Brezillon 			}
112693db446aSBoris Brezillon 		}
1127130bbde4SÁlvaro Fernández Rojas 	}
112893db446aSBoris Brezillon 
112993db446aSBoris Brezillon 	return 0;
113093db446aSBoris Brezillon }
113193db446aSBoris Brezillon 
113293db446aSBoris Brezillon static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
113393db446aSBoris Brezillon 	.ecc = brcmnand_hamming_ooblayout_ecc,
113493db446aSBoris Brezillon 	.free = brcmnand_hamming_ooblayout_free,
113593db446aSBoris Brezillon };
113693db446aSBoris Brezillon 
113793db446aSBoris Brezillon static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
113893db446aSBoris Brezillon 				      struct mtd_oob_region *oobregion)
113993db446aSBoris Brezillon {
114093db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
114193db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
114293db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
114393db446aSBoris Brezillon 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
114493db446aSBoris Brezillon 	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
114593db446aSBoris Brezillon 
114693db446aSBoris Brezillon 	if (section >= sectors)
114793db446aSBoris Brezillon 		return -ERANGE;
114893db446aSBoris Brezillon 
1149917cc594SKamal Dasu 	oobregion->offset = ((section + 1) * sas) - chip->ecc.bytes;
115093db446aSBoris Brezillon 	oobregion->length = chip->ecc.bytes;
115193db446aSBoris Brezillon 
115293db446aSBoris Brezillon 	return 0;
115393db446aSBoris Brezillon }
115493db446aSBoris Brezillon 
115593db446aSBoris Brezillon static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
115693db446aSBoris Brezillon 					  struct mtd_oob_region *oobregion)
115793db446aSBoris Brezillon {
115893db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
115993db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
116093db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
116193db446aSBoris Brezillon 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
116293db446aSBoris Brezillon 	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
116393db446aSBoris Brezillon 
116493db446aSBoris Brezillon 	if (section >= sectors)
116593db446aSBoris Brezillon 		return -ERANGE;
116693db446aSBoris Brezillon 
116793db446aSBoris Brezillon 	if (sas <= chip->ecc.bytes)
116893db446aSBoris Brezillon 		return 0;
116993db446aSBoris Brezillon 
117093db446aSBoris Brezillon 	oobregion->offset = section * sas;
117193db446aSBoris Brezillon 	oobregion->length = sas - chip->ecc.bytes;
117293db446aSBoris Brezillon 
117393db446aSBoris Brezillon 	if (!section) {
117493db446aSBoris Brezillon 		oobregion->offset++;
117593db446aSBoris Brezillon 		oobregion->length--;
117693db446aSBoris Brezillon 	}
117793db446aSBoris Brezillon 
117893db446aSBoris Brezillon 	return 0;
117993db446aSBoris Brezillon }
118093db446aSBoris Brezillon 
118193db446aSBoris Brezillon static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
118293db446aSBoris Brezillon 					  struct mtd_oob_region *oobregion)
118393db446aSBoris Brezillon {
118493db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
118593db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
118693db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
118793db446aSBoris Brezillon 	int sas = cfg->spare_area_size << cfg->sector_size_1k;
118893db446aSBoris Brezillon 
118993db446aSBoris Brezillon 	if (section > 1 || sas - chip->ecc.bytes < 6 ||
119093db446aSBoris Brezillon 	    (section && sas - chip->ecc.bytes == 6))
119193db446aSBoris Brezillon 		return -ERANGE;
119293db446aSBoris Brezillon 
119393db446aSBoris Brezillon 	if (!section) {
119493db446aSBoris Brezillon 		oobregion->offset = 0;
119593db446aSBoris Brezillon 		oobregion->length = 5;
119693db446aSBoris Brezillon 	} else {
119793db446aSBoris Brezillon 		oobregion->offset = 6;
119893db446aSBoris Brezillon 		oobregion->length = sas - chip->ecc.bytes - 6;
119993db446aSBoris Brezillon 	}
120093db446aSBoris Brezillon 
120193db446aSBoris Brezillon 	return 0;
120293db446aSBoris Brezillon }
120393db446aSBoris Brezillon 
120493db446aSBoris Brezillon static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
120593db446aSBoris Brezillon 	.ecc = brcmnand_bch_ooblayout_ecc,
120693db446aSBoris Brezillon 	.free = brcmnand_bch_ooblayout_free_lp,
120793db446aSBoris Brezillon };
120893db446aSBoris Brezillon 
120993db446aSBoris Brezillon static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
121093db446aSBoris Brezillon 	.ecc = brcmnand_bch_ooblayout_ecc,
121193db446aSBoris Brezillon 	.free = brcmnand_bch_ooblayout_free_sp,
121293db446aSBoris Brezillon };
121393db446aSBoris Brezillon 
121493db446aSBoris Brezillon static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
121593db446aSBoris Brezillon {
121693db446aSBoris Brezillon 	struct brcmnand_cfg *p = &host->hwcfg;
121793db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(&host->chip);
121893db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &host->chip.ecc;
121993db446aSBoris Brezillon 	unsigned int ecc_level = p->ecc_level;
122093db446aSBoris Brezillon 	int sas = p->spare_area_size << p->sector_size_1k;
122193db446aSBoris Brezillon 	int sectors = p->page_size / (512 << p->sector_size_1k);
122293db446aSBoris Brezillon 
122393db446aSBoris Brezillon 	if (p->sector_size_1k)
122493db446aSBoris Brezillon 		ecc_level <<= 1;
122593db446aSBoris Brezillon 
122693db446aSBoris Brezillon 	if (is_hamming_ecc(host->ctrl, p)) {
122793db446aSBoris Brezillon 		ecc->bytes = 3 * sectors;
122893db446aSBoris Brezillon 		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
122993db446aSBoris Brezillon 		return 0;
123093db446aSBoris Brezillon 	}
123193db446aSBoris Brezillon 
123293db446aSBoris Brezillon 	/*
123393db446aSBoris Brezillon 	 * CONTROLLER_VERSION:
123493db446aSBoris Brezillon 	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
123593db446aSBoris Brezillon 	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
123693db446aSBoris Brezillon 	 * But we will just be conservative.
123793db446aSBoris Brezillon 	 */
123893db446aSBoris Brezillon 	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
123993db446aSBoris Brezillon 	if (p->page_size == 512)
124093db446aSBoris Brezillon 		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
124193db446aSBoris Brezillon 	else
124293db446aSBoris Brezillon 		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
124393db446aSBoris Brezillon 
124493db446aSBoris Brezillon 	if (ecc->bytes >= sas) {
124593db446aSBoris Brezillon 		dev_err(&host->pdev->dev,
124693db446aSBoris Brezillon 			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
124793db446aSBoris Brezillon 			ecc->bytes, sas);
124893db446aSBoris Brezillon 		return -EINVAL;
124993db446aSBoris Brezillon 	}
125093db446aSBoris Brezillon 
125193db446aSBoris Brezillon 	return 0;
125293db446aSBoris Brezillon }
125393db446aSBoris Brezillon 
125493db446aSBoris Brezillon static void brcmnand_wp(struct mtd_info *mtd, int wp)
125593db446aSBoris Brezillon {
125693db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
125793db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
125893db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
125993db446aSBoris Brezillon 
126093db446aSBoris Brezillon 	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
126193db446aSBoris Brezillon 		static int old_wp = -1;
126293db446aSBoris Brezillon 		int ret;
126393db446aSBoris Brezillon 
126493db446aSBoris Brezillon 		if (old_wp != wp) {
126593db446aSBoris Brezillon 			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
126693db446aSBoris Brezillon 			old_wp = wp;
126793db446aSBoris Brezillon 		}
126893db446aSBoris Brezillon 
126993db446aSBoris Brezillon 		/*
127093db446aSBoris Brezillon 		 * make sure ctrl/flash ready before and after
127193db446aSBoris Brezillon 		 * changing state of #WP pin
127293db446aSBoris Brezillon 		 */
127393db446aSBoris Brezillon 		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
127493db446aSBoris Brezillon 					       NAND_STATUS_READY,
127593db446aSBoris Brezillon 					       NAND_CTRL_RDY |
127693db446aSBoris Brezillon 					       NAND_STATUS_READY, 0);
127793db446aSBoris Brezillon 		if (ret)
127893db446aSBoris Brezillon 			return;
127993db446aSBoris Brezillon 
128093db446aSBoris Brezillon 		brcmnand_set_wp(ctrl, wp);
128193db446aSBoris Brezillon 		nand_status_op(chip, NULL);
128293db446aSBoris Brezillon 		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
128393db446aSBoris Brezillon 		ret = bcmnand_ctrl_poll_status(ctrl,
128493db446aSBoris Brezillon 					       NAND_CTRL_RDY |
128593db446aSBoris Brezillon 					       NAND_STATUS_READY |
128693db446aSBoris Brezillon 					       NAND_STATUS_WP,
128793db446aSBoris Brezillon 					       NAND_CTRL_RDY |
128893db446aSBoris Brezillon 					       NAND_STATUS_READY |
128993db446aSBoris Brezillon 					       (wp ? 0 : NAND_STATUS_WP), 0);
129093db446aSBoris Brezillon 
129193db446aSBoris Brezillon 		if (ret)
129293db446aSBoris Brezillon 			dev_err_ratelimited(&host->pdev->dev,
129393db446aSBoris Brezillon 					    "nand #WP expected %s\n",
129493db446aSBoris Brezillon 					    wp ? "on" : "off");
129593db446aSBoris Brezillon 	}
129693db446aSBoris Brezillon }
129793db446aSBoris Brezillon 
129893db446aSBoris Brezillon /* Helper functions for reading and writing OOB registers */
129993db446aSBoris Brezillon static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
130093db446aSBoris Brezillon {
130193db446aSBoris Brezillon 	u16 offset0, offset10, reg_offs;
130293db446aSBoris Brezillon 
130393db446aSBoris Brezillon 	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
130493db446aSBoris Brezillon 	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
130593db446aSBoris Brezillon 
130693db446aSBoris Brezillon 	if (offs >= ctrl->max_oob)
130793db446aSBoris Brezillon 		return 0x77;
130893db446aSBoris Brezillon 
130993db446aSBoris Brezillon 	if (offs >= 16 && offset10)
131093db446aSBoris Brezillon 		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
131193db446aSBoris Brezillon 	else
131293db446aSBoris Brezillon 		reg_offs = offset0 + (offs & ~0x03);
131393db446aSBoris Brezillon 
131493db446aSBoris Brezillon 	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
131593db446aSBoris Brezillon }
131693db446aSBoris Brezillon 
131793db446aSBoris Brezillon static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
131893db446aSBoris Brezillon 				 u32 data)
131993db446aSBoris Brezillon {
132093db446aSBoris Brezillon 	u16 offset0, offset10, reg_offs;
132193db446aSBoris Brezillon 
132293db446aSBoris Brezillon 	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
132393db446aSBoris Brezillon 	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
132493db446aSBoris Brezillon 
132593db446aSBoris Brezillon 	if (offs >= ctrl->max_oob)
132693db446aSBoris Brezillon 		return;
132793db446aSBoris Brezillon 
132893db446aSBoris Brezillon 	if (offs >= 16 && offset10)
132993db446aSBoris Brezillon 		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
133093db446aSBoris Brezillon 	else
133193db446aSBoris Brezillon 		reg_offs = offset0 + (offs & ~0x03);
133293db446aSBoris Brezillon 
133393db446aSBoris Brezillon 	nand_writereg(ctrl, reg_offs, data);
133493db446aSBoris Brezillon }
133593db446aSBoris Brezillon 
133693db446aSBoris Brezillon /*
133793db446aSBoris Brezillon  * read_oob_from_regs - read data from OOB registers
133893db446aSBoris Brezillon  * @ctrl: NAND controller
133993db446aSBoris Brezillon  * @i: sub-page sector index
134093db446aSBoris Brezillon  * @oob: buffer to read to
134193db446aSBoris Brezillon  * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
134293db446aSBoris Brezillon  * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
134393db446aSBoris Brezillon  */
134493db446aSBoris Brezillon static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
134593db446aSBoris Brezillon 			      int sas, int sector_1k)
134693db446aSBoris Brezillon {
134793db446aSBoris Brezillon 	int tbytes = sas << sector_1k;
134893db446aSBoris Brezillon 	int j;
134993db446aSBoris Brezillon 
135093db446aSBoris Brezillon 	/* Adjust OOB values for 1K sector size */
135193db446aSBoris Brezillon 	if (sector_1k && (i & 0x01))
135293db446aSBoris Brezillon 		tbytes = max(0, tbytes - (int)ctrl->max_oob);
135393db446aSBoris Brezillon 	tbytes = min_t(int, tbytes, ctrl->max_oob);
135493db446aSBoris Brezillon 
135593db446aSBoris Brezillon 	for (j = 0; j < tbytes; j++)
135693db446aSBoris Brezillon 		oob[j] = oob_reg_read(ctrl, j);
135793db446aSBoris Brezillon 	return tbytes;
135893db446aSBoris Brezillon }
135993db446aSBoris Brezillon 
136093db446aSBoris Brezillon /*
136193db446aSBoris Brezillon  * write_oob_to_regs - write data to OOB registers
136293db446aSBoris Brezillon  * @i: sub-page sector index
136393db446aSBoris Brezillon  * @oob: buffer to write from
136493db446aSBoris Brezillon  * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
136593db446aSBoris Brezillon  * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
136693db446aSBoris Brezillon  */
136793db446aSBoris Brezillon static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
136893db446aSBoris Brezillon 			     const u8 *oob, int sas, int sector_1k)
136993db446aSBoris Brezillon {
137093db446aSBoris Brezillon 	int tbytes = sas << sector_1k;
137193db446aSBoris Brezillon 	int j;
137293db446aSBoris Brezillon 
137393db446aSBoris Brezillon 	/* Adjust OOB values for 1K sector size */
137493db446aSBoris Brezillon 	if (sector_1k && (i & 0x01))
137593db446aSBoris Brezillon 		tbytes = max(0, tbytes - (int)ctrl->max_oob);
137693db446aSBoris Brezillon 	tbytes = min_t(int, tbytes, ctrl->max_oob);
137793db446aSBoris Brezillon 
137893db446aSBoris Brezillon 	for (j = 0; j < tbytes; j += 4)
137993db446aSBoris Brezillon 		oob_reg_write(ctrl, j,
138093db446aSBoris Brezillon 				(oob[j + 0] << 24) |
138193db446aSBoris Brezillon 				(oob[j + 1] << 16) |
138293db446aSBoris Brezillon 				(oob[j + 2] <<  8) |
138393db446aSBoris Brezillon 				(oob[j + 3] <<  0));
138493db446aSBoris Brezillon 	return tbytes;
138593db446aSBoris Brezillon }
138693db446aSBoris Brezillon 
1387a5d53ad2SKamal Dasu static void brcmnand_edu_init(struct brcmnand_controller *ctrl)
1388a5d53ad2SKamal Dasu {
1389a5d53ad2SKamal Dasu 	/* initialize edu */
1390a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_ERR_STATUS, 0);
1391a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_ERR_STATUS);
1392a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_DONE, 0);
1393a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_DONE, 0);
1394a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_DONE, 0);
1395a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_DONE, 0);
1396a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_DONE);
1397a5d53ad2SKamal Dasu }
1398a5d53ad2SKamal Dasu 
1399a5d53ad2SKamal Dasu /* edu irq */
1400a5d53ad2SKamal Dasu static irqreturn_t brcmnand_edu_irq(int irq, void *data)
1401a5d53ad2SKamal Dasu {
1402a5d53ad2SKamal Dasu 	struct brcmnand_controller *ctrl = data;
1403a5d53ad2SKamal Dasu 
1404a5d53ad2SKamal Dasu 	if (ctrl->edu_count) {
1405a5d53ad2SKamal Dasu 		ctrl->edu_count--;
1406a5d53ad2SKamal Dasu 		while (!(edu_readl(ctrl, EDU_DONE) & EDU_DONE_MASK))
1407a5d53ad2SKamal Dasu 			udelay(1);
1408a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_DONE, 0);
1409a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_DONE);
1410a5d53ad2SKamal Dasu 	}
1411a5d53ad2SKamal Dasu 
1412a5d53ad2SKamal Dasu 	if (ctrl->edu_count) {
1413a5d53ad2SKamal Dasu 		ctrl->edu_dram_addr += FC_BYTES;
1414a5d53ad2SKamal Dasu 		ctrl->edu_ext_addr += FC_BYTES;
1415a5d53ad2SKamal Dasu 
1416a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr);
1417a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_DRAM_ADDR);
1418a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr);
1419a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_EXT_ADDR);
1420a5d53ad2SKamal Dasu 
1421a5d53ad2SKamal Dasu 		mb(); /* flush previous writes */
1422a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
1423a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_CMD);
1424a5d53ad2SKamal Dasu 
1425a5d53ad2SKamal Dasu 		return IRQ_HANDLED;
1426a5d53ad2SKamal Dasu 	}
1427a5d53ad2SKamal Dasu 
1428a5d53ad2SKamal Dasu 	complete(&ctrl->edu_done);
1429a5d53ad2SKamal Dasu 
1430a5d53ad2SKamal Dasu 	return IRQ_HANDLED;
1431a5d53ad2SKamal Dasu }
1432a5d53ad2SKamal Dasu 
143393db446aSBoris Brezillon static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
143493db446aSBoris Brezillon {
143593db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = data;
143693db446aSBoris Brezillon 
143793db446aSBoris Brezillon 	/* Discard all NAND_CTLRDY interrupts during DMA */
143893db446aSBoris Brezillon 	if (ctrl->dma_pending)
143993db446aSBoris Brezillon 		return IRQ_HANDLED;
144093db446aSBoris Brezillon 
1441a5d53ad2SKamal Dasu 	/* check if you need to piggy back on the ctrlrdy irq */
1442a5d53ad2SKamal Dasu 	if (ctrl->edu_pending) {
1443a5d53ad2SKamal Dasu 		if (irq == ctrl->irq && ((int)ctrl->edu_irq >= 0))
1444a5d53ad2SKamal Dasu 	/* Discard interrupts while using dedicated edu irq */
1445a5d53ad2SKamal Dasu 			return IRQ_HANDLED;
1446a5d53ad2SKamal Dasu 
1447a5d53ad2SKamal Dasu 	/* no registered edu irq, call handler */
1448a5d53ad2SKamal Dasu 		return brcmnand_edu_irq(irq, data);
1449a5d53ad2SKamal Dasu 	}
1450a5d53ad2SKamal Dasu 
145193db446aSBoris Brezillon 	complete(&ctrl->done);
145293db446aSBoris Brezillon 	return IRQ_HANDLED;
145393db446aSBoris Brezillon }
145493db446aSBoris Brezillon 
145593db446aSBoris Brezillon /* Handle SoC-specific interrupt hardware */
145693db446aSBoris Brezillon static irqreturn_t brcmnand_irq(int irq, void *data)
145793db446aSBoris Brezillon {
145893db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = data;
145993db446aSBoris Brezillon 
146093db446aSBoris Brezillon 	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
146193db446aSBoris Brezillon 		return brcmnand_ctlrdy_irq(irq, data);
146293db446aSBoris Brezillon 
146393db446aSBoris Brezillon 	return IRQ_NONE;
146493db446aSBoris Brezillon }
146593db446aSBoris Brezillon 
146693db446aSBoris Brezillon static irqreturn_t brcmnand_dma_irq(int irq, void *data)
146793db446aSBoris Brezillon {
146893db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = data;
146993db446aSBoris Brezillon 
147093db446aSBoris Brezillon 	complete(&ctrl->dma_done);
147193db446aSBoris Brezillon 
147293db446aSBoris Brezillon 	return IRQ_HANDLED;
147393db446aSBoris Brezillon }
147493db446aSBoris Brezillon 
147593db446aSBoris Brezillon static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
147693db446aSBoris Brezillon {
147793db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
147893db446aSBoris Brezillon 	int ret;
14793c7c1e45SKamal Dasu 	u64 cmd_addr;
148093db446aSBoris Brezillon 
14813c7c1e45SKamal Dasu 	cmd_addr = brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
14823c7c1e45SKamal Dasu 
14833c7c1e45SKamal Dasu 	dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr);
14843c7c1e45SKamal Dasu 
148593db446aSBoris Brezillon 	BUG_ON(ctrl->cmd_pending != 0);
148693db446aSBoris Brezillon 	ctrl->cmd_pending = cmd;
148793db446aSBoris Brezillon 
148893db446aSBoris Brezillon 	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
148993db446aSBoris Brezillon 	WARN_ON(ret);
149093db446aSBoris Brezillon 
149193db446aSBoris Brezillon 	mb(); /* flush previous writes */
149293db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
149393db446aSBoris Brezillon 			   cmd << brcmnand_cmd_shift(ctrl));
149493db446aSBoris Brezillon }
149593db446aSBoris Brezillon 
149693db446aSBoris Brezillon /***********************************************************************
149793db446aSBoris Brezillon  * NAND MTD API: read/program/erase
149893db446aSBoris Brezillon  ***********************************************************************/
149993db446aSBoris Brezillon 
15000f808c16SBoris Brezillon static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
150193db446aSBoris Brezillon 			      unsigned int ctrl)
150293db446aSBoris Brezillon {
150393db446aSBoris Brezillon 	/* intentionally left blank */
150493db446aSBoris Brezillon }
150593db446aSBoris Brezillon 
1506c1ac2dc3SKamal Dasu static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip)
1507c1ac2dc3SKamal Dasu {
1508c1ac2dc3SKamal Dasu 	struct brcmnand_host *host = nand_get_controller_data(chip);
1509c1ac2dc3SKamal Dasu 	struct brcmnand_controller *ctrl = host->ctrl;
1510c1ac2dc3SKamal Dasu 	struct mtd_info *mtd = nand_to_mtd(chip);
1511c1ac2dc3SKamal Dasu 	bool err = false;
1512c1ac2dc3SKamal Dasu 	int sts;
1513c1ac2dc3SKamal Dasu 
1514c1ac2dc3SKamal Dasu 	if (mtd->oops_panic_write) {
1515c1ac2dc3SKamal Dasu 		/* switch to interrupt polling and PIO mode */
1516c1ac2dc3SKamal Dasu 		disable_ctrl_irqs(ctrl);
1517c1ac2dc3SKamal Dasu 		sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY,
1518c1ac2dc3SKamal Dasu 					       NAND_CTRL_RDY, 0);
1519c1ac2dc3SKamal Dasu 		err = (sts < 0) ? true : false;
1520c1ac2dc3SKamal Dasu 	} else {
1521c1ac2dc3SKamal Dasu 		unsigned long timeo = msecs_to_jiffies(
1522c1ac2dc3SKamal Dasu 						NAND_POLL_STATUS_TIMEOUT_MS);
1523c1ac2dc3SKamal Dasu 		/* wait for completion interrupt */
1524c1ac2dc3SKamal Dasu 		sts = wait_for_completion_timeout(&ctrl->done, timeo);
1525c1ac2dc3SKamal Dasu 		err = (sts <= 0) ? true : false;
1526c1ac2dc3SKamal Dasu 	}
1527c1ac2dc3SKamal Dasu 
1528c1ac2dc3SKamal Dasu 	return err;
1529c1ac2dc3SKamal Dasu }
1530c1ac2dc3SKamal Dasu 
1531f1d46942SBoris Brezillon static int brcmnand_waitfunc(struct nand_chip *chip)
153293db446aSBoris Brezillon {
153393db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
153493db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
1535c1ac2dc3SKamal Dasu 	bool err = false;
153693db446aSBoris Brezillon 
153793db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
1538c1ac2dc3SKamal Dasu 	if (ctrl->cmd_pending)
1539c1ac2dc3SKamal Dasu 		err = brcmstb_nand_wait_for_completion(chip);
1540c1ac2dc3SKamal Dasu 
1541c1ac2dc3SKamal Dasu 	if (err) {
154293db446aSBoris Brezillon 		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
154393db446aSBoris Brezillon 					>> brcmnand_cmd_shift(ctrl);
154493db446aSBoris Brezillon 
154593db446aSBoris Brezillon 		dev_err_ratelimited(ctrl->dev,
154693db446aSBoris Brezillon 			"timeout waiting for command %#02x\n", cmd);
154793db446aSBoris Brezillon 		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
154893db446aSBoris Brezillon 			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
154993db446aSBoris Brezillon 	}
155093db446aSBoris Brezillon 	ctrl->cmd_pending = 0;
155193db446aSBoris Brezillon 	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
155293db446aSBoris Brezillon 				 INTFC_FLASH_STATUS;
155393db446aSBoris Brezillon }
155493db446aSBoris Brezillon 
155593db446aSBoris Brezillon enum {
155693db446aSBoris Brezillon 	LLOP_RE				= BIT(16),
155793db446aSBoris Brezillon 	LLOP_WE				= BIT(17),
155893db446aSBoris Brezillon 	LLOP_ALE			= BIT(18),
155993db446aSBoris Brezillon 	LLOP_CLE			= BIT(19),
156093db446aSBoris Brezillon 	LLOP_RETURN_IDLE		= BIT(31),
156193db446aSBoris Brezillon 
156293db446aSBoris Brezillon 	LLOP_DATA_MASK			= GENMASK(15, 0),
156393db446aSBoris Brezillon };
156493db446aSBoris Brezillon 
156593db446aSBoris Brezillon static int brcmnand_low_level_op(struct brcmnand_host *host,
156693db446aSBoris Brezillon 				 enum brcmnand_llop_type type, u32 data,
156793db446aSBoris Brezillon 				 bool last_op)
156893db446aSBoris Brezillon {
156993db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
157093db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
157193db446aSBoris Brezillon 	u32 tmp;
157293db446aSBoris Brezillon 
157393db446aSBoris Brezillon 	tmp = data & LLOP_DATA_MASK;
157493db446aSBoris Brezillon 	switch (type) {
157593db446aSBoris Brezillon 	case LL_OP_CMD:
157693db446aSBoris Brezillon 		tmp |= LLOP_WE | LLOP_CLE;
157793db446aSBoris Brezillon 		break;
157893db446aSBoris Brezillon 	case LL_OP_ADDR:
157993db446aSBoris Brezillon 		/* WE | ALE */
158093db446aSBoris Brezillon 		tmp |= LLOP_WE | LLOP_ALE;
158193db446aSBoris Brezillon 		break;
158293db446aSBoris Brezillon 	case LL_OP_WR:
158393db446aSBoris Brezillon 		/* WE */
158493db446aSBoris Brezillon 		tmp |= LLOP_WE;
158593db446aSBoris Brezillon 		break;
158693db446aSBoris Brezillon 	case LL_OP_RD:
158793db446aSBoris Brezillon 		/* RE */
158893db446aSBoris Brezillon 		tmp |= LLOP_RE;
158993db446aSBoris Brezillon 		break;
159093db446aSBoris Brezillon 	}
159193db446aSBoris Brezillon 	if (last_op)
159293db446aSBoris Brezillon 		/* RETURN_IDLE */
159393db446aSBoris Brezillon 		tmp |= LLOP_RETURN_IDLE;
159493db446aSBoris Brezillon 
159593db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
159693db446aSBoris Brezillon 
159793db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
159893db446aSBoris Brezillon 	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
159993db446aSBoris Brezillon 
160093db446aSBoris Brezillon 	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
1601f1d46942SBoris Brezillon 	return brcmnand_waitfunc(chip);
160293db446aSBoris Brezillon }
160393db446aSBoris Brezillon 
16045295cf2eSBoris Brezillon static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
160593db446aSBoris Brezillon 			     int column, int page_addr)
160693db446aSBoris Brezillon {
16075295cf2eSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
160893db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
160993db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
161093db446aSBoris Brezillon 	u64 addr = (u64)page_addr << chip->page_shift;
161193db446aSBoris Brezillon 	int native_cmd = 0;
161293db446aSBoris Brezillon 
161393db446aSBoris Brezillon 	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
161493db446aSBoris Brezillon 			command == NAND_CMD_RNDOUT)
161593db446aSBoris Brezillon 		addr = (u64)column;
161693db446aSBoris Brezillon 	/* Avoid propagating a negative, don't-care address */
161793db446aSBoris Brezillon 	else if (page_addr < 0)
161893db446aSBoris Brezillon 		addr = 0;
161993db446aSBoris Brezillon 
162093db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
162193db446aSBoris Brezillon 		(unsigned long long)addr);
162293db446aSBoris Brezillon 
162393db446aSBoris Brezillon 	host->last_cmd = command;
162493db446aSBoris Brezillon 	host->last_byte = 0;
162593db446aSBoris Brezillon 	host->last_addr = addr;
162693db446aSBoris Brezillon 
162793db446aSBoris Brezillon 	switch (command) {
162893db446aSBoris Brezillon 	case NAND_CMD_RESET:
162993db446aSBoris Brezillon 		native_cmd = CMD_FLASH_RESET;
163093db446aSBoris Brezillon 		break;
163193db446aSBoris Brezillon 	case NAND_CMD_STATUS:
163293db446aSBoris Brezillon 		native_cmd = CMD_STATUS_READ;
163393db446aSBoris Brezillon 		break;
163493db446aSBoris Brezillon 	case NAND_CMD_READID:
163593db446aSBoris Brezillon 		native_cmd = CMD_DEVICE_ID_READ;
163693db446aSBoris Brezillon 		break;
163793db446aSBoris Brezillon 	case NAND_CMD_READOOB:
163893db446aSBoris Brezillon 		native_cmd = CMD_SPARE_AREA_READ;
163993db446aSBoris Brezillon 		break;
164093db446aSBoris Brezillon 	case NAND_CMD_ERASE1:
164193db446aSBoris Brezillon 		native_cmd = CMD_BLOCK_ERASE;
164293db446aSBoris Brezillon 		brcmnand_wp(mtd, 0);
164393db446aSBoris Brezillon 		break;
164493db446aSBoris Brezillon 	case NAND_CMD_PARAM:
164593db446aSBoris Brezillon 		native_cmd = CMD_PARAMETER_READ;
164693db446aSBoris Brezillon 		break;
164793db446aSBoris Brezillon 	case NAND_CMD_SET_FEATURES:
164893db446aSBoris Brezillon 	case NAND_CMD_GET_FEATURES:
164993db446aSBoris Brezillon 		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
165093db446aSBoris Brezillon 		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
165193db446aSBoris Brezillon 		break;
165293db446aSBoris Brezillon 	case NAND_CMD_RNDOUT:
165393db446aSBoris Brezillon 		native_cmd = CMD_PARAMETER_CHANGE_COL;
165493db446aSBoris Brezillon 		addr &= ~((u64)(FC_BYTES - 1));
165593db446aSBoris Brezillon 		/*
165693db446aSBoris Brezillon 		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
165793db446aSBoris Brezillon 		 * NB: hwcfg.sector_size_1k may not be initialized yet
165893db446aSBoris Brezillon 		 */
165993db446aSBoris Brezillon 		if (brcmnand_get_sector_size_1k(host)) {
166093db446aSBoris Brezillon 			host->hwcfg.sector_size_1k =
166193db446aSBoris Brezillon 				brcmnand_get_sector_size_1k(host);
166293db446aSBoris Brezillon 			brcmnand_set_sector_size_1k(host, 0);
166393db446aSBoris Brezillon 		}
166493db446aSBoris Brezillon 		break;
166593db446aSBoris Brezillon 	}
166693db446aSBoris Brezillon 
166793db446aSBoris Brezillon 	if (!native_cmd)
166893db446aSBoris Brezillon 		return;
166993db446aSBoris Brezillon 
16703c7c1e45SKamal Dasu 	brcmnand_set_cmd_addr(mtd, addr);
167193db446aSBoris Brezillon 	brcmnand_send_cmd(host, native_cmd);
1672f1d46942SBoris Brezillon 	brcmnand_waitfunc(chip);
167393db446aSBoris Brezillon 
167493db446aSBoris Brezillon 	if (native_cmd == CMD_PARAMETER_READ ||
167593db446aSBoris Brezillon 			native_cmd == CMD_PARAMETER_CHANGE_COL) {
167693db446aSBoris Brezillon 		/* Copy flash cache word-wise */
167793db446aSBoris Brezillon 		u32 *flash_cache = (u32 *)ctrl->flash_cache;
167893db446aSBoris Brezillon 		int i;
167993db446aSBoris Brezillon 
168093db446aSBoris Brezillon 		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
168193db446aSBoris Brezillon 
168293db446aSBoris Brezillon 		/*
168393db446aSBoris Brezillon 		 * Must cache the FLASH_CACHE now, since changes in
168493db446aSBoris Brezillon 		 * SECTOR_SIZE_1K may invalidate it
168593db446aSBoris Brezillon 		 */
168693db446aSBoris Brezillon 		for (i = 0; i < FC_WORDS; i++)
168793db446aSBoris Brezillon 			/*
168893db446aSBoris Brezillon 			 * Flash cache is big endian for parameter pages, at
168993db446aSBoris Brezillon 			 * least on STB SoCs
169093db446aSBoris Brezillon 			 */
169193db446aSBoris Brezillon 			flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
169293db446aSBoris Brezillon 
169393db446aSBoris Brezillon 		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
169493db446aSBoris Brezillon 
169593db446aSBoris Brezillon 		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
169693db446aSBoris Brezillon 		if (host->hwcfg.sector_size_1k)
169793db446aSBoris Brezillon 			brcmnand_set_sector_size_1k(host,
169893db446aSBoris Brezillon 						    host->hwcfg.sector_size_1k);
169993db446aSBoris Brezillon 	}
170093db446aSBoris Brezillon 
170193db446aSBoris Brezillon 	/* Re-enable protection is necessary only after erase */
170293db446aSBoris Brezillon 	if (command == NAND_CMD_ERASE1)
170393db446aSBoris Brezillon 		brcmnand_wp(mtd, 1);
170493db446aSBoris Brezillon }
170593db446aSBoris Brezillon 
17067e534323SBoris Brezillon static uint8_t brcmnand_read_byte(struct nand_chip *chip)
170793db446aSBoris Brezillon {
170893db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
170993db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
171093db446aSBoris Brezillon 	uint8_t ret = 0;
171193db446aSBoris Brezillon 	int addr, offs;
171293db446aSBoris Brezillon 
171393db446aSBoris Brezillon 	switch (host->last_cmd) {
171493db446aSBoris Brezillon 	case NAND_CMD_READID:
171593db446aSBoris Brezillon 		if (host->last_byte < 4)
171693db446aSBoris Brezillon 			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
171793db446aSBoris Brezillon 				(24 - (host->last_byte << 3));
171893db446aSBoris Brezillon 		else if (host->last_byte < 8)
171993db446aSBoris Brezillon 			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
172093db446aSBoris Brezillon 				(56 - (host->last_byte << 3));
172193db446aSBoris Brezillon 		break;
172293db446aSBoris Brezillon 
172393db446aSBoris Brezillon 	case NAND_CMD_READOOB:
172493db446aSBoris Brezillon 		ret = oob_reg_read(ctrl, host->last_byte);
172593db446aSBoris Brezillon 		break;
172693db446aSBoris Brezillon 
172793db446aSBoris Brezillon 	case NAND_CMD_STATUS:
172893db446aSBoris Brezillon 		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
172993db446aSBoris Brezillon 					INTFC_FLASH_STATUS;
173093db446aSBoris Brezillon 		if (wp_on) /* hide WP status */
173193db446aSBoris Brezillon 			ret |= NAND_STATUS_WP;
173293db446aSBoris Brezillon 		break;
173393db446aSBoris Brezillon 
173493db446aSBoris Brezillon 	case NAND_CMD_PARAM:
173593db446aSBoris Brezillon 	case NAND_CMD_RNDOUT:
173693db446aSBoris Brezillon 		addr = host->last_addr + host->last_byte;
173793db446aSBoris Brezillon 		offs = addr & (FC_BYTES - 1);
173893db446aSBoris Brezillon 
173993db446aSBoris Brezillon 		/* At FC_BYTES boundary, switch to next column */
174093db446aSBoris Brezillon 		if (host->last_byte > 0 && offs == 0)
174193db446aSBoris Brezillon 			nand_change_read_column_op(chip, addr, NULL, 0, false);
174293db446aSBoris Brezillon 
174393db446aSBoris Brezillon 		ret = ctrl->flash_cache[offs];
174493db446aSBoris Brezillon 		break;
174593db446aSBoris Brezillon 	case NAND_CMD_GET_FEATURES:
174693db446aSBoris Brezillon 		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
174793db446aSBoris Brezillon 			ret = 0;
174893db446aSBoris Brezillon 		} else {
174993db446aSBoris Brezillon 			bool last = host->last_byte ==
175093db446aSBoris Brezillon 				ONFI_SUBFEATURE_PARAM_LEN - 1;
175193db446aSBoris Brezillon 			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
175293db446aSBoris Brezillon 			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
175393db446aSBoris Brezillon 		}
175493db446aSBoris Brezillon 	}
175593db446aSBoris Brezillon 
175693db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
175793db446aSBoris Brezillon 	host->last_byte++;
175893db446aSBoris Brezillon 
175993db446aSBoris Brezillon 	return ret;
176093db446aSBoris Brezillon }
176193db446aSBoris Brezillon 
17627e534323SBoris Brezillon static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
176393db446aSBoris Brezillon {
176493db446aSBoris Brezillon 	int i;
176593db446aSBoris Brezillon 
176693db446aSBoris Brezillon 	for (i = 0; i < len; i++, buf++)
17677e534323SBoris Brezillon 		*buf = brcmnand_read_byte(chip);
176893db446aSBoris Brezillon }
176993db446aSBoris Brezillon 
1770c0739d85SBoris Brezillon static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
177193db446aSBoris Brezillon 			       int len)
177293db446aSBoris Brezillon {
177393db446aSBoris Brezillon 	int i;
177493db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
177593db446aSBoris Brezillon 
177693db446aSBoris Brezillon 	switch (host->last_cmd) {
177793db446aSBoris Brezillon 	case NAND_CMD_SET_FEATURES:
177893db446aSBoris Brezillon 		for (i = 0; i < len; i++)
177993db446aSBoris Brezillon 			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
178093db446aSBoris Brezillon 						  (i + 1) == len);
178193db446aSBoris Brezillon 		break;
178293db446aSBoris Brezillon 	default:
178393db446aSBoris Brezillon 		BUG();
178493db446aSBoris Brezillon 		break;
178593db446aSBoris Brezillon 	}
178693db446aSBoris Brezillon }
178793db446aSBoris Brezillon 
178893db446aSBoris Brezillon /**
1789a5d53ad2SKamal Dasu  *  Kick EDU engine
1790a5d53ad2SKamal Dasu  */
1791a5d53ad2SKamal Dasu static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
1792a5d53ad2SKamal Dasu 			      u32 len, u8 cmd)
1793a5d53ad2SKamal Dasu {
1794a5d53ad2SKamal Dasu 	struct brcmnand_controller *ctrl = host->ctrl;
1795a5d53ad2SKamal Dasu 	unsigned long timeo = msecs_to_jiffies(200);
1796a5d53ad2SKamal Dasu 	int ret = 0;
1797a5d53ad2SKamal Dasu 	int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
1798a5d53ad2SKamal Dasu 	u8 edu_cmd = (cmd == CMD_PAGE_READ ? EDU_CMD_READ : EDU_CMD_WRITE);
1799a5d53ad2SKamal Dasu 	unsigned int trans = len >> FC_SHIFT;
1800a5d53ad2SKamal Dasu 	dma_addr_t pa;
1801a5d53ad2SKamal Dasu 
1802a5d53ad2SKamal Dasu 	pa = dma_map_single(ctrl->dev, buf, len, dir);
1803a5d53ad2SKamal Dasu 	if (dma_mapping_error(ctrl->dev, pa)) {
1804a5d53ad2SKamal Dasu 		dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n");
1805a5d53ad2SKamal Dasu 		return -ENOMEM;
1806a5d53ad2SKamal Dasu 	}
1807a5d53ad2SKamal Dasu 
1808a5d53ad2SKamal Dasu 	ctrl->edu_pending = true;
1809a5d53ad2SKamal Dasu 	ctrl->edu_dram_addr = pa;
1810a5d53ad2SKamal Dasu 	ctrl->edu_ext_addr = addr;
1811a5d53ad2SKamal Dasu 	ctrl->edu_cmd = edu_cmd;
1812a5d53ad2SKamal Dasu 	ctrl->edu_count = trans;
1813a5d53ad2SKamal Dasu 
1814a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr);
1815a5d53ad2SKamal Dasu 	edu_readl(ctrl,  EDU_DRAM_ADDR);
1816a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr);
1817a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_EXT_ADDR);
1818a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_LENGTH, FC_BYTES);
1819a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_LENGTH);
1820a5d53ad2SKamal Dasu 
1821a5d53ad2SKamal Dasu 	/* Start edu engine */
1822a5d53ad2SKamal Dasu 	mb(); /* flush previous writes */
1823a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
1824a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_CMD);
1825a5d53ad2SKamal Dasu 
1826a5d53ad2SKamal Dasu 	if (wait_for_completion_timeout(&ctrl->edu_done, timeo) <= 0) {
1827a5d53ad2SKamal Dasu 		dev_err(ctrl->dev,
1828a5d53ad2SKamal Dasu 			"timeout waiting for EDU; status %#x, error status %#x\n",
1829a5d53ad2SKamal Dasu 			edu_readl(ctrl, EDU_STATUS),
1830a5d53ad2SKamal Dasu 			edu_readl(ctrl, EDU_ERR_STATUS));
1831a5d53ad2SKamal Dasu 	}
1832a5d53ad2SKamal Dasu 
1833a5d53ad2SKamal Dasu 	dma_unmap_single(ctrl->dev, pa, len, dir);
1834a5d53ad2SKamal Dasu 
1835a5d53ad2SKamal Dasu 	/* for program page check NAND status */
1836a5d53ad2SKamal Dasu 	if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
1837a5d53ad2SKamal Dasu 	      INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) &&
1838a5d53ad2SKamal Dasu 	    edu_cmd == EDU_CMD_WRITE) {
1839a5d53ad2SKamal Dasu 		dev_info(ctrl->dev, "program failed at %llx\n",
1840a5d53ad2SKamal Dasu 			 (unsigned long long)addr);
1841a5d53ad2SKamal Dasu 		ret = -EIO;
1842a5d53ad2SKamal Dasu 	}
1843a5d53ad2SKamal Dasu 
1844a5d53ad2SKamal Dasu 	/* Make sure the EDU status is clean */
1845a5d53ad2SKamal Dasu 	if (edu_readl(ctrl, EDU_STATUS) & EDU_STATUS_ACTIVE)
1846a5d53ad2SKamal Dasu 		dev_warn(ctrl->dev, "EDU still active: %#x\n",
1847a5d53ad2SKamal Dasu 			 edu_readl(ctrl, EDU_STATUS));
1848a5d53ad2SKamal Dasu 
1849a5d53ad2SKamal Dasu 	if (unlikely(edu_readl(ctrl, EDU_ERR_STATUS) & EDU_ERR_STATUS_ERRACK)) {
1850a5d53ad2SKamal Dasu 		dev_warn(ctrl->dev, "EDU RBUS error at addr %llx\n",
1851a5d53ad2SKamal Dasu 			 (unsigned long long)addr);
1852a5d53ad2SKamal Dasu 		ret = -EIO;
1853a5d53ad2SKamal Dasu 	}
1854a5d53ad2SKamal Dasu 
1855a5d53ad2SKamal Dasu 	ctrl->edu_pending = false;
1856a5d53ad2SKamal Dasu 	brcmnand_edu_init(ctrl);
1857a5d53ad2SKamal Dasu 	edu_writel(ctrl, EDU_STOP, 0); /* force stop */
1858a5d53ad2SKamal Dasu 	edu_readl(ctrl, EDU_STOP);
1859a5d53ad2SKamal Dasu 
1860a5d53ad2SKamal Dasu 	return ret;
1861a5d53ad2SKamal Dasu }
1862a5d53ad2SKamal Dasu 
1863a5d53ad2SKamal Dasu /**
186493db446aSBoris Brezillon  * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
186593db446aSBoris Brezillon  * following ahead of time:
186693db446aSBoris Brezillon  *  - Is this descriptor the beginning or end of a linked list?
186793db446aSBoris Brezillon  *  - What is the (DMA) address of the next descriptor in the linked list?
186893db446aSBoris Brezillon  */
186993db446aSBoris Brezillon static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
187093db446aSBoris Brezillon 				  struct brcm_nand_dma_desc *desc, u64 addr,
187193db446aSBoris Brezillon 				  dma_addr_t buf, u32 len, u8 dma_cmd,
187293db446aSBoris Brezillon 				  bool begin, bool end,
187393db446aSBoris Brezillon 				  dma_addr_t next_desc)
187493db446aSBoris Brezillon {
187593db446aSBoris Brezillon 	memset(desc, 0, sizeof(*desc));
187693db446aSBoris Brezillon 	/* Descriptors are written in native byte order (wordwise) */
187793db446aSBoris Brezillon 	desc->next_desc = lower_32_bits(next_desc);
187893db446aSBoris Brezillon 	desc->next_desc_ext = upper_32_bits(next_desc);
187993db446aSBoris Brezillon 	desc->cmd_irq = (dma_cmd << 24) |
188093db446aSBoris Brezillon 		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
188193db446aSBoris Brezillon 		(!!begin) | ((!!end) << 1); /* head, tail */
188293db446aSBoris Brezillon #ifdef CONFIG_CPU_BIG_ENDIAN
188393db446aSBoris Brezillon 	desc->cmd_irq |= 0x01 << 12;
188493db446aSBoris Brezillon #endif
188593db446aSBoris Brezillon 	desc->dram_addr = lower_32_bits(buf);
188693db446aSBoris Brezillon 	desc->dram_addr_ext = upper_32_bits(buf);
188793db446aSBoris Brezillon 	desc->tfr_len = len;
188893db446aSBoris Brezillon 	desc->total_len = len;
188993db446aSBoris Brezillon 	desc->flash_addr = lower_32_bits(addr);
189093db446aSBoris Brezillon 	desc->flash_addr_ext = upper_32_bits(addr);
189193db446aSBoris Brezillon 	desc->cs = host->cs;
189293db446aSBoris Brezillon 	desc->status_valid = 0x01;
189393db446aSBoris Brezillon 	return 0;
189493db446aSBoris Brezillon }
189593db446aSBoris Brezillon 
189693db446aSBoris Brezillon /**
189793db446aSBoris Brezillon  * Kick the FLASH_DMA engine, with a given DMA descriptor
189893db446aSBoris Brezillon  */
189993db446aSBoris Brezillon static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
190093db446aSBoris Brezillon {
190193db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
190293db446aSBoris Brezillon 	unsigned long timeo = msecs_to_jiffies(100);
190393db446aSBoris Brezillon 
190493db446aSBoris Brezillon 	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
190593db446aSBoris Brezillon 	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
190683156c1cSKamal Dasu 	if (ctrl->nand_version > 0x0602) {
190783156c1cSKamal Dasu 		flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT,
190883156c1cSKamal Dasu 				 upper_32_bits(desc));
190993db446aSBoris Brezillon 		(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
191083156c1cSKamal Dasu 	}
191193db446aSBoris Brezillon 
191293db446aSBoris Brezillon 	/* Start FLASH_DMA engine */
191393db446aSBoris Brezillon 	ctrl->dma_pending = true;
191493db446aSBoris Brezillon 	mb(); /* flush previous writes */
191593db446aSBoris Brezillon 	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
191693db446aSBoris Brezillon 
191793db446aSBoris Brezillon 	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
191893db446aSBoris Brezillon 		dev_err(ctrl->dev,
191993db446aSBoris Brezillon 				"timeout waiting for DMA; status %#x, error status %#x\n",
192093db446aSBoris Brezillon 				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
192193db446aSBoris Brezillon 				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
192293db446aSBoris Brezillon 	}
192393db446aSBoris Brezillon 	ctrl->dma_pending = false;
192493db446aSBoris Brezillon 	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
192593db446aSBoris Brezillon }
192693db446aSBoris Brezillon 
192793db446aSBoris Brezillon static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
192893db446aSBoris Brezillon 			      u32 len, u8 dma_cmd)
192993db446aSBoris Brezillon {
193093db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
193193db446aSBoris Brezillon 	dma_addr_t buf_pa;
193293db446aSBoris Brezillon 	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
193393db446aSBoris Brezillon 
193493db446aSBoris Brezillon 	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
193593db446aSBoris Brezillon 	if (dma_mapping_error(ctrl->dev, buf_pa)) {
193693db446aSBoris Brezillon 		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
193793db446aSBoris Brezillon 		return -ENOMEM;
193893db446aSBoris Brezillon 	}
193993db446aSBoris Brezillon 
194093db446aSBoris Brezillon 	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
194193db446aSBoris Brezillon 				   dma_cmd, true, true, 0);
194293db446aSBoris Brezillon 
194393db446aSBoris Brezillon 	brcmnand_dma_run(host, ctrl->dma_pa);
194493db446aSBoris Brezillon 
194593db446aSBoris Brezillon 	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
194693db446aSBoris Brezillon 
194793db446aSBoris Brezillon 	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
194893db446aSBoris Brezillon 		return -EBADMSG;
194993db446aSBoris Brezillon 	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
195093db446aSBoris Brezillon 		return -EUCLEAN;
195193db446aSBoris Brezillon 
195293db446aSBoris Brezillon 	return 0;
195393db446aSBoris Brezillon }
195493db446aSBoris Brezillon 
195593db446aSBoris Brezillon /*
195693db446aSBoris Brezillon  * Assumes proper CS is already set
195793db446aSBoris Brezillon  */
195893db446aSBoris Brezillon static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
195993db446aSBoris Brezillon 				u64 addr, unsigned int trans, u32 *buf,
196093db446aSBoris Brezillon 				u8 *oob, u64 *err_addr)
196193db446aSBoris Brezillon {
196293db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
196393db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
196493db446aSBoris Brezillon 	int i, j, ret = 0;
196593db446aSBoris Brezillon 
19663c7c1e45SKamal Dasu 	brcmnand_clear_ecc_addr(ctrl);
196793db446aSBoris Brezillon 
196893db446aSBoris Brezillon 	for (i = 0; i < trans; i++, addr += FC_BYTES) {
19693c7c1e45SKamal Dasu 		brcmnand_set_cmd_addr(mtd, addr);
197093db446aSBoris Brezillon 		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
197193db446aSBoris Brezillon 		brcmnand_send_cmd(host, CMD_PAGE_READ);
1972f1d46942SBoris Brezillon 		brcmnand_waitfunc(chip);
197393db446aSBoris Brezillon 
197493db446aSBoris Brezillon 		if (likely(buf)) {
197593db446aSBoris Brezillon 			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
197693db446aSBoris Brezillon 
197793db446aSBoris Brezillon 			for (j = 0; j < FC_WORDS; j++, buf++)
197893db446aSBoris Brezillon 				*buf = brcmnand_read_fc(ctrl, j);
197993db446aSBoris Brezillon 
198093db446aSBoris Brezillon 			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
198193db446aSBoris Brezillon 		}
198293db446aSBoris Brezillon 
198393db446aSBoris Brezillon 		if (oob)
198493db446aSBoris Brezillon 			oob += read_oob_from_regs(ctrl, i, oob,
198593db446aSBoris Brezillon 					mtd->oobsize / trans,
198693db446aSBoris Brezillon 					host->hwcfg.sector_size_1k);
198793db446aSBoris Brezillon 
198893db446aSBoris Brezillon 		if (!ret) {
19893c7c1e45SKamal Dasu 			*err_addr = brcmnand_get_uncorrecc_addr(ctrl);
19903c7c1e45SKamal Dasu 
199193db446aSBoris Brezillon 			if (*err_addr)
199293db446aSBoris Brezillon 				ret = -EBADMSG;
199393db446aSBoris Brezillon 		}
199493db446aSBoris Brezillon 
199593db446aSBoris Brezillon 		if (!ret) {
19963c7c1e45SKamal Dasu 			*err_addr = brcmnand_get_correcc_addr(ctrl);
19973c7c1e45SKamal Dasu 
199893db446aSBoris Brezillon 			if (*err_addr)
199993db446aSBoris Brezillon 				ret = -EUCLEAN;
200093db446aSBoris Brezillon 		}
200193db446aSBoris Brezillon 	}
200293db446aSBoris Brezillon 
200393db446aSBoris Brezillon 	return ret;
200493db446aSBoris Brezillon }
200593db446aSBoris Brezillon 
200693db446aSBoris Brezillon /*
200793db446aSBoris Brezillon  * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
200893db446aSBoris Brezillon  * error
200993db446aSBoris Brezillon  *
201093db446aSBoris Brezillon  * Because the HW ECC signals an ECC error if an erase paged has even a single
201193db446aSBoris Brezillon  * bitflip, we must check each ECC error to see if it is actually an erased
201293db446aSBoris Brezillon  * page with bitflips, not a truly corrupted page.
201393db446aSBoris Brezillon  *
201493db446aSBoris Brezillon  * On a real error, return a negative error code (-EBADMSG for ECC error), and
201593db446aSBoris Brezillon  * buf will contain raw data.
201693db446aSBoris Brezillon  * Otherwise, buf gets filled with 0xffs and return the maximum number of
201793db446aSBoris Brezillon  * bitflips-per-ECC-sector to the caller.
201893db446aSBoris Brezillon  *
201993db446aSBoris Brezillon  */
202093db446aSBoris Brezillon static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
202193db446aSBoris Brezillon 		  struct nand_chip *chip, void *buf, u64 addr)
202293db446aSBoris Brezillon {
202393db446aSBoris Brezillon 	int i, sas;
202493db446aSBoris Brezillon 	void *oob = chip->oob_poi;
202593db446aSBoris Brezillon 	int bitflips = 0;
202693db446aSBoris Brezillon 	int page = addr >> chip->page_shift;
202793db446aSBoris Brezillon 	int ret;
20287f852cc1SClaire Lin 	void *ecc_chunk;
202993db446aSBoris Brezillon 
2030eeab7174SBoris Brezillon 	if (!buf)
2031eeab7174SBoris Brezillon 		buf = nand_get_data_buf(chip);
203293db446aSBoris Brezillon 
203393db446aSBoris Brezillon 	sas = mtd->oobsize / chip->ecc.steps;
203493db446aSBoris Brezillon 
203593db446aSBoris Brezillon 	/* read without ecc for verification */
2036b9761687SBoris Brezillon 	ret = chip->ecc.read_page_raw(chip, buf, true, page);
203793db446aSBoris Brezillon 	if (ret)
203893db446aSBoris Brezillon 		return ret;
203993db446aSBoris Brezillon 
204093db446aSBoris Brezillon 	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
20417f852cc1SClaire Lin 		ecc_chunk = buf + chip->ecc.size * i;
20427f852cc1SClaire Lin 		ret = nand_check_erased_ecc_chunk(ecc_chunk,
20437f852cc1SClaire Lin 						  chip->ecc.size,
204493db446aSBoris Brezillon 						  oob, sas, NULL, 0,
204593db446aSBoris Brezillon 						  chip->ecc.strength);
204693db446aSBoris Brezillon 		if (ret < 0)
204793db446aSBoris Brezillon 			return ret;
204893db446aSBoris Brezillon 
204993db446aSBoris Brezillon 		bitflips = max(bitflips, ret);
205093db446aSBoris Brezillon 	}
205193db446aSBoris Brezillon 
205293db446aSBoris Brezillon 	return bitflips;
205393db446aSBoris Brezillon }
205493db446aSBoris Brezillon 
205593db446aSBoris Brezillon static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
205693db446aSBoris Brezillon 			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
205793db446aSBoris Brezillon {
205893db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
205993db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
206093db446aSBoris Brezillon 	u64 err_addr = 0;
206193db446aSBoris Brezillon 	int err;
206293db446aSBoris Brezillon 	bool retry = true;
206393db446aSBoris Brezillon 
206493db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
206593db446aSBoris Brezillon 
206693db446aSBoris Brezillon try_dmaread:
20673c7c1e45SKamal Dasu 	brcmnand_clear_ecc_addr(ctrl);
206893db446aSBoris Brezillon 
2069a5d53ad2SKamal Dasu 	if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) {
2070a5d53ad2SKamal Dasu 		err = ctrl->dma_trans(host, addr, buf,
2071a5d53ad2SKamal Dasu 				      trans * FC_BYTES,
207293db446aSBoris Brezillon 				      CMD_PAGE_READ);
2073a5d53ad2SKamal Dasu 
207493db446aSBoris Brezillon 		if (err) {
207593db446aSBoris Brezillon 			if (mtd_is_bitflip_or_eccerr(err))
207693db446aSBoris Brezillon 				err_addr = addr;
207793db446aSBoris Brezillon 			else
207893db446aSBoris Brezillon 				return -EIO;
207993db446aSBoris Brezillon 		}
208093db446aSBoris Brezillon 	} else {
208193db446aSBoris Brezillon 		if (oob)
208293db446aSBoris Brezillon 			memset(oob, 0x99, mtd->oobsize);
208393db446aSBoris Brezillon 
208493db446aSBoris Brezillon 		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
208593db446aSBoris Brezillon 					       oob, &err_addr);
208693db446aSBoris Brezillon 	}
208793db446aSBoris Brezillon 
208893db446aSBoris Brezillon 	if (mtd_is_eccerr(err)) {
208993db446aSBoris Brezillon 		/*
209093db446aSBoris Brezillon 		 * On controller version and 7.0, 7.1 , DMA read after a
209193db446aSBoris Brezillon 		 * prior PIO read that reported uncorrectable error,
209293db446aSBoris Brezillon 		 * the DMA engine captures this error following DMA read
209393db446aSBoris Brezillon 		 * cleared only on subsequent DMA read, so just retry once
209493db446aSBoris Brezillon 		 * to clear a possible false error reported for current DMA
209593db446aSBoris Brezillon 		 * read
209693db446aSBoris Brezillon 		 */
209793db446aSBoris Brezillon 		if ((ctrl->nand_version == 0x0700) ||
209893db446aSBoris Brezillon 		    (ctrl->nand_version == 0x0701)) {
209993db446aSBoris Brezillon 			if (retry) {
210093db446aSBoris Brezillon 				retry = false;
210193db446aSBoris Brezillon 				goto try_dmaread;
210293db446aSBoris Brezillon 			}
210393db446aSBoris Brezillon 		}
210493db446aSBoris Brezillon 
210593db446aSBoris Brezillon 		/*
210693db446aSBoris Brezillon 		 * Controller version 7.2 has hw encoder to detect erased page
210793db446aSBoris Brezillon 		 * bitflips, apply sw verification for older controllers only
210893db446aSBoris Brezillon 		 */
210993db446aSBoris Brezillon 		if (ctrl->nand_version < 0x0702) {
211093db446aSBoris Brezillon 			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
211193db446aSBoris Brezillon 							      addr);
211293db446aSBoris Brezillon 			/* erased page bitflips corrected */
211393db446aSBoris Brezillon 			if (err >= 0)
211493db446aSBoris Brezillon 				return err;
211593db446aSBoris Brezillon 		}
211693db446aSBoris Brezillon 
211793db446aSBoris Brezillon 		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
211893db446aSBoris Brezillon 			(unsigned long long)err_addr);
211993db446aSBoris Brezillon 		mtd->ecc_stats.failed++;
212093db446aSBoris Brezillon 		/* NAND layer expects zero on ECC errors */
212193db446aSBoris Brezillon 		return 0;
212293db446aSBoris Brezillon 	}
212393db446aSBoris Brezillon 
212493db446aSBoris Brezillon 	if (mtd_is_bitflip(err)) {
212593db446aSBoris Brezillon 		unsigned int corrected = brcmnand_count_corrected(ctrl);
212693db446aSBoris Brezillon 
212793db446aSBoris Brezillon 		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
212893db446aSBoris Brezillon 			(unsigned long long)err_addr);
212993db446aSBoris Brezillon 		mtd->ecc_stats.corrected += corrected;
213093db446aSBoris Brezillon 		/* Always exceed the software-imposed threshold */
213193db446aSBoris Brezillon 		return max(mtd->bitflip_threshold, corrected);
213293db446aSBoris Brezillon 	}
213393db446aSBoris Brezillon 
213493db446aSBoris Brezillon 	return 0;
213593db446aSBoris Brezillon }
213693db446aSBoris Brezillon 
2137b9761687SBoris Brezillon static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf,
2138b9761687SBoris Brezillon 			      int oob_required, int page)
213993db446aSBoris Brezillon {
2140b9761687SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
214193db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
214293db446aSBoris Brezillon 	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
214393db446aSBoris Brezillon 
214493db446aSBoris Brezillon 	nand_read_page_op(chip, page, 0, NULL, 0);
214593db446aSBoris Brezillon 
214693db446aSBoris Brezillon 	return brcmnand_read(mtd, chip, host->last_addr,
214793db446aSBoris Brezillon 			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
214893db446aSBoris Brezillon }
214993db446aSBoris Brezillon 
2150b9761687SBoris Brezillon static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
2151b9761687SBoris Brezillon 				  int oob_required, int page)
215293db446aSBoris Brezillon {
215393db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
2154b9761687SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
215593db446aSBoris Brezillon 	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
215693db446aSBoris Brezillon 	int ret;
215793db446aSBoris Brezillon 
215893db446aSBoris Brezillon 	nand_read_page_op(chip, page, 0, NULL, 0);
215993db446aSBoris Brezillon 
216093db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 0);
216193db446aSBoris Brezillon 	ret = brcmnand_read(mtd, chip, host->last_addr,
216293db446aSBoris Brezillon 			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
216393db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 1);
216493db446aSBoris Brezillon 	return ret;
216593db446aSBoris Brezillon }
216693db446aSBoris Brezillon 
2167b9761687SBoris Brezillon static int brcmnand_read_oob(struct nand_chip *chip, int page)
216893db446aSBoris Brezillon {
2169b9761687SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
2170b9761687SBoris Brezillon 
217193db446aSBoris Brezillon 	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
217293db446aSBoris Brezillon 			mtd->writesize >> FC_SHIFT,
217393db446aSBoris Brezillon 			NULL, (u8 *)chip->oob_poi);
217493db446aSBoris Brezillon }
217593db446aSBoris Brezillon 
2176b9761687SBoris Brezillon static int brcmnand_read_oob_raw(struct nand_chip *chip, int page)
217793db446aSBoris Brezillon {
2178b9761687SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
217993db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
218093db446aSBoris Brezillon 
218193db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 0);
218293db446aSBoris Brezillon 	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
218393db446aSBoris Brezillon 		mtd->writesize >> FC_SHIFT,
218493db446aSBoris Brezillon 		NULL, (u8 *)chip->oob_poi);
218593db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 1);
218693db446aSBoris Brezillon 	return 0;
218793db446aSBoris Brezillon }
218893db446aSBoris Brezillon 
218993db446aSBoris Brezillon static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
219093db446aSBoris Brezillon 			  u64 addr, const u32 *buf, u8 *oob)
219193db446aSBoris Brezillon {
219293db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
219393db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
219493db446aSBoris Brezillon 	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
219593db446aSBoris Brezillon 	int status, ret = 0;
219693db446aSBoris Brezillon 
219793db446aSBoris Brezillon 	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
219893db446aSBoris Brezillon 
219993db446aSBoris Brezillon 	if (unlikely((unsigned long)buf & 0x03)) {
220093db446aSBoris Brezillon 		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
220193db446aSBoris Brezillon 		buf = (u32 *)((unsigned long)buf & ~0x03);
220293db446aSBoris Brezillon 	}
220393db446aSBoris Brezillon 
220493db446aSBoris Brezillon 	brcmnand_wp(mtd, 0);
220593db446aSBoris Brezillon 
220693db446aSBoris Brezillon 	for (i = 0; i < ctrl->max_oob; i += 4)
220793db446aSBoris Brezillon 		oob_reg_write(ctrl, i, 0xffffffff);
220893db446aSBoris Brezillon 
2209a5d53ad2SKamal Dasu 	if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
2210a5d53ad2SKamal Dasu 		if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize,
2211a5d53ad2SKamal Dasu 				    CMD_PROGRAM_PAGE))
2212a5d53ad2SKamal Dasu 
221393db446aSBoris Brezillon 			ret = -EIO;
2214a5d53ad2SKamal Dasu 
221593db446aSBoris Brezillon 		goto out;
221693db446aSBoris Brezillon 	}
221793db446aSBoris Brezillon 
221893db446aSBoris Brezillon 	for (i = 0; i < trans; i++, addr += FC_BYTES) {
221993db446aSBoris Brezillon 		/* full address MUST be set before populating FC */
22203c7c1e45SKamal Dasu 		brcmnand_set_cmd_addr(mtd, addr);
222193db446aSBoris Brezillon 
222293db446aSBoris Brezillon 		if (buf) {
222393db446aSBoris Brezillon 			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
222493db446aSBoris Brezillon 
222593db446aSBoris Brezillon 			for (j = 0; j < FC_WORDS; j++, buf++)
222693db446aSBoris Brezillon 				brcmnand_write_fc(ctrl, j, *buf);
222793db446aSBoris Brezillon 
222893db446aSBoris Brezillon 			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
222993db446aSBoris Brezillon 		} else if (oob) {
223093db446aSBoris Brezillon 			for (j = 0; j < FC_WORDS; j++)
223193db446aSBoris Brezillon 				brcmnand_write_fc(ctrl, j, 0xffffffff);
223293db446aSBoris Brezillon 		}
223393db446aSBoris Brezillon 
223493db446aSBoris Brezillon 		if (oob) {
223593db446aSBoris Brezillon 			oob += write_oob_to_regs(ctrl, i, oob,
223693db446aSBoris Brezillon 					mtd->oobsize / trans,
223793db446aSBoris Brezillon 					host->hwcfg.sector_size_1k);
223893db446aSBoris Brezillon 		}
223993db446aSBoris Brezillon 
224093db446aSBoris Brezillon 		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
224193db446aSBoris Brezillon 		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
2242f1d46942SBoris Brezillon 		status = brcmnand_waitfunc(chip);
224393db446aSBoris Brezillon 
224493db446aSBoris Brezillon 		if (status & NAND_STATUS_FAIL) {
224593db446aSBoris Brezillon 			dev_info(ctrl->dev, "program failed at %llx\n",
224693db446aSBoris Brezillon 				(unsigned long long)addr);
224793db446aSBoris Brezillon 			ret = -EIO;
224893db446aSBoris Brezillon 			goto out;
224993db446aSBoris Brezillon 		}
225093db446aSBoris Brezillon 	}
225193db446aSBoris Brezillon out:
225293db446aSBoris Brezillon 	brcmnand_wp(mtd, 1);
225393db446aSBoris Brezillon 	return ret;
225493db446aSBoris Brezillon }
225593db446aSBoris Brezillon 
2256767eb6fbSBoris Brezillon static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf,
2257767eb6fbSBoris Brezillon 			       int oob_required, int page)
225893db446aSBoris Brezillon {
2259767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
226093db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
226193db446aSBoris Brezillon 	void *oob = oob_required ? chip->oob_poi : NULL;
226293db446aSBoris Brezillon 
226393db446aSBoris Brezillon 	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
226493db446aSBoris Brezillon 	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
226593db446aSBoris Brezillon 
226693db446aSBoris Brezillon 	return nand_prog_page_end_op(chip);
226793db446aSBoris Brezillon }
226893db446aSBoris Brezillon 
2269767eb6fbSBoris Brezillon static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
227093db446aSBoris Brezillon 				   int oob_required, int page)
227193db446aSBoris Brezillon {
2272767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
227393db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
227493db446aSBoris Brezillon 	void *oob = oob_required ? chip->oob_poi : NULL;
227593db446aSBoris Brezillon 
227693db446aSBoris Brezillon 	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
227793db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 0);
227893db446aSBoris Brezillon 	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
227993db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 1);
228093db446aSBoris Brezillon 
228193db446aSBoris Brezillon 	return nand_prog_page_end_op(chip);
228293db446aSBoris Brezillon }
228393db446aSBoris Brezillon 
2284767eb6fbSBoris Brezillon static int brcmnand_write_oob(struct nand_chip *chip, int page)
228593db446aSBoris Brezillon {
2286767eb6fbSBoris Brezillon 	return brcmnand_write(nand_to_mtd(chip), chip,
2287767eb6fbSBoris Brezillon 			      (u64)page << chip->page_shift, NULL,
2288767eb6fbSBoris Brezillon 			      chip->oob_poi);
228993db446aSBoris Brezillon }
229093db446aSBoris Brezillon 
2291767eb6fbSBoris Brezillon static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
229293db446aSBoris Brezillon {
2293767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
229493db446aSBoris Brezillon 	struct brcmnand_host *host = nand_get_controller_data(chip);
229593db446aSBoris Brezillon 	int ret;
229693db446aSBoris Brezillon 
229793db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 0);
229893db446aSBoris Brezillon 	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
229993db446aSBoris Brezillon 				 (u8 *)chip->oob_poi);
230093db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 1);
230193db446aSBoris Brezillon 
230293db446aSBoris Brezillon 	return ret;
230393db446aSBoris Brezillon }
230493db446aSBoris Brezillon 
230593db446aSBoris Brezillon /***********************************************************************
230693db446aSBoris Brezillon  * Per-CS setup (1 NAND device)
230793db446aSBoris Brezillon  ***********************************************************************/
230893db446aSBoris Brezillon 
230993db446aSBoris Brezillon static int brcmnand_set_cfg(struct brcmnand_host *host,
231093db446aSBoris Brezillon 			    struct brcmnand_cfg *cfg)
231193db446aSBoris Brezillon {
231293db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
231393db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
231493db446aSBoris Brezillon 	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
231593db446aSBoris Brezillon 	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
231693db446aSBoris Brezillon 			BRCMNAND_CS_CFG_EXT);
231793db446aSBoris Brezillon 	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
231893db446aSBoris Brezillon 			BRCMNAND_CS_ACC_CONTROL);
231993db446aSBoris Brezillon 	u8 block_size = 0, page_size = 0, device_size = 0;
232093db446aSBoris Brezillon 	u32 tmp;
232193db446aSBoris Brezillon 
232293db446aSBoris Brezillon 	if (ctrl->block_sizes) {
232393db446aSBoris Brezillon 		int i, found;
232493db446aSBoris Brezillon 
232593db446aSBoris Brezillon 		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
232693db446aSBoris Brezillon 			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
232793db446aSBoris Brezillon 				block_size = i;
232893db446aSBoris Brezillon 				found = 1;
232993db446aSBoris Brezillon 			}
233093db446aSBoris Brezillon 		if (!found) {
233193db446aSBoris Brezillon 			dev_warn(ctrl->dev, "invalid block size %u\n",
233293db446aSBoris Brezillon 					cfg->block_size);
233393db446aSBoris Brezillon 			return -EINVAL;
233493db446aSBoris Brezillon 		}
233593db446aSBoris Brezillon 	} else {
233693db446aSBoris Brezillon 		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
233793db446aSBoris Brezillon 	}
233893db446aSBoris Brezillon 
233993db446aSBoris Brezillon 	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
234093db446aSBoris Brezillon 				cfg->block_size > ctrl->max_block_size)) {
234193db446aSBoris Brezillon 		dev_warn(ctrl->dev, "invalid block size %u\n",
234293db446aSBoris Brezillon 				cfg->block_size);
234393db446aSBoris Brezillon 		block_size = 0;
234493db446aSBoris Brezillon 	}
234593db446aSBoris Brezillon 
234693db446aSBoris Brezillon 	if (ctrl->page_sizes) {
234793db446aSBoris Brezillon 		int i, found;
234893db446aSBoris Brezillon 
234993db446aSBoris Brezillon 		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
235093db446aSBoris Brezillon 			if (ctrl->page_sizes[i] == cfg->page_size) {
235193db446aSBoris Brezillon 				page_size = i;
235293db446aSBoris Brezillon 				found = 1;
235393db446aSBoris Brezillon 			}
235493db446aSBoris Brezillon 		if (!found) {
235593db446aSBoris Brezillon 			dev_warn(ctrl->dev, "invalid page size %u\n",
235693db446aSBoris Brezillon 					cfg->page_size);
235793db446aSBoris Brezillon 			return -EINVAL;
235893db446aSBoris Brezillon 		}
235993db446aSBoris Brezillon 	} else {
236093db446aSBoris Brezillon 		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
236193db446aSBoris Brezillon 	}
236293db446aSBoris Brezillon 
236393db446aSBoris Brezillon 	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
236493db446aSBoris Brezillon 				cfg->page_size > ctrl->max_page_size)) {
236593db446aSBoris Brezillon 		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
236693db446aSBoris Brezillon 		return -EINVAL;
236793db446aSBoris Brezillon 	}
236893db446aSBoris Brezillon 
236993db446aSBoris Brezillon 	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
237093db446aSBoris Brezillon 		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
237193db446aSBoris Brezillon 			(unsigned long long)cfg->device_size);
237293db446aSBoris Brezillon 		return -EINVAL;
237393db446aSBoris Brezillon 	}
237493db446aSBoris Brezillon 	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
237593db446aSBoris Brezillon 
237693db446aSBoris Brezillon 	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
237793db446aSBoris Brezillon 		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
237893db446aSBoris Brezillon 		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
237993db446aSBoris Brezillon 		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
238093db446aSBoris Brezillon 		(device_size << CFG_DEVICE_SIZE_SHIFT);
238193db446aSBoris Brezillon 	if (cfg_offs == cfg_ext_offs) {
238293db446aSBoris Brezillon 		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
238393db446aSBoris Brezillon 		       (block_size << CFG_BLK_SIZE_SHIFT);
238493db446aSBoris Brezillon 		nand_writereg(ctrl, cfg_offs, tmp);
238593db446aSBoris Brezillon 	} else {
238693db446aSBoris Brezillon 		nand_writereg(ctrl, cfg_offs, tmp);
238793db446aSBoris Brezillon 		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
238893db446aSBoris Brezillon 		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
238993db446aSBoris Brezillon 		nand_writereg(ctrl, cfg_ext_offs, tmp);
239093db446aSBoris Brezillon 	}
239193db446aSBoris Brezillon 
239293db446aSBoris Brezillon 	tmp = nand_readreg(ctrl, acc_control_offs);
239393db446aSBoris Brezillon 	tmp &= ~brcmnand_ecc_level_mask(ctrl);
239493db446aSBoris Brezillon 	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
239593db446aSBoris Brezillon 	tmp &= ~brcmnand_spare_area_mask(ctrl);
239693db446aSBoris Brezillon 	tmp |= cfg->spare_area_size;
239793db446aSBoris Brezillon 	nand_writereg(ctrl, acc_control_offs, tmp);
239893db446aSBoris Brezillon 
239993db446aSBoris Brezillon 	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
240093db446aSBoris Brezillon 
240193db446aSBoris Brezillon 	/* threshold = ceil(BCH-level * 0.75) */
240293db446aSBoris Brezillon 	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
240393db446aSBoris Brezillon 
240493db446aSBoris Brezillon 	return 0;
240593db446aSBoris Brezillon }
240693db446aSBoris Brezillon 
240793db446aSBoris Brezillon static void brcmnand_print_cfg(struct brcmnand_host *host,
240893db446aSBoris Brezillon 			       char *buf, struct brcmnand_cfg *cfg)
240993db446aSBoris Brezillon {
241093db446aSBoris Brezillon 	buf += sprintf(buf,
241193db446aSBoris Brezillon 		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
241293db446aSBoris Brezillon 		(unsigned long long)cfg->device_size >> 20,
241393db446aSBoris Brezillon 		cfg->block_size >> 10,
241493db446aSBoris Brezillon 		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
241593db446aSBoris Brezillon 		cfg->page_size >= 1024 ? "KiB" : "B",
241693db446aSBoris Brezillon 		cfg->spare_area_size, cfg->device_width);
241793db446aSBoris Brezillon 
241893db446aSBoris Brezillon 	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
241993db446aSBoris Brezillon 	if (is_hamming_ecc(host->ctrl, cfg))
242093db446aSBoris Brezillon 		sprintf(buf, ", Hamming ECC");
242193db446aSBoris Brezillon 	else if (cfg->sector_size_1k)
242293db446aSBoris Brezillon 		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
242393db446aSBoris Brezillon 	else
242493db446aSBoris Brezillon 		sprintf(buf, ", BCH-%u", cfg->ecc_level);
242593db446aSBoris Brezillon }
242693db446aSBoris Brezillon 
242793db446aSBoris Brezillon /*
242893db446aSBoris Brezillon  * Minimum number of bytes to address a page. Calculated as:
242993db446aSBoris Brezillon  *     roundup(log2(size / page-size) / 8)
243093db446aSBoris Brezillon  *
243193db446aSBoris Brezillon  * NB: the following does not "round up" for non-power-of-2 'size'; but this is
243293db446aSBoris Brezillon  *     OK because many other things will break if 'size' is irregular...
243393db446aSBoris Brezillon  */
243493db446aSBoris Brezillon static inline int get_blk_adr_bytes(u64 size, u32 writesize)
243593db446aSBoris Brezillon {
243693db446aSBoris Brezillon 	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
243793db446aSBoris Brezillon }
243893db446aSBoris Brezillon 
243993db446aSBoris Brezillon static int brcmnand_setup_dev(struct brcmnand_host *host)
244093db446aSBoris Brezillon {
244193db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(&host->chip);
244293db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
244393db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
244493db446aSBoris Brezillon 	struct brcmnand_cfg *cfg = &host->hwcfg;
244593db446aSBoris Brezillon 	char msg[128];
244693db446aSBoris Brezillon 	u32 offs, tmp, oob_sector;
244793db446aSBoris Brezillon 	int ret;
244893db446aSBoris Brezillon 
244993db446aSBoris Brezillon 	memset(cfg, 0, sizeof(*cfg));
245093db446aSBoris Brezillon 
245193db446aSBoris Brezillon 	ret = of_property_read_u32(nand_get_flash_node(chip),
245293db446aSBoris Brezillon 				   "brcm,nand-oob-sector-size",
245393db446aSBoris Brezillon 				   &oob_sector);
245493db446aSBoris Brezillon 	if (ret) {
245593db446aSBoris Brezillon 		/* Use detected size */
245693db446aSBoris Brezillon 		cfg->spare_area_size = mtd->oobsize /
245793db446aSBoris Brezillon 					(mtd->writesize >> FC_SHIFT);
245893db446aSBoris Brezillon 	} else {
245993db446aSBoris Brezillon 		cfg->spare_area_size = oob_sector;
246093db446aSBoris Brezillon 	}
246193db446aSBoris Brezillon 	if (cfg->spare_area_size > ctrl->max_oob)
246293db446aSBoris Brezillon 		cfg->spare_area_size = ctrl->max_oob;
246393db446aSBoris Brezillon 	/*
246493db446aSBoris Brezillon 	 * Set oobsize to be consistent with controller's spare_area_size, as
246593db446aSBoris Brezillon 	 * the rest is inaccessible.
246693db446aSBoris Brezillon 	 */
246793db446aSBoris Brezillon 	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
246893db446aSBoris Brezillon 
246993db446aSBoris Brezillon 	cfg->device_size = mtd->size;
247093db446aSBoris Brezillon 	cfg->block_size = mtd->erasesize;
247193db446aSBoris Brezillon 	cfg->page_size = mtd->writesize;
247293db446aSBoris Brezillon 	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
247393db446aSBoris Brezillon 	cfg->col_adr_bytes = 2;
247493db446aSBoris Brezillon 	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
247593db446aSBoris Brezillon 
247693db446aSBoris Brezillon 	if (chip->ecc.mode != NAND_ECC_HW) {
247793db446aSBoris Brezillon 		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
247893db446aSBoris Brezillon 			chip->ecc.mode);
247993db446aSBoris Brezillon 		return -EINVAL;
248093db446aSBoris Brezillon 	}
248193db446aSBoris Brezillon 
248293db446aSBoris Brezillon 	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
248393db446aSBoris Brezillon 		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
248493db446aSBoris Brezillon 			/* Default to Hamming for 1-bit ECC, if unspecified */
248593db446aSBoris Brezillon 			chip->ecc.algo = NAND_ECC_HAMMING;
248693db446aSBoris Brezillon 		else
248793db446aSBoris Brezillon 			/* Otherwise, BCH */
248893db446aSBoris Brezillon 			chip->ecc.algo = NAND_ECC_BCH;
248993db446aSBoris Brezillon 	}
249093db446aSBoris Brezillon 
249193db446aSBoris Brezillon 	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
249293db446aSBoris Brezillon 						   chip->ecc.size != 512)) {
249393db446aSBoris Brezillon 		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
249493db446aSBoris Brezillon 			chip->ecc.strength, chip->ecc.size);
249593db446aSBoris Brezillon 		return -EINVAL;
249693db446aSBoris Brezillon 	}
249793db446aSBoris Brezillon 
249878933218SKamal Dasu 	if (chip->ecc.mode != NAND_ECC_NONE &&
249978933218SKamal Dasu 	    (!chip->ecc.size || !chip->ecc.strength)) {
250078933218SKamal Dasu 		if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
250178933218SKamal Dasu 			/* use detected ECC parameters */
250278933218SKamal Dasu 			chip->ecc.size = chip->base.eccreq.step_size;
250378933218SKamal Dasu 			chip->ecc.strength = chip->base.eccreq.strength;
250478933218SKamal Dasu 			dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
250578933218SKamal Dasu 				chip->ecc.size, chip->ecc.strength);
250678933218SKamal Dasu 		}
250778933218SKamal Dasu 	}
250878933218SKamal Dasu 
250993db446aSBoris Brezillon 	switch (chip->ecc.size) {
251093db446aSBoris Brezillon 	case 512:
251193db446aSBoris Brezillon 		if (chip->ecc.algo == NAND_ECC_HAMMING)
251293db446aSBoris Brezillon 			cfg->ecc_level = 15;
251393db446aSBoris Brezillon 		else
251493db446aSBoris Brezillon 			cfg->ecc_level = chip->ecc.strength;
251593db446aSBoris Brezillon 		cfg->sector_size_1k = 0;
251693db446aSBoris Brezillon 		break;
251793db446aSBoris Brezillon 	case 1024:
251893db446aSBoris Brezillon 		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
251993db446aSBoris Brezillon 			dev_err(ctrl->dev, "1KB sectors not supported\n");
252093db446aSBoris Brezillon 			return -EINVAL;
252193db446aSBoris Brezillon 		}
252293db446aSBoris Brezillon 		if (chip->ecc.strength & 0x1) {
252393db446aSBoris Brezillon 			dev_err(ctrl->dev,
252493db446aSBoris Brezillon 				"odd ECC not supported with 1KB sectors\n");
252593db446aSBoris Brezillon 			return -EINVAL;
252693db446aSBoris Brezillon 		}
252793db446aSBoris Brezillon 
252893db446aSBoris Brezillon 		cfg->ecc_level = chip->ecc.strength >> 1;
252993db446aSBoris Brezillon 		cfg->sector_size_1k = 1;
253093db446aSBoris Brezillon 		break;
253193db446aSBoris Brezillon 	default:
253293db446aSBoris Brezillon 		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
253393db446aSBoris Brezillon 			chip->ecc.size);
253493db446aSBoris Brezillon 		return -EINVAL;
253593db446aSBoris Brezillon 	}
253693db446aSBoris Brezillon 
253793db446aSBoris Brezillon 	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
253893db446aSBoris Brezillon 	if (mtd->writesize > 512)
253993db446aSBoris Brezillon 		cfg->ful_adr_bytes += cfg->col_adr_bytes;
254093db446aSBoris Brezillon 	else
254193db446aSBoris Brezillon 		cfg->ful_adr_bytes += 1;
254293db446aSBoris Brezillon 
254393db446aSBoris Brezillon 	ret = brcmnand_set_cfg(host, cfg);
254493db446aSBoris Brezillon 	if (ret)
254593db446aSBoris Brezillon 		return ret;
254693db446aSBoris Brezillon 
254793db446aSBoris Brezillon 	brcmnand_set_ecc_enabled(host, 1);
254893db446aSBoris Brezillon 
254993db446aSBoris Brezillon 	brcmnand_print_cfg(host, msg, cfg);
255093db446aSBoris Brezillon 	dev_info(ctrl->dev, "detected %s\n", msg);
255193db446aSBoris Brezillon 
255293db446aSBoris Brezillon 	/* Configure ACC_CONTROL */
255393db446aSBoris Brezillon 	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
255493db446aSBoris Brezillon 	tmp = nand_readreg(ctrl, offs);
255593db446aSBoris Brezillon 	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
255693db446aSBoris Brezillon 	tmp &= ~ACC_CONTROL_RD_ERASED;
255793db446aSBoris Brezillon 
255893db446aSBoris Brezillon 	/* We need to turn on Read from erased paged protected by ECC */
255993db446aSBoris Brezillon 	if (ctrl->nand_version >= 0x0702)
256093db446aSBoris Brezillon 		tmp |= ACC_CONTROL_RD_ERASED;
256193db446aSBoris Brezillon 	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
256293db446aSBoris Brezillon 	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
256393db446aSBoris Brezillon 		tmp &= ~ACC_CONTROL_PREFETCH;
256493db446aSBoris Brezillon 
256593db446aSBoris Brezillon 	nand_writereg(ctrl, offs, tmp);
256693db446aSBoris Brezillon 
256793db446aSBoris Brezillon 	return 0;
256893db446aSBoris Brezillon }
256993db446aSBoris Brezillon 
25704918b905SMiquel Raynal static int brcmnand_attach_chip(struct nand_chip *chip)
25714918b905SMiquel Raynal {
25724918b905SMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(chip);
25734918b905SMiquel Raynal 	struct brcmnand_host *host = nand_get_controller_data(chip);
25744918b905SMiquel Raynal 	int ret;
25754918b905SMiquel Raynal 
25764918b905SMiquel Raynal 	chip->options |= NAND_NO_SUBPAGE_WRITE;
25774918b905SMiquel Raynal 	/*
25784918b905SMiquel Raynal 	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
25794918b905SMiquel Raynal 	 * to/from, and have nand_base pass us a bounce buffer instead, as
25804918b905SMiquel Raynal 	 * needed.
25814918b905SMiquel Raynal 	 */
2582ce8148d7SMiquel Raynal 	chip->options |= NAND_USES_DMA;
25834918b905SMiquel Raynal 
25844918b905SMiquel Raynal 	if (chip->bbt_options & NAND_BBT_USE_FLASH)
25854918b905SMiquel Raynal 		chip->bbt_options |= NAND_BBT_NO_OOB;
25864918b905SMiquel Raynal 
25874918b905SMiquel Raynal 	if (brcmnand_setup_dev(host))
25884918b905SMiquel Raynal 		return -ENXIO;
25894918b905SMiquel Raynal 
25904918b905SMiquel Raynal 	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
25914918b905SMiquel Raynal 
25924918b905SMiquel Raynal 	/* only use our internal HW threshold */
25934918b905SMiquel Raynal 	mtd->bitflip_threshold = 1;
25944918b905SMiquel Raynal 
25954918b905SMiquel Raynal 	ret = brcmstb_choose_ecc_layout(host);
25964918b905SMiquel Raynal 
25974918b905SMiquel Raynal 	return ret;
25984918b905SMiquel Raynal }
25994918b905SMiquel Raynal 
26004918b905SMiquel Raynal static const struct nand_controller_ops brcmnand_controller_ops = {
26014918b905SMiquel Raynal 	.attach_chip = brcmnand_attach_chip,
26024918b905SMiquel Raynal };
26034918b905SMiquel Raynal 
260493db446aSBoris Brezillon static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
260593db446aSBoris Brezillon {
260693db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
260793db446aSBoris Brezillon 	struct platform_device *pdev = host->pdev;
260893db446aSBoris Brezillon 	struct mtd_info *mtd;
260993db446aSBoris Brezillon 	struct nand_chip *chip;
261093db446aSBoris Brezillon 	int ret;
261193db446aSBoris Brezillon 	u16 cfg_offs;
261293db446aSBoris Brezillon 
261393db446aSBoris Brezillon 	ret = of_property_read_u32(dn, "reg", &host->cs);
261493db446aSBoris Brezillon 	if (ret) {
261593db446aSBoris Brezillon 		dev_err(&pdev->dev, "can't get chip-select\n");
261693db446aSBoris Brezillon 		return -ENXIO;
261793db446aSBoris Brezillon 	}
261893db446aSBoris Brezillon 
261993db446aSBoris Brezillon 	mtd = nand_to_mtd(&host->chip);
262093db446aSBoris Brezillon 	chip = &host->chip;
262193db446aSBoris Brezillon 
262293db446aSBoris Brezillon 	nand_set_flash_node(chip, dn);
262393db446aSBoris Brezillon 	nand_set_controller_data(chip, host);
262493db446aSBoris Brezillon 	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
262593db446aSBoris Brezillon 				   host->cs);
262693db446aSBoris Brezillon 	if (!mtd->name)
262793db446aSBoris Brezillon 		return -ENOMEM;
262893db446aSBoris Brezillon 
262993db446aSBoris Brezillon 	mtd->owner = THIS_MODULE;
263093db446aSBoris Brezillon 	mtd->dev.parent = &pdev->dev;
263193db446aSBoris Brezillon 
2632bf6065c6SBoris Brezillon 	chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl;
2633bf6065c6SBoris Brezillon 	chip->legacy.cmdfunc = brcmnand_cmdfunc;
26348395b753SBoris Brezillon 	chip->legacy.waitfunc = brcmnand_waitfunc;
2635716bbbabSBoris Brezillon 	chip->legacy.read_byte = brcmnand_read_byte;
2636716bbbabSBoris Brezillon 	chip->legacy.read_buf = brcmnand_read_buf;
2637716bbbabSBoris Brezillon 	chip->legacy.write_buf = brcmnand_write_buf;
263893db446aSBoris Brezillon 
263993db446aSBoris Brezillon 	chip->ecc.mode = NAND_ECC_HW;
264093db446aSBoris Brezillon 	chip->ecc.read_page = brcmnand_read_page;
264193db446aSBoris Brezillon 	chip->ecc.write_page = brcmnand_write_page;
264293db446aSBoris Brezillon 	chip->ecc.read_page_raw = brcmnand_read_page_raw;
264393db446aSBoris Brezillon 	chip->ecc.write_page_raw = brcmnand_write_page_raw;
264493db446aSBoris Brezillon 	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
264593db446aSBoris Brezillon 	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
264693db446aSBoris Brezillon 	chip->ecc.read_oob = brcmnand_read_oob;
264793db446aSBoris Brezillon 	chip->ecc.write_oob = brcmnand_write_oob;
264893db446aSBoris Brezillon 
264993db446aSBoris Brezillon 	chip->controller = &ctrl->controller;
265093db446aSBoris Brezillon 
265193db446aSBoris Brezillon 	/*
265293db446aSBoris Brezillon 	 * The bootloader might have configured 16bit mode but
265393db446aSBoris Brezillon 	 * NAND READID command only works in 8bit mode. We force
265493db446aSBoris Brezillon 	 * 8bit mode here to ensure that NAND READID commands works.
265593db446aSBoris Brezillon 	 */
265693db446aSBoris Brezillon 	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
265793db446aSBoris Brezillon 	nand_writereg(ctrl, cfg_offs,
265893db446aSBoris Brezillon 		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
265993db446aSBoris Brezillon 
266000ad378fSBoris Brezillon 	ret = nand_scan(chip, 1);
266193db446aSBoris Brezillon 	if (ret)
266293db446aSBoris Brezillon 		return ret;
266393db446aSBoris Brezillon 
26645826b880SMiquel Raynal 	ret = mtd_device_register(mtd, NULL, 0);
26655826b880SMiquel Raynal 	if (ret)
26665826b880SMiquel Raynal 		nand_cleanup(chip);
26675826b880SMiquel Raynal 
26685826b880SMiquel Raynal 	return ret;
266993db446aSBoris Brezillon }
267093db446aSBoris Brezillon 
267193db446aSBoris Brezillon static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
267293db446aSBoris Brezillon 					    int restore)
267393db446aSBoris Brezillon {
267493db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = host->ctrl;
267593db446aSBoris Brezillon 	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
267693db446aSBoris Brezillon 	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
267793db446aSBoris Brezillon 			BRCMNAND_CS_CFG_EXT);
267893db446aSBoris Brezillon 	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
267993db446aSBoris Brezillon 			BRCMNAND_CS_ACC_CONTROL);
268093db446aSBoris Brezillon 	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
268193db446aSBoris Brezillon 	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
268293db446aSBoris Brezillon 
268393db446aSBoris Brezillon 	if (restore) {
268493db446aSBoris Brezillon 		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
268593db446aSBoris Brezillon 		if (cfg_offs != cfg_ext_offs)
268693db446aSBoris Brezillon 			nand_writereg(ctrl, cfg_ext_offs,
268793db446aSBoris Brezillon 				      host->hwcfg.config_ext);
268893db446aSBoris Brezillon 		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
268993db446aSBoris Brezillon 		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
269093db446aSBoris Brezillon 		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
269193db446aSBoris Brezillon 	} else {
269293db446aSBoris Brezillon 		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
269393db446aSBoris Brezillon 		if (cfg_offs != cfg_ext_offs)
269493db446aSBoris Brezillon 			host->hwcfg.config_ext =
269593db446aSBoris Brezillon 				nand_readreg(ctrl, cfg_ext_offs);
269693db446aSBoris Brezillon 		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
269793db446aSBoris Brezillon 		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
269893db446aSBoris Brezillon 		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
269993db446aSBoris Brezillon 	}
270093db446aSBoris Brezillon }
270193db446aSBoris Brezillon 
270293db446aSBoris Brezillon static int brcmnand_suspend(struct device *dev)
270393db446aSBoris Brezillon {
270493db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
270593db446aSBoris Brezillon 	struct brcmnand_host *host;
270693db446aSBoris Brezillon 
270793db446aSBoris Brezillon 	list_for_each_entry(host, &ctrl->host_list, node)
270893db446aSBoris Brezillon 		brcmnand_save_restore_cs_config(host, 0);
270993db446aSBoris Brezillon 
271093db446aSBoris Brezillon 	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
271193db446aSBoris Brezillon 	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
271293db446aSBoris Brezillon 	ctrl->corr_stat_threshold =
271393db446aSBoris Brezillon 		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
271493db446aSBoris Brezillon 
271593db446aSBoris Brezillon 	if (has_flash_dma(ctrl))
271693db446aSBoris Brezillon 		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
2717a5d53ad2SKamal Dasu 	else if (has_edu(ctrl))
2718a5d53ad2SKamal Dasu 		ctrl->edu_config = edu_readl(ctrl, EDU_CONFIG);
271993db446aSBoris Brezillon 
272093db446aSBoris Brezillon 	return 0;
272193db446aSBoris Brezillon }
272293db446aSBoris Brezillon 
272393db446aSBoris Brezillon static int brcmnand_resume(struct device *dev)
272493db446aSBoris Brezillon {
272593db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
272693db446aSBoris Brezillon 	struct brcmnand_host *host;
272793db446aSBoris Brezillon 
272893db446aSBoris Brezillon 	if (has_flash_dma(ctrl)) {
272993db446aSBoris Brezillon 		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
273093db446aSBoris Brezillon 		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
273193db446aSBoris Brezillon 	}
273293db446aSBoris Brezillon 
2733a5d53ad2SKamal Dasu 	if (has_edu(ctrl))
2734a5d53ad2SKamal Dasu 		ctrl->edu_config = edu_readl(ctrl, EDU_CONFIG);
2735a5d53ad2SKamal Dasu 	else {
2736a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_CONFIG, ctrl->edu_config);
2737a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_CONFIG);
2738a5d53ad2SKamal Dasu 		brcmnand_edu_init(ctrl);
2739a5d53ad2SKamal Dasu 	}
2740a5d53ad2SKamal Dasu 
274193db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
274293db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
274393db446aSBoris Brezillon 	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
274493db446aSBoris Brezillon 			ctrl->corr_stat_threshold);
274593db446aSBoris Brezillon 	if (ctrl->soc) {
274693db446aSBoris Brezillon 		/* Clear/re-enable interrupt */
274793db446aSBoris Brezillon 		ctrl->soc->ctlrdy_ack(ctrl->soc);
274893db446aSBoris Brezillon 		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
274993db446aSBoris Brezillon 	}
275093db446aSBoris Brezillon 
275193db446aSBoris Brezillon 	list_for_each_entry(host, &ctrl->host_list, node) {
275293db446aSBoris Brezillon 		struct nand_chip *chip = &host->chip;
275393db446aSBoris Brezillon 
275493db446aSBoris Brezillon 		brcmnand_save_restore_cs_config(host, 1);
275593db446aSBoris Brezillon 
275693db446aSBoris Brezillon 		/* Reset the chip, required by some chips after power-up */
275793db446aSBoris Brezillon 		nand_reset_op(chip);
275893db446aSBoris Brezillon 	}
275993db446aSBoris Brezillon 
276093db446aSBoris Brezillon 	return 0;
276193db446aSBoris Brezillon }
276293db446aSBoris Brezillon 
276393db446aSBoris Brezillon const struct dev_pm_ops brcmnand_pm_ops = {
276493db446aSBoris Brezillon 	.suspend		= brcmnand_suspend,
276593db446aSBoris Brezillon 	.resume			= brcmnand_resume,
276693db446aSBoris Brezillon };
276793db446aSBoris Brezillon EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
276893db446aSBoris Brezillon 
276993db446aSBoris Brezillon static const struct of_device_id brcmnand_of_match[] = {
277093db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v4.0" },
277193db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v5.0" },
277293db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v6.0" },
277393db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v6.1" },
277493db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v6.2" },
277593db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v7.0" },
277693db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v7.1" },
277793db446aSBoris Brezillon 	{ .compatible = "brcm,brcmnand-v7.2" },
27780c06da57SKamal Dasu 	{ .compatible = "brcm,brcmnand-v7.3" },
277993db446aSBoris Brezillon 	{},
278093db446aSBoris Brezillon };
278193db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, brcmnand_of_match);
278293db446aSBoris Brezillon 
278393db446aSBoris Brezillon /***********************************************************************
278493db446aSBoris Brezillon  * Platform driver setup (per controller)
278593db446aSBoris Brezillon  ***********************************************************************/
2786a5d53ad2SKamal Dasu static int brcmnand_edu_setup(struct platform_device *pdev)
2787a5d53ad2SKamal Dasu {
2788a5d53ad2SKamal Dasu 	struct device *dev = &pdev->dev;
2789a5d53ad2SKamal Dasu 	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
2790a5d53ad2SKamal Dasu 	struct resource *res;
2791a5d53ad2SKamal Dasu 	int ret;
2792a5d53ad2SKamal Dasu 
2793a5d53ad2SKamal Dasu 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-edu");
2794a5d53ad2SKamal Dasu 	if (res) {
2795a5d53ad2SKamal Dasu 		ctrl->edu_base = devm_ioremap_resource(dev, res);
2796a5d53ad2SKamal Dasu 		if (IS_ERR(ctrl->edu_base))
2797a5d53ad2SKamal Dasu 			return PTR_ERR(ctrl->edu_base);
2798a5d53ad2SKamal Dasu 
2799a5d53ad2SKamal Dasu 		ctrl->edu_offsets = edu_regs;
2800a5d53ad2SKamal Dasu 
2801a5d53ad2SKamal Dasu 		edu_writel(ctrl, EDU_CONFIG, EDU_CONFIG_MODE_NAND |
2802a5d53ad2SKamal Dasu 			   EDU_CONFIG_SWAP_CFG);
2803a5d53ad2SKamal Dasu 		edu_readl(ctrl, EDU_CONFIG);
2804a5d53ad2SKamal Dasu 
2805a5d53ad2SKamal Dasu 		/* initialize edu */
2806a5d53ad2SKamal Dasu 		brcmnand_edu_init(ctrl);
2807a5d53ad2SKamal Dasu 
2808a5d53ad2SKamal Dasu 		ctrl->edu_irq = platform_get_irq_optional(pdev, 1);
2809a5d53ad2SKamal Dasu 		if (ctrl->edu_irq < 0) {
2810a5d53ad2SKamal Dasu 			dev_warn(dev,
2811a5d53ad2SKamal Dasu 				 "FLASH EDU enabled, using ctlrdy irq\n");
2812a5d53ad2SKamal Dasu 		} else {
2813a5d53ad2SKamal Dasu 			ret = devm_request_irq(dev, ctrl->edu_irq,
2814a5d53ad2SKamal Dasu 					       brcmnand_edu_irq, 0,
2815a5d53ad2SKamal Dasu 					       "brcmnand-edu", ctrl);
2816a5d53ad2SKamal Dasu 			if (ret < 0) {
2817a5d53ad2SKamal Dasu 				dev_err(ctrl->dev, "can't allocate IRQ %d: error %d\n",
2818a5d53ad2SKamal Dasu 					ctrl->edu_irq, ret);
2819a5d53ad2SKamal Dasu 				return ret;
2820a5d53ad2SKamal Dasu 			}
2821a5d53ad2SKamal Dasu 
2822a5d53ad2SKamal Dasu 			dev_info(dev, "FLASH EDU enabled using irq %u\n",
2823a5d53ad2SKamal Dasu 				 ctrl->edu_irq);
2824a5d53ad2SKamal Dasu 		}
2825a5d53ad2SKamal Dasu 	}
2826a5d53ad2SKamal Dasu 
2827a5d53ad2SKamal Dasu 	return 0;
2828a5d53ad2SKamal Dasu }
282993db446aSBoris Brezillon 
283093db446aSBoris Brezillon int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
283193db446aSBoris Brezillon {
283293db446aSBoris Brezillon 	struct device *dev = &pdev->dev;
283393db446aSBoris Brezillon 	struct device_node *dn = dev->of_node, *child;
283493db446aSBoris Brezillon 	struct brcmnand_controller *ctrl;
283593db446aSBoris Brezillon 	struct resource *res;
283693db446aSBoris Brezillon 	int ret;
283793db446aSBoris Brezillon 
283893db446aSBoris Brezillon 	/* We only support device-tree instantiation */
283993db446aSBoris Brezillon 	if (!dn)
284093db446aSBoris Brezillon 		return -ENODEV;
284193db446aSBoris Brezillon 
284293db446aSBoris Brezillon 	if (!of_match_node(brcmnand_of_match, dn))
284393db446aSBoris Brezillon 		return -ENODEV;
284493db446aSBoris Brezillon 
284593db446aSBoris Brezillon 	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
284693db446aSBoris Brezillon 	if (!ctrl)
284793db446aSBoris Brezillon 		return -ENOMEM;
284893db446aSBoris Brezillon 
284993db446aSBoris Brezillon 	dev_set_drvdata(dev, ctrl);
285093db446aSBoris Brezillon 	ctrl->dev = dev;
285193db446aSBoris Brezillon 
285293db446aSBoris Brezillon 	init_completion(&ctrl->done);
285393db446aSBoris Brezillon 	init_completion(&ctrl->dma_done);
2854a5d53ad2SKamal Dasu 	init_completion(&ctrl->edu_done);
28557da45139SMiquel Raynal 	nand_controller_init(&ctrl->controller);
28564918b905SMiquel Raynal 	ctrl->controller.ops = &brcmnand_controller_ops;
285793db446aSBoris Brezillon 	INIT_LIST_HEAD(&ctrl->host_list);
285893db446aSBoris Brezillon 
285993db446aSBoris Brezillon 	/* NAND register range */
286093db446aSBoris Brezillon 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
286193db446aSBoris Brezillon 	ctrl->nand_base = devm_ioremap_resource(dev, res);
286293db446aSBoris Brezillon 	if (IS_ERR(ctrl->nand_base))
286393db446aSBoris Brezillon 		return PTR_ERR(ctrl->nand_base);
286493db446aSBoris Brezillon 
286593db446aSBoris Brezillon 	/* Enable clock before using NAND registers */
286693db446aSBoris Brezillon 	ctrl->clk = devm_clk_get(dev, "nand");
286793db446aSBoris Brezillon 	if (!IS_ERR(ctrl->clk)) {
286893db446aSBoris Brezillon 		ret = clk_prepare_enable(ctrl->clk);
286993db446aSBoris Brezillon 		if (ret)
287093db446aSBoris Brezillon 			return ret;
287193db446aSBoris Brezillon 	} else {
287293db446aSBoris Brezillon 		ret = PTR_ERR(ctrl->clk);
287393db446aSBoris Brezillon 		if (ret == -EPROBE_DEFER)
287493db446aSBoris Brezillon 			return ret;
287593db446aSBoris Brezillon 
287693db446aSBoris Brezillon 		ctrl->clk = NULL;
287793db446aSBoris Brezillon 	}
287893db446aSBoris Brezillon 
287993db446aSBoris Brezillon 	/* Initialize NAND revision */
288093db446aSBoris Brezillon 	ret = brcmnand_revision_init(ctrl);
288193db446aSBoris Brezillon 	if (ret)
288293db446aSBoris Brezillon 		goto err;
288393db446aSBoris Brezillon 
288493db446aSBoris Brezillon 	/*
288593db446aSBoris Brezillon 	 * Most chips have this cache at a fixed offset within 'nand' block.
288693db446aSBoris Brezillon 	 * Some must specify this region separately.
288793db446aSBoris Brezillon 	 */
288893db446aSBoris Brezillon 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
288993db446aSBoris Brezillon 	if (res) {
289093db446aSBoris Brezillon 		ctrl->nand_fc = devm_ioremap_resource(dev, res);
289193db446aSBoris Brezillon 		if (IS_ERR(ctrl->nand_fc)) {
289293db446aSBoris Brezillon 			ret = PTR_ERR(ctrl->nand_fc);
289393db446aSBoris Brezillon 			goto err;
289493db446aSBoris Brezillon 		}
289593db446aSBoris Brezillon 	} else {
289693db446aSBoris Brezillon 		ctrl->nand_fc = ctrl->nand_base +
289793db446aSBoris Brezillon 				ctrl->reg_offsets[BRCMNAND_FC_BASE];
289893db446aSBoris Brezillon 	}
289993db446aSBoris Brezillon 
290093db446aSBoris Brezillon 	/* FLASH_DMA */
290193db446aSBoris Brezillon 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
290293db446aSBoris Brezillon 	if (res) {
290393db446aSBoris Brezillon 		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
290493db446aSBoris Brezillon 		if (IS_ERR(ctrl->flash_dma_base)) {
290593db446aSBoris Brezillon 			ret = PTR_ERR(ctrl->flash_dma_base);
290693db446aSBoris Brezillon 			goto err;
290793db446aSBoris Brezillon 		}
290893db446aSBoris Brezillon 
29090c06da57SKamal Dasu 		/* initialize the dma version */
29100c06da57SKamal Dasu 		brcmnand_flash_dma_revision_init(ctrl);
29110c06da57SKamal Dasu 
2912393947e5SFlorian Fainelli 		ret = -EIO;
2913393947e5SFlorian Fainelli 		if (ctrl->nand_version >= 0x0700)
2914393947e5SFlorian Fainelli 			ret = dma_set_mask_and_coherent(&pdev->dev,
2915393947e5SFlorian Fainelli 							DMA_BIT_MASK(40));
2916393947e5SFlorian Fainelli 		if (ret)
2917393947e5SFlorian Fainelli 			ret = dma_set_mask_and_coherent(&pdev->dev,
2918393947e5SFlorian Fainelli 							DMA_BIT_MASK(32));
2919393947e5SFlorian Fainelli 		if (ret)
2920393947e5SFlorian Fainelli 			goto err;
2921393947e5SFlorian Fainelli 
29220c06da57SKamal Dasu 		/* linked-list and stop on error */
29230c06da57SKamal Dasu 		flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK);
292493db446aSBoris Brezillon 		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
292593db446aSBoris Brezillon 
292693db446aSBoris Brezillon 		/* Allocate descriptor(s) */
292793db446aSBoris Brezillon 		ctrl->dma_desc = dmam_alloc_coherent(dev,
292893db446aSBoris Brezillon 						     sizeof(*ctrl->dma_desc),
292993db446aSBoris Brezillon 						     &ctrl->dma_pa, GFP_KERNEL);
293093db446aSBoris Brezillon 		if (!ctrl->dma_desc) {
293193db446aSBoris Brezillon 			ret = -ENOMEM;
293293db446aSBoris Brezillon 			goto err;
293393db446aSBoris Brezillon 		}
293493db446aSBoris Brezillon 
293593db446aSBoris Brezillon 		ctrl->dma_irq = platform_get_irq(pdev, 1);
293693db446aSBoris Brezillon 		if ((int)ctrl->dma_irq < 0) {
293793db446aSBoris Brezillon 			dev_err(dev, "missing FLASH_DMA IRQ\n");
293893db446aSBoris Brezillon 			ret = -ENODEV;
293993db446aSBoris Brezillon 			goto err;
294093db446aSBoris Brezillon 		}
294193db446aSBoris Brezillon 
294293db446aSBoris Brezillon 		ret = devm_request_irq(dev, ctrl->dma_irq,
294393db446aSBoris Brezillon 				brcmnand_dma_irq, 0, DRV_NAME,
294493db446aSBoris Brezillon 				ctrl);
294593db446aSBoris Brezillon 		if (ret < 0) {
294693db446aSBoris Brezillon 			dev_err(dev, "can't allocate IRQ %d: error %d\n",
294793db446aSBoris Brezillon 					ctrl->dma_irq, ret);
294893db446aSBoris Brezillon 			goto err;
294993db446aSBoris Brezillon 		}
295093db446aSBoris Brezillon 
295193db446aSBoris Brezillon 		dev_info(dev, "enabling FLASH_DMA\n");
2952a5d53ad2SKamal Dasu 		/* set flash dma transfer function to call */
2953a5d53ad2SKamal Dasu 		ctrl->dma_trans = brcmnand_dma_trans;
2954a5d53ad2SKamal Dasu 	} else	{
2955a5d53ad2SKamal Dasu 		ret = brcmnand_edu_setup(pdev);
2956a5d53ad2SKamal Dasu 		if (ret < 0)
2957a5d53ad2SKamal Dasu 			goto err;
2958a5d53ad2SKamal Dasu 
2959a5d53ad2SKamal Dasu 		/* set edu transfer function to call */
2960a5d53ad2SKamal Dasu 		ctrl->dma_trans = brcmnand_edu_trans;
296193db446aSBoris Brezillon 	}
296293db446aSBoris Brezillon 
296393db446aSBoris Brezillon 	/* Disable automatic device ID config, direct addressing */
296493db446aSBoris Brezillon 	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
296593db446aSBoris Brezillon 			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
296693db446aSBoris Brezillon 	/* Disable XOR addressing */
296793db446aSBoris Brezillon 	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
296893db446aSBoris Brezillon 
296993db446aSBoris Brezillon 	if (ctrl->features & BRCMNAND_HAS_WP) {
297093db446aSBoris Brezillon 		/* Permanently disable write protection */
297193db446aSBoris Brezillon 		if (wp_on == 2)
297293db446aSBoris Brezillon 			brcmnand_set_wp(ctrl, false);
297393db446aSBoris Brezillon 	} else {
297493db446aSBoris Brezillon 		wp_on = 0;
297593db446aSBoris Brezillon 	}
297693db446aSBoris Brezillon 
297793db446aSBoris Brezillon 	/* IRQ */
297893db446aSBoris Brezillon 	ctrl->irq = platform_get_irq(pdev, 0);
297993db446aSBoris Brezillon 	if ((int)ctrl->irq < 0) {
298093db446aSBoris Brezillon 		dev_err(dev, "no IRQ defined\n");
298193db446aSBoris Brezillon 		ret = -ENODEV;
298293db446aSBoris Brezillon 		goto err;
298393db446aSBoris Brezillon 	}
298493db446aSBoris Brezillon 
298593db446aSBoris Brezillon 	/*
298693db446aSBoris Brezillon 	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
298793db446aSBoris Brezillon 	 * interesting ways
298893db446aSBoris Brezillon 	 */
298993db446aSBoris Brezillon 	if (soc) {
299093db446aSBoris Brezillon 		ctrl->soc = soc;
299193db446aSBoris Brezillon 
299293db446aSBoris Brezillon 		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
299393db446aSBoris Brezillon 				       DRV_NAME, ctrl);
299493db446aSBoris Brezillon 
299593db446aSBoris Brezillon 		/* Enable interrupt */
299693db446aSBoris Brezillon 		ctrl->soc->ctlrdy_ack(ctrl->soc);
299793db446aSBoris Brezillon 		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
299893db446aSBoris Brezillon 	} else {
299993db446aSBoris Brezillon 		/* Use standard interrupt infrastructure */
300093db446aSBoris Brezillon 		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
300193db446aSBoris Brezillon 				       DRV_NAME, ctrl);
300293db446aSBoris Brezillon 	}
300393db446aSBoris Brezillon 	if (ret < 0) {
300493db446aSBoris Brezillon 		dev_err(dev, "can't allocate IRQ %d: error %d\n",
300593db446aSBoris Brezillon 			ctrl->irq, ret);
300693db446aSBoris Brezillon 		goto err;
300793db446aSBoris Brezillon 	}
300893db446aSBoris Brezillon 
300993db446aSBoris Brezillon 	for_each_available_child_of_node(dn, child) {
301093db446aSBoris Brezillon 		if (of_device_is_compatible(child, "brcm,nandcs")) {
301193db446aSBoris Brezillon 			struct brcmnand_host *host;
301293db446aSBoris Brezillon 
301393db446aSBoris Brezillon 			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
301493db446aSBoris Brezillon 			if (!host) {
301593db446aSBoris Brezillon 				of_node_put(child);
301693db446aSBoris Brezillon 				ret = -ENOMEM;
301793db446aSBoris Brezillon 				goto err;
301893db446aSBoris Brezillon 			}
301993db446aSBoris Brezillon 			host->pdev = pdev;
302093db446aSBoris Brezillon 			host->ctrl = ctrl;
302193db446aSBoris Brezillon 
302293db446aSBoris Brezillon 			ret = brcmnand_init_cs(host, child);
302393db446aSBoris Brezillon 			if (ret) {
302493db446aSBoris Brezillon 				devm_kfree(dev, host);
302593db446aSBoris Brezillon 				continue; /* Try all chip-selects */
302693db446aSBoris Brezillon 			}
302793db446aSBoris Brezillon 
302893db446aSBoris Brezillon 			list_add_tail(&host->node, &ctrl->host_list);
302993db446aSBoris Brezillon 		}
303093db446aSBoris Brezillon 	}
303193db446aSBoris Brezillon 
303293db446aSBoris Brezillon 	/* No chip-selects could initialize properly */
303393db446aSBoris Brezillon 	if (list_empty(&ctrl->host_list)) {
303493db446aSBoris Brezillon 		ret = -ENODEV;
303593db446aSBoris Brezillon 		goto err;
303693db446aSBoris Brezillon 	}
303793db446aSBoris Brezillon 
303893db446aSBoris Brezillon 	return 0;
303993db446aSBoris Brezillon 
304093db446aSBoris Brezillon err:
304193db446aSBoris Brezillon 	clk_disable_unprepare(ctrl->clk);
304293db446aSBoris Brezillon 	return ret;
304393db446aSBoris Brezillon 
304493db446aSBoris Brezillon }
304593db446aSBoris Brezillon EXPORT_SYMBOL_GPL(brcmnand_probe);
304693db446aSBoris Brezillon 
304793db446aSBoris Brezillon int brcmnand_remove(struct platform_device *pdev)
304893db446aSBoris Brezillon {
304993db446aSBoris Brezillon 	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
305093db446aSBoris Brezillon 	struct brcmnand_host *host;
305193db446aSBoris Brezillon 
305293db446aSBoris Brezillon 	list_for_each_entry(host, &ctrl->host_list, node)
305359ac276fSBoris Brezillon 		nand_release(&host->chip);
305493db446aSBoris Brezillon 
305593db446aSBoris Brezillon 	clk_disable_unprepare(ctrl->clk);
305693db446aSBoris Brezillon 
305793db446aSBoris Brezillon 	dev_set_drvdata(&pdev->dev, NULL);
305893db446aSBoris Brezillon 
305993db446aSBoris Brezillon 	return 0;
306093db446aSBoris Brezillon }
306193db446aSBoris Brezillon EXPORT_SYMBOL_GPL(brcmnand_remove);
306293db446aSBoris Brezillon 
306393db446aSBoris Brezillon MODULE_LICENSE("GPL v2");
306493db446aSBoris Brezillon MODULE_AUTHOR("Kevin Cernekee");
306593db446aSBoris Brezillon MODULE_AUTHOR("Brian Norris");
306693db446aSBoris Brezillon MODULE_DESCRIPTION("NAND driver for Broadcom chips");
306793db446aSBoris Brezillon MODULE_ALIAS("platform:brcmnand");
3068