xref: /openbmc/linux/drivers/mtd/nand/raw/qcom_nandc.c (revision c1e01cdbe0312d95b8c1542abd67fe786b534f57)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
493db446aSBoris Brezillon  */
593db446aSBoris Brezillon #include <linux/bitops.h>
693db446aSBoris Brezillon #include <linux/clk.h>
793ca966bSManivannan Sadhasivam #include <linux/delay.h>
893db446aSBoris Brezillon #include <linux/dmaengine.h>
993ca966bSManivannan Sadhasivam #include <linux/dma-mapping.h>
1093ca966bSManivannan Sadhasivam #include <linux/dma/qcom_adm.h>
1193ca966bSManivannan Sadhasivam #include <linux/dma/qcom_bam_dma.h>
1293db446aSBoris Brezillon #include <linux/module.h>
1393db446aSBoris Brezillon #include <linux/mtd/partitions.h>
1493ca966bSManivannan Sadhasivam #include <linux/mtd/rawnand.h>
1593db446aSBoris Brezillon #include <linux/of.h>
16c2fc6b69SRob Herring #include <linux/platform_device.h>
1793db446aSBoris Brezillon #include <linux/slab.h>
1893db446aSBoris Brezillon 
1993db446aSBoris Brezillon /* NANDc reg offsets */
2093db446aSBoris Brezillon #define	NAND_FLASH_CMD			0x00
2193db446aSBoris Brezillon #define	NAND_ADDR0			0x04
2293db446aSBoris Brezillon #define	NAND_ADDR1			0x08
2393db446aSBoris Brezillon #define	NAND_FLASH_CHIP_SELECT		0x0c
2493db446aSBoris Brezillon #define	NAND_EXEC_CMD			0x10
2593db446aSBoris Brezillon #define	NAND_FLASH_STATUS		0x14
2693db446aSBoris Brezillon #define	NAND_BUFFER_STATUS		0x18
2793db446aSBoris Brezillon #define	NAND_DEV0_CFG0			0x20
2893db446aSBoris Brezillon #define	NAND_DEV0_CFG1			0x24
2993db446aSBoris Brezillon #define	NAND_DEV0_ECC_CFG		0x28
300646493eSMd Sadre Alam #define	NAND_AUTO_STATUS_EN		0x2c
3193db446aSBoris Brezillon #define	NAND_DEV1_CFG0			0x30
3293db446aSBoris Brezillon #define	NAND_DEV1_CFG1			0x34
3393db446aSBoris Brezillon #define	NAND_READ_ID			0x40
3493db446aSBoris Brezillon #define	NAND_READ_STATUS		0x44
3593db446aSBoris Brezillon #define	NAND_DEV_CMD0			0xa0
3693db446aSBoris Brezillon #define	NAND_DEV_CMD1			0xa4
3793db446aSBoris Brezillon #define	NAND_DEV_CMD2			0xa8
3893db446aSBoris Brezillon #define	NAND_DEV_CMD_VLD		0xac
3993db446aSBoris Brezillon #define	SFLASHC_BURST_CFG		0xe0
4093db446aSBoris Brezillon #define	NAND_ERASED_CW_DETECT_CFG	0xe8
4193db446aSBoris Brezillon #define	NAND_ERASED_CW_DETECT_STATUS	0xec
4293db446aSBoris Brezillon #define	NAND_EBI2_ECC_BUF_CFG		0xf0
4393db446aSBoris Brezillon #define	FLASH_BUF_ACC			0x100
4493db446aSBoris Brezillon 
4593db446aSBoris Brezillon #define	NAND_CTRL			0xf00
4693db446aSBoris Brezillon #define	NAND_VERSION			0xf08
4793db446aSBoris Brezillon #define	NAND_READ_LOCATION_0		0xf20
4893db446aSBoris Brezillon #define	NAND_READ_LOCATION_1		0xf24
4993db446aSBoris Brezillon #define	NAND_READ_LOCATION_2		0xf28
5093db446aSBoris Brezillon #define	NAND_READ_LOCATION_3		0xf2c
51503ee5aaSMd Sadre Alam #define	NAND_READ_LOCATION_LAST_CW_0	0xf40
52503ee5aaSMd Sadre Alam #define	NAND_READ_LOCATION_LAST_CW_1	0xf44
53503ee5aaSMd Sadre Alam #define	NAND_READ_LOCATION_LAST_CW_2	0xf48
54503ee5aaSMd Sadre Alam #define	NAND_READ_LOCATION_LAST_CW_3	0xf4c
5593db446aSBoris Brezillon 
5693db446aSBoris Brezillon /* dummy register offsets, used by write_reg_dma */
5793db446aSBoris Brezillon #define	NAND_DEV_CMD1_RESTORE		0xdead
5893db446aSBoris Brezillon #define	NAND_DEV_CMD_VLD_RESTORE	0xbeef
5993db446aSBoris Brezillon 
6093db446aSBoris Brezillon /* NAND_FLASH_CMD bits */
6193db446aSBoris Brezillon #define	PAGE_ACC			BIT(4)
6293db446aSBoris Brezillon #define	LAST_PAGE			BIT(5)
6393db446aSBoris Brezillon 
6493db446aSBoris Brezillon /* NAND_FLASH_CHIP_SELECT bits */
6593db446aSBoris Brezillon #define	NAND_DEV_SEL			0
6693db446aSBoris Brezillon #define	DM_EN				BIT(2)
6793db446aSBoris Brezillon 
6893db446aSBoris Brezillon /* NAND_FLASH_STATUS bits */
6993db446aSBoris Brezillon #define	FS_OP_ERR			BIT(4)
7093db446aSBoris Brezillon #define	FS_READY_BSY_N			BIT(5)
7193db446aSBoris Brezillon #define	FS_MPU_ERR			BIT(8)
7293db446aSBoris Brezillon #define	FS_DEVICE_STS_ERR		BIT(16)
7393db446aSBoris Brezillon #define	FS_DEVICE_WP			BIT(23)
7493db446aSBoris Brezillon 
7593db446aSBoris Brezillon /* NAND_BUFFER_STATUS bits */
7693db446aSBoris Brezillon #define	BS_UNCORRECTABLE_BIT		BIT(8)
7793db446aSBoris Brezillon #define	BS_CORRECTABLE_ERR_MSK		0x1f
7893db446aSBoris Brezillon 
7993db446aSBoris Brezillon /* NAND_DEVn_CFG0 bits */
8093db446aSBoris Brezillon #define	DISABLE_STATUS_AFTER_WRITE	4
8193db446aSBoris Brezillon #define	CW_PER_PAGE			6
8293db446aSBoris Brezillon #define	UD_SIZE_BYTES			9
83862bdeddSChristian Marangi #define	UD_SIZE_BYTES_MASK		GENMASK(18, 9)
8493db446aSBoris Brezillon #define	ECC_PARITY_SIZE_BYTES_RS	19
8593db446aSBoris Brezillon #define	SPARE_SIZE_BYTES		23
86862bdeddSChristian Marangi #define	SPARE_SIZE_BYTES_MASK		GENMASK(26, 23)
8793db446aSBoris Brezillon #define	NUM_ADDR_CYCLES			27
8893db446aSBoris Brezillon #define	STATUS_BFR_READ			30
8993db446aSBoris Brezillon #define	SET_RD_MODE_AFTER_STATUS	31
9093db446aSBoris Brezillon 
9193db446aSBoris Brezillon /* NAND_DEVn_CFG0 bits */
9293db446aSBoris Brezillon #define	DEV0_CFG1_ECC_DISABLE		0
9393db446aSBoris Brezillon #define	WIDE_FLASH			1
9493db446aSBoris Brezillon #define	NAND_RECOVERY_CYCLES		2
9593db446aSBoris Brezillon #define	CS_ACTIVE_BSY			5
9693db446aSBoris Brezillon #define	BAD_BLOCK_BYTE_NUM		6
9793db446aSBoris Brezillon #define	BAD_BLOCK_IN_SPARE_AREA		16
9893db446aSBoris Brezillon #define	WR_RD_BSY_GAP			17
9993db446aSBoris Brezillon #define	ENABLE_BCH_ECC			27
10093db446aSBoris Brezillon 
10193db446aSBoris Brezillon /* NAND_DEV0_ECC_CFG bits */
10293db446aSBoris Brezillon #define	ECC_CFG_ECC_DISABLE		0
10393db446aSBoris Brezillon #define	ECC_SW_RESET			1
10493db446aSBoris Brezillon #define	ECC_MODE			4
10593db446aSBoris Brezillon #define	ECC_PARITY_SIZE_BYTES_BCH	8
10693db446aSBoris Brezillon #define	ECC_NUM_DATA_BYTES		16
107862bdeddSChristian Marangi #define	ECC_NUM_DATA_BYTES_MASK		GENMASK(25, 16)
10893db446aSBoris Brezillon #define	ECC_FORCE_CLK_OPEN		30
10993db446aSBoris Brezillon 
11093db446aSBoris Brezillon /* NAND_DEV_CMD1 bits */
11193db446aSBoris Brezillon #define	READ_ADDR			0
11293db446aSBoris Brezillon 
11393db446aSBoris Brezillon /* NAND_DEV_CMD_VLD bits */
11493db446aSBoris Brezillon #define	READ_START_VLD			BIT(0)
11593db446aSBoris Brezillon #define	READ_STOP_VLD			BIT(1)
11693db446aSBoris Brezillon #define	WRITE_START_VLD			BIT(2)
11793db446aSBoris Brezillon #define	ERASE_START_VLD			BIT(3)
11893db446aSBoris Brezillon #define	SEQ_READ_START_VLD		BIT(4)
11993db446aSBoris Brezillon 
12093db446aSBoris Brezillon /* NAND_EBI2_ECC_BUF_CFG bits */
12193db446aSBoris Brezillon #define	NUM_STEPS			0
12293db446aSBoris Brezillon 
12393db446aSBoris Brezillon /* NAND_ERASED_CW_DETECT_CFG bits */
12493db446aSBoris Brezillon #define	ERASED_CW_ECC_MASK		1
12593db446aSBoris Brezillon #define	AUTO_DETECT_RES			0
126a6de6660SMiquel Raynal #define	MASK_ECC			BIT(ERASED_CW_ECC_MASK)
127a6de6660SMiquel Raynal #define	RESET_ERASED_DET		BIT(AUTO_DETECT_RES)
12893db446aSBoris Brezillon #define	ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
12993db446aSBoris Brezillon #define	CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
13093db446aSBoris Brezillon #define	SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
13193db446aSBoris Brezillon 
13293db446aSBoris Brezillon /* NAND_ERASED_CW_DETECT_STATUS bits */
13393db446aSBoris Brezillon #define	PAGE_ALL_ERASED			BIT(7)
13493db446aSBoris Brezillon #define	CODEWORD_ALL_ERASED		BIT(6)
13593db446aSBoris Brezillon #define	PAGE_ERASED			BIT(5)
13693db446aSBoris Brezillon #define	CODEWORD_ERASED			BIT(4)
13793db446aSBoris Brezillon #define	ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
13893db446aSBoris Brezillon #define	ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
13993db446aSBoris Brezillon 
14093db446aSBoris Brezillon /* NAND_READ_LOCATION_n bits */
14193db446aSBoris Brezillon #define READ_LOCATION_OFFSET		0
14293db446aSBoris Brezillon #define READ_LOCATION_SIZE		16
14393db446aSBoris Brezillon #define READ_LOCATION_LAST		31
14493db446aSBoris Brezillon 
14593db446aSBoris Brezillon /* Version Mask */
14693db446aSBoris Brezillon #define	NAND_VERSION_MAJOR_MASK		0xf0000000
14793db446aSBoris Brezillon #define	NAND_VERSION_MAJOR_SHIFT	28
14893db446aSBoris Brezillon #define	NAND_VERSION_MINOR_MASK		0x0fff0000
14993db446aSBoris Brezillon #define	NAND_VERSION_MINOR_SHIFT	16
15093db446aSBoris Brezillon 
15193db446aSBoris Brezillon /* NAND OP_CMDs */
15233bf5519SOlof Johansson #define	OP_PAGE_READ			0x2
15333bf5519SOlof Johansson #define	OP_PAGE_READ_WITH_ECC		0x3
15433bf5519SOlof Johansson #define	OP_PAGE_READ_WITH_ECC_SPARE	0x4
155b1209582SManivannan Sadhasivam #define	OP_PAGE_READ_ONFI_READ		0x5
15633bf5519SOlof Johansson #define	OP_PROGRAM_PAGE			0x6
15733bf5519SOlof Johansson #define	OP_PAGE_PROGRAM_WITH_ECC	0x7
15833bf5519SOlof Johansson #define	OP_PROGRAM_PAGE_SPARE		0x9
15933bf5519SOlof Johansson #define	OP_BLOCK_ERASE			0xa
16089550bebSMd Sadre Alam #define	OP_CHECK_STATUS			0xc
16133bf5519SOlof Johansson #define	OP_FETCH_ID			0xb
16233bf5519SOlof Johansson #define	OP_RESET_DEVICE			0xd
16393db446aSBoris Brezillon 
16493db446aSBoris Brezillon /* Default Value for NAND_DEV_CMD_VLD */
16593db446aSBoris Brezillon #define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \
16693db446aSBoris Brezillon 					 ERASE_START_VLD | SEQ_READ_START_VLD)
16793db446aSBoris Brezillon 
16893db446aSBoris Brezillon /* NAND_CTRL bits */
16993db446aSBoris Brezillon #define	BAM_MODE_EN			BIT(0)
17093db446aSBoris Brezillon 
17193db446aSBoris Brezillon /*
17293db446aSBoris Brezillon  * the NAND controller performs reads/writes with ECC in 516 byte chunks.
17393db446aSBoris Brezillon  * the driver calls the chunks 'step' or 'codeword' interchangeably
17493db446aSBoris Brezillon  */
17593db446aSBoris Brezillon #define	NANDC_STEP_SIZE			512
17693db446aSBoris Brezillon 
17793db446aSBoris Brezillon /*
17893db446aSBoris Brezillon  * the largest page size we support is 8K, this will have 16 steps/codewords
17993db446aSBoris Brezillon  * of 512 bytes each
18093db446aSBoris Brezillon  */
18193db446aSBoris Brezillon #define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
18293db446aSBoris Brezillon 
18393db446aSBoris Brezillon /* we read at most 3 registers per codeword scan */
18493db446aSBoris Brezillon #define	MAX_REG_RD			(3 * MAX_NUM_STEPS)
18593db446aSBoris Brezillon 
18693db446aSBoris Brezillon /* ECC modes supported by the controller */
18793db446aSBoris Brezillon #define	ECC_NONE	BIT(0)
18893db446aSBoris Brezillon #define	ECC_RS_4BIT	BIT(1)
18993db446aSBoris Brezillon #define	ECC_BCH_4BIT	BIT(2)
19093db446aSBoris Brezillon #define	ECC_BCH_8BIT	BIT(3)
19193db446aSBoris Brezillon 
192e7a307f2SMd Sadre Alam #define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc)	\
193e7a307f2SMd Sadre Alam nandc_set_reg(chip, reg,			\
194622d3fc8SMd Sadre Alam 	      ((cw_offset) << READ_LOCATION_OFFSET) |		\
195622d3fc8SMd Sadre Alam 	      ((read_size) << READ_LOCATION_SIZE) |			\
196622d3fc8SMd Sadre Alam 	      ((is_last_read_loc) << READ_LOCATION_LAST))
19793db446aSBoris Brezillon 
198503ee5aaSMd Sadre Alam #define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc)	\
199503ee5aaSMd Sadre Alam nandc_set_reg(chip, reg,			\
200503ee5aaSMd Sadre Alam 	      ((cw_offset) << READ_LOCATION_OFFSET) |		\
201503ee5aaSMd Sadre Alam 	      ((read_size) << READ_LOCATION_SIZE) |			\
202503ee5aaSMd Sadre Alam 	      ((is_last_read_loc) << READ_LOCATION_LAST))
20393db446aSBoris Brezillon /*
20493db446aSBoris Brezillon  * Returns the actual register address for all NAND_DEV_ registers
20593db446aSBoris Brezillon  * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
20693db446aSBoris Brezillon  */
20793db446aSBoris Brezillon #define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
20893db446aSBoris Brezillon 
20993db446aSBoris Brezillon /* Returns the NAND register physical address */
21093db446aSBoris Brezillon #define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
21193db446aSBoris Brezillon 
21293db446aSBoris Brezillon /* Returns the dma address for reg read buffer */
21393db446aSBoris Brezillon #define reg_buf_dma_addr(chip, vaddr) \
21493db446aSBoris Brezillon 	((chip)->reg_read_dma + \
215428771b6SMiquel Raynal 	((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
21693db446aSBoris Brezillon 
21793db446aSBoris Brezillon #define QPIC_PER_CW_CMD_ELEMENTS	32
21893db446aSBoris Brezillon #define QPIC_PER_CW_CMD_SGL		32
21993db446aSBoris Brezillon #define QPIC_PER_CW_DATA_SGL		8
22093db446aSBoris Brezillon 
2216f20070dSAbhishek Sahu #define QPIC_NAND_COMPLETION_TIMEOUT	msecs_to_jiffies(2000)
2226f20070dSAbhishek Sahu 
22393db446aSBoris Brezillon /*
22493db446aSBoris Brezillon  * Flags used in DMA descriptor preparation helper functions
22593db446aSBoris Brezillon  * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
22693db446aSBoris Brezillon  */
22793db446aSBoris Brezillon /* Don't set the EOT in current tx BAM sgl */
22893db446aSBoris Brezillon #define NAND_BAM_NO_EOT			BIT(0)
22993db446aSBoris Brezillon /* Set the NWD flag in current BAM sgl */
23093db446aSBoris Brezillon #define NAND_BAM_NWD			BIT(1)
23193db446aSBoris Brezillon /* Finish writing in the current BAM sgl and start writing in another BAM sgl */
23293db446aSBoris Brezillon #define NAND_BAM_NEXT_SGL		BIT(2)
23393db446aSBoris Brezillon /*
23493db446aSBoris Brezillon  * Erased codeword status is being used two times in single transfer so this
23593db446aSBoris Brezillon  * flag will determine the current value of erased codeword status register
23693db446aSBoris Brezillon  */
23793db446aSBoris Brezillon #define NAND_ERASED_CW_SET		BIT(4)
23893db446aSBoris Brezillon 
23989550bebSMd Sadre Alam #define MAX_ADDRESS_CYCLE		5
24089550bebSMd Sadre Alam 
24193db446aSBoris Brezillon /*
24293db446aSBoris Brezillon  * This data type corresponds to the BAM transaction which will be used for all
24393db446aSBoris Brezillon  * NAND transfers.
24493db446aSBoris Brezillon  * @bam_ce - the array of BAM command elements
24593db446aSBoris Brezillon  * @cmd_sgl - sgl for NAND BAM command pipe
24693db446aSBoris Brezillon  * @data_sgl - sgl for NAND BAM consumer/producer pipe
247b360514eSChristian Marangi  * @last_data_desc - last DMA desc in data channel (tx/rx).
248b360514eSChristian Marangi  * @last_cmd_desc - last DMA desc in command channel.
249b360514eSChristian Marangi  * @txn_done - completion for NAND transfer.
25093db446aSBoris Brezillon  * @bam_ce_pos - the index in bam_ce which is available for next sgl
25193db446aSBoris Brezillon  * @bam_ce_start - the index in bam_ce which marks the start position ce
25293db446aSBoris Brezillon  *		   for current sgl. It will be used for size calculation
25393db446aSBoris Brezillon  *		   for current sgl
25493db446aSBoris Brezillon  * @cmd_sgl_pos - current index in command sgl.
25593db446aSBoris Brezillon  * @cmd_sgl_start - start index in command sgl.
25693db446aSBoris Brezillon  * @tx_sgl_pos - current index in data sgl for tx.
25793db446aSBoris Brezillon  * @tx_sgl_start - start index in data sgl for tx.
25893db446aSBoris Brezillon  * @rx_sgl_pos - current index in data sgl for rx.
25993db446aSBoris Brezillon  * @rx_sgl_start - start index in data sgl for rx.
2606f20070dSAbhishek Sahu  * @wait_second_completion - wait for second DMA desc completion before making
2616f20070dSAbhishek Sahu  *			     the NAND transfer completion.
26293db446aSBoris Brezillon  */
26393db446aSBoris Brezillon struct bam_transaction {
26493db446aSBoris Brezillon 	struct bam_cmd_element *bam_ce;
26593db446aSBoris Brezillon 	struct scatterlist *cmd_sgl;
26693db446aSBoris Brezillon 	struct scatterlist *data_sgl;
267b360514eSChristian Marangi 	struct dma_async_tx_descriptor *last_data_desc;
268b360514eSChristian Marangi 	struct dma_async_tx_descriptor *last_cmd_desc;
269b360514eSChristian Marangi 	struct completion txn_done;
27093db446aSBoris Brezillon 	u32 bam_ce_pos;
27193db446aSBoris Brezillon 	u32 bam_ce_start;
27293db446aSBoris Brezillon 	u32 cmd_sgl_pos;
27393db446aSBoris Brezillon 	u32 cmd_sgl_start;
27493db446aSBoris Brezillon 	u32 tx_sgl_pos;
27593db446aSBoris Brezillon 	u32 tx_sgl_start;
27693db446aSBoris Brezillon 	u32 rx_sgl_pos;
27793db446aSBoris Brezillon 	u32 rx_sgl_start;
2786f20070dSAbhishek Sahu 	bool wait_second_completion;
27993db446aSBoris Brezillon };
28093db446aSBoris Brezillon 
28193db446aSBoris Brezillon /*
28293db446aSBoris Brezillon  * This data type corresponds to the nand dma descriptor
283b360514eSChristian Marangi  * @dma_desc - low level DMA engine descriptor
28493db446aSBoris Brezillon  * @list - list for desc_info
285b360514eSChristian Marangi  *
28693db446aSBoris Brezillon  * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
28793db446aSBoris Brezillon  *	      ADM
28893db446aSBoris Brezillon  * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
28993db446aSBoris Brezillon  * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
290b360514eSChristian Marangi  * @dir - DMA transfer direction
29193db446aSBoris Brezillon  */
29293db446aSBoris Brezillon struct desc_info {
293b360514eSChristian Marangi 	struct dma_async_tx_descriptor *dma_desc;
29493db446aSBoris Brezillon 	struct list_head node;
29593db446aSBoris Brezillon 
29693db446aSBoris Brezillon 	union {
29793db446aSBoris Brezillon 		struct scatterlist adm_sgl;
29893db446aSBoris Brezillon 		struct {
29993db446aSBoris Brezillon 			struct scatterlist *bam_sgl;
30093db446aSBoris Brezillon 			int sgl_cnt;
30193db446aSBoris Brezillon 		};
30293db446aSBoris Brezillon 	};
303b360514eSChristian Marangi 	enum dma_data_direction dir;
30493db446aSBoris Brezillon };
30593db446aSBoris Brezillon 
30693db446aSBoris Brezillon /*
30793db446aSBoris Brezillon  * holds the current register values that we want to write. acts as a contiguous
30893db446aSBoris Brezillon  * chunk of memory which we use to write the controller registers through DMA.
30993db446aSBoris Brezillon  */
31093db446aSBoris Brezillon struct nandc_regs {
31193db446aSBoris Brezillon 	__le32 cmd;
31293db446aSBoris Brezillon 	__le32 addr0;
31393db446aSBoris Brezillon 	__le32 addr1;
31493db446aSBoris Brezillon 	__le32 chip_sel;
31593db446aSBoris Brezillon 	__le32 exec;
31693db446aSBoris Brezillon 
31793db446aSBoris Brezillon 	__le32 cfg0;
31893db446aSBoris Brezillon 	__le32 cfg1;
31993db446aSBoris Brezillon 	__le32 ecc_bch_cfg;
32093db446aSBoris Brezillon 
32193db446aSBoris Brezillon 	__le32 clrflashstatus;
32293db446aSBoris Brezillon 	__le32 clrreadstatus;
32393db446aSBoris Brezillon 
32493db446aSBoris Brezillon 	__le32 cmd1;
32593db446aSBoris Brezillon 	__le32 vld;
32693db446aSBoris Brezillon 
32793db446aSBoris Brezillon 	__le32 orig_cmd1;
32893db446aSBoris Brezillon 	__le32 orig_vld;
32993db446aSBoris Brezillon 
33093db446aSBoris Brezillon 	__le32 ecc_buf_cfg;
33193db446aSBoris Brezillon 	__le32 read_location0;
33293db446aSBoris Brezillon 	__le32 read_location1;
33393db446aSBoris Brezillon 	__le32 read_location2;
33493db446aSBoris Brezillon 	__le32 read_location3;
335503ee5aaSMd Sadre Alam 	__le32 read_location_last0;
336503ee5aaSMd Sadre Alam 	__le32 read_location_last1;
337503ee5aaSMd Sadre Alam 	__le32 read_location_last2;
338503ee5aaSMd Sadre Alam 	__le32 read_location_last3;
33993db446aSBoris Brezillon 
34093db446aSBoris Brezillon 	__le32 erased_cw_detect_cfg_clr;
34193db446aSBoris Brezillon 	__le32 erased_cw_detect_cfg_set;
34293db446aSBoris Brezillon };
34393db446aSBoris Brezillon 
34493db446aSBoris Brezillon /*
34593db446aSBoris Brezillon  * NAND controller data struct
34693db446aSBoris Brezillon  *
347b360514eSChristian Marangi  * @dev:			parent device
348b360514eSChristian Marangi  *
349b360514eSChristian Marangi  * @base:			MMIO base
350b360514eSChristian Marangi  *
351b360514eSChristian Marangi  * @core_clk:			controller clock
352b360514eSChristian Marangi  * @aon_clk:			another controller clock
353b360514eSChristian Marangi  *
354b360514eSChristian Marangi  * @regs:			a contiguous chunk of memory for DMA register
355b360514eSChristian Marangi  *				writes. contains the register values to be
356b360514eSChristian Marangi  *				written to controller
357b360514eSChristian Marangi  *
358b360514eSChristian Marangi  * @props:			properties of current NAND controller,
359b360514eSChristian Marangi  *				initialized via DT match data
360b360514eSChristian Marangi  *
36193db446aSBoris Brezillon  * @controller:			base controller structure
36293db446aSBoris Brezillon  * @host_list:			list containing all the chips attached to the
36393db446aSBoris Brezillon  *				controller
36493db446aSBoris Brezillon  *
36593db446aSBoris Brezillon  * @chan:			dma channel
36693db446aSBoris Brezillon  * @cmd_crci:			ADM DMA CRCI for command flow control
36793db446aSBoris Brezillon  * @data_crci:			ADM DMA CRCI for data flow control
368b360514eSChristian Marangi  *
36993db446aSBoris Brezillon  * @desc_list:			DMA descriptor list (list of desc_infos)
37093db446aSBoris Brezillon  *
37193db446aSBoris Brezillon  * @data_buffer:		our local DMA buffer for page read/writes,
37293db446aSBoris Brezillon  *				used when we can't use the buffer provided
37393db446aSBoris Brezillon  *				by upper layers directly
374b360514eSChristian Marangi  * @reg_read_buf:		local buffer for reading back registers via DMA
375b360514eSChristian Marangi  *
376b360514eSChristian Marangi  * @base_phys:			physical base address of controller registers
377b360514eSChristian Marangi  * @base_dma:			dma base address of controller registers
378b360514eSChristian Marangi  * @reg_read_dma:		contains dma address for register read buffer
379b360514eSChristian Marangi  *
380716bbbabSBoris Brezillon  * @buf_size/count/start:	markers for chip->legacy.read_buf/write_buf
381716bbbabSBoris Brezillon  *				functions
38293db446aSBoris Brezillon  * @max_cwperpage:		maximum QPIC codewords required. calculated
38393db446aSBoris Brezillon  *				from all connected NAND devices pagesize
384b360514eSChristian Marangi  *
385b360514eSChristian Marangi  * @reg_read_pos:		marker for data read in reg_read_buf
386b360514eSChristian Marangi  *
387b360514eSChristian Marangi  * @cmd1/vld:			some fixed controller register values
38889550bebSMd Sadre Alam  *
38989550bebSMd Sadre Alam  * @exec_opwrite:		flag to select correct number of code word
39089550bebSMd Sadre Alam  *				while reading status
39193db446aSBoris Brezillon  */
39293db446aSBoris Brezillon struct qcom_nand_controller {
39393db446aSBoris Brezillon 	struct device *dev;
39493db446aSBoris Brezillon 
39593db446aSBoris Brezillon 	void __iomem *base;
39693db446aSBoris Brezillon 
39793db446aSBoris Brezillon 	struct clk *core_clk;
39893db446aSBoris Brezillon 	struct clk *aon_clk;
39993db446aSBoris Brezillon 
400b360514eSChristian Marangi 	struct nandc_regs *regs;
401b360514eSChristian Marangi 	struct bam_transaction *bam_txn;
402b360514eSChristian Marangi 
403b360514eSChristian Marangi 	const struct qcom_nandc_props *props;
404b360514eSChristian Marangi 
405b360514eSChristian Marangi 	struct nand_controller controller;
406b360514eSChristian Marangi 	struct list_head host_list;
407b360514eSChristian Marangi 
40893db446aSBoris Brezillon 	union {
40993db446aSBoris Brezillon 		/* will be used only by QPIC for BAM DMA */
41093db446aSBoris Brezillon 		struct {
41193db446aSBoris Brezillon 			struct dma_chan *tx_chan;
41293db446aSBoris Brezillon 			struct dma_chan *rx_chan;
41393db446aSBoris Brezillon 			struct dma_chan *cmd_chan;
41493db446aSBoris Brezillon 		};
41593db446aSBoris Brezillon 
41693db446aSBoris Brezillon 		/* will be used only by EBI2 for ADM DMA */
41793db446aSBoris Brezillon 		struct {
41893db446aSBoris Brezillon 			struct dma_chan *chan;
41993db446aSBoris Brezillon 			unsigned int cmd_crci;
42093db446aSBoris Brezillon 			unsigned int data_crci;
42193db446aSBoris Brezillon 		};
42293db446aSBoris Brezillon 	};
42393db446aSBoris Brezillon 
42493db446aSBoris Brezillon 	struct list_head desc_list;
42593db446aSBoris Brezillon 
42693db446aSBoris Brezillon 	u8		*data_buffer;
427b360514eSChristian Marangi 	__le32		*reg_read_buf;
428b360514eSChristian Marangi 
429b360514eSChristian Marangi 	phys_addr_t base_phys;
430b360514eSChristian Marangi 	dma_addr_t base_dma;
431b360514eSChristian Marangi 	dma_addr_t reg_read_dma;
432b360514eSChristian Marangi 
43393db446aSBoris Brezillon 	int		buf_size;
43493db446aSBoris Brezillon 	int		buf_count;
43593db446aSBoris Brezillon 	int		buf_start;
43693db446aSBoris Brezillon 	unsigned int	max_cwperpage;
43793db446aSBoris Brezillon 
43893db446aSBoris Brezillon 	int reg_read_pos;
43993db446aSBoris Brezillon 
44093db446aSBoris Brezillon 	u32 cmd1, vld;
44189550bebSMd Sadre Alam 	bool exec_opwrite;
44293db446aSBoris Brezillon };
44393db446aSBoris Brezillon 
44493db446aSBoris Brezillon /*
445862bdeddSChristian Marangi  * NAND special boot partitions
446862bdeddSChristian Marangi  *
447862bdeddSChristian Marangi  * @page_offset:		offset of the partition where spare data is not protected
448862bdeddSChristian Marangi  *				by ECC (value in pages)
449862bdeddSChristian Marangi  * @page_offset:		size of the partition where spare data is not protected
450862bdeddSChristian Marangi  *				by ECC (value in pages)
451862bdeddSChristian Marangi  */
452862bdeddSChristian Marangi struct qcom_nand_boot_partition {
453862bdeddSChristian Marangi 	u32 page_offset;
454862bdeddSChristian Marangi 	u32 page_size;
455862bdeddSChristian Marangi };
456862bdeddSChristian Marangi 
457862bdeddSChristian Marangi /*
45889550bebSMd Sadre Alam  * Qcom op for each exec_op transfer
45989550bebSMd Sadre Alam  *
46089550bebSMd Sadre Alam  * @data_instr:			data instruction pointer
46189550bebSMd Sadre Alam  * @data_instr_idx:		data instruction index
46289550bebSMd Sadre Alam  * @rdy_timeout_ms:		wait ready timeout in ms
46389550bebSMd Sadre Alam  * @rdy_delay_ns:		Additional delay in ns
46489550bebSMd Sadre Alam  * @addr1_reg:			Address1 register value
46589550bebSMd Sadre Alam  * @addr2_reg:			Address2 register value
46689550bebSMd Sadre Alam  * @cmd_reg:			CMD register value
46789550bebSMd Sadre Alam  * @flag:			flag for misc instruction
46889550bebSMd Sadre Alam  */
46989550bebSMd Sadre Alam struct qcom_op {
47089550bebSMd Sadre Alam 	const struct nand_op_instr *data_instr;
47189550bebSMd Sadre Alam 	unsigned int data_instr_idx;
47289550bebSMd Sadre Alam 	unsigned int rdy_timeout_ms;
47389550bebSMd Sadre Alam 	unsigned int rdy_delay_ns;
47489550bebSMd Sadre Alam 	u32 addr1_reg;
47589550bebSMd Sadre Alam 	u32 addr2_reg;
47689550bebSMd Sadre Alam 	u32 cmd_reg;
47789550bebSMd Sadre Alam 	u8 flag;
47889550bebSMd Sadre Alam };
47989550bebSMd Sadre Alam 
48089550bebSMd Sadre Alam /*
48193db446aSBoris Brezillon  * NAND chip structure
48293db446aSBoris Brezillon  *
483862bdeddSChristian Marangi  * @boot_partitions:		array of boot partitions where offset and size of the
484862bdeddSChristian Marangi  *				boot partitions are stored
485862bdeddSChristian Marangi  *
48693db446aSBoris Brezillon  * @chip:			base NAND chip structure
48793db446aSBoris Brezillon  * @node:			list node to add itself to host_list in
48893db446aSBoris Brezillon  *				qcom_nand_controller
48993db446aSBoris Brezillon  *
490862bdeddSChristian Marangi  * @nr_boot_partitions:		count of the boot partitions where spare data is not
491862bdeddSChristian Marangi  *				protected by ECC
492862bdeddSChristian Marangi  *
49393db446aSBoris Brezillon  * @cs:				chip select value for this chip
49493db446aSBoris Brezillon  * @cw_size:			the number of bytes in a single step/codeword
49593db446aSBoris Brezillon  *				of a page, consisting of all data, ecc, spare
49693db446aSBoris Brezillon  *				and reserved bytes
49793db446aSBoris Brezillon  * @cw_data:			the number of bytes within a codeword protected
49893db446aSBoris Brezillon  *				by ECC
49993db446aSBoris Brezillon  * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
50093db446aSBoris Brezillon  *				chip
501b360514eSChristian Marangi  *
50293db446aSBoris Brezillon  * @last_command:		keeps track of last command on this chip. used
50393db446aSBoris Brezillon  *				for reading correct status
50493db446aSBoris Brezillon  *
50593db446aSBoris Brezillon  * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
50693db446aSBoris Brezillon  *				ecc/non-ecc mode for the current nand flash
50793db446aSBoris Brezillon  *				device
508b360514eSChristian Marangi  *
509b360514eSChristian Marangi  * @status:			value to be returned if NAND_CMD_STATUS command
510b360514eSChristian Marangi  *				is executed
511862bdeddSChristian Marangi  * @codeword_fixup:		keep track of the current layout used by
512862bdeddSChristian Marangi  *				the driver for read/write operation.
513b360514eSChristian Marangi  * @use_ecc:			request the controller to use ECC for the
514b360514eSChristian Marangi  *				upcoming read/write
515b360514eSChristian Marangi  * @bch_enabled:		flag to tell whether BCH ECC mode is used
51693db446aSBoris Brezillon  */
51793db446aSBoris Brezillon struct qcom_nand_host {
518862bdeddSChristian Marangi 	struct qcom_nand_boot_partition *boot_partitions;
519862bdeddSChristian Marangi 
52093db446aSBoris Brezillon 	struct nand_chip chip;
52193db446aSBoris Brezillon 	struct list_head node;
52293db446aSBoris Brezillon 
523862bdeddSChristian Marangi 	int nr_boot_partitions;
524862bdeddSChristian Marangi 
52593db446aSBoris Brezillon 	int cs;
52693db446aSBoris Brezillon 	int cw_size;
52793db446aSBoris Brezillon 	int cw_data;
52893db446aSBoris Brezillon 	int ecc_bytes_hw;
52993db446aSBoris Brezillon 	int spare_bytes;
53093db446aSBoris Brezillon 	int bbm_size;
531b360514eSChristian Marangi 
53293db446aSBoris Brezillon 	int last_command;
53393db446aSBoris Brezillon 
53493db446aSBoris Brezillon 	u32 cfg0, cfg1;
53593db446aSBoris Brezillon 	u32 cfg0_raw, cfg1_raw;
53693db446aSBoris Brezillon 	u32 ecc_buf_cfg;
53793db446aSBoris Brezillon 	u32 ecc_bch_cfg;
53893db446aSBoris Brezillon 	u32 clrflashstatus;
53993db446aSBoris Brezillon 	u32 clrreadstatus;
540b360514eSChristian Marangi 
541b360514eSChristian Marangi 	u8 status;
542862bdeddSChristian Marangi 	bool codeword_fixup;
543b360514eSChristian Marangi 	bool use_ecc;
544b360514eSChristian Marangi 	bool bch_enabled;
54593db446aSBoris Brezillon };
54693db446aSBoris Brezillon 
54793db446aSBoris Brezillon /*
54893db446aSBoris Brezillon  * This data type corresponds to the NAND controller properties which varies
54993db446aSBoris Brezillon  * among different NAND controllers.
55093db446aSBoris Brezillon  * @ecc_modes - ecc mode for NAND
551b360514eSChristian Marangi  * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
55293db446aSBoris Brezillon  * @is_bam - whether NAND controller is using BAM
553443440ccSSivaprakash Murugesan  * @is_qpic - whether NAND CTRL is part of qpic IP
554b1209582SManivannan Sadhasivam  * @qpic_v2 - flag to indicate QPIC IP version 2
555862bdeddSChristian Marangi  * @use_codeword_fixup - whether NAND has different layout for boot partitions
55693db446aSBoris Brezillon  */
55793db446aSBoris Brezillon struct qcom_nandc_props {
55893db446aSBoris Brezillon 	u32 ecc_modes;
559b360514eSChristian Marangi 	u32 dev_cmd_reg_start;
56093db446aSBoris Brezillon 	bool is_bam;
561443440ccSSivaprakash Murugesan 	bool is_qpic;
562b1209582SManivannan Sadhasivam 	bool qpic_v2;
563862bdeddSChristian Marangi 	bool use_codeword_fixup;
56493db446aSBoris Brezillon };
56593db446aSBoris Brezillon 
56693db446aSBoris Brezillon /* Frees the BAM transaction memory */
free_bam_transaction(struct qcom_nand_controller * nandc)56793db446aSBoris Brezillon static void free_bam_transaction(struct qcom_nand_controller *nandc)
56893db446aSBoris Brezillon {
56993db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
57093db446aSBoris Brezillon 
57193db446aSBoris Brezillon 	devm_kfree(nandc->dev, bam_txn);
57293db446aSBoris Brezillon }
57393db446aSBoris Brezillon 
57493db446aSBoris Brezillon /* Allocates and Initializes the BAM transaction */
57593db446aSBoris Brezillon static struct bam_transaction *
alloc_bam_transaction(struct qcom_nand_controller * nandc)57693db446aSBoris Brezillon alloc_bam_transaction(struct qcom_nand_controller *nandc)
57793db446aSBoris Brezillon {
57893db446aSBoris Brezillon 	struct bam_transaction *bam_txn;
57993db446aSBoris Brezillon 	size_t bam_txn_size;
58093db446aSBoris Brezillon 	unsigned int num_cw = nandc->max_cwperpage;
58193db446aSBoris Brezillon 	void *bam_txn_buf;
58293db446aSBoris Brezillon 
58393db446aSBoris Brezillon 	bam_txn_size =
58493db446aSBoris Brezillon 		sizeof(*bam_txn) + num_cw *
58593db446aSBoris Brezillon 		((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
58693db446aSBoris Brezillon 		(sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
58793db446aSBoris Brezillon 		(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
58893db446aSBoris Brezillon 
58993db446aSBoris Brezillon 	bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
59093db446aSBoris Brezillon 	if (!bam_txn_buf)
59193db446aSBoris Brezillon 		return NULL;
59293db446aSBoris Brezillon 
59393db446aSBoris Brezillon 	bam_txn = bam_txn_buf;
59493db446aSBoris Brezillon 	bam_txn_buf += sizeof(*bam_txn);
59593db446aSBoris Brezillon 
59693db446aSBoris Brezillon 	bam_txn->bam_ce = bam_txn_buf;
59793db446aSBoris Brezillon 	bam_txn_buf +=
59893db446aSBoris Brezillon 		sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
59993db446aSBoris Brezillon 
60093db446aSBoris Brezillon 	bam_txn->cmd_sgl = bam_txn_buf;
60193db446aSBoris Brezillon 	bam_txn_buf +=
60293db446aSBoris Brezillon 		sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
60393db446aSBoris Brezillon 
60493db446aSBoris Brezillon 	bam_txn->data_sgl = bam_txn_buf;
60593db446aSBoris Brezillon 
6066f20070dSAbhishek Sahu 	init_completion(&bam_txn->txn_done);
6076f20070dSAbhishek Sahu 
60893db446aSBoris Brezillon 	return bam_txn;
60993db446aSBoris Brezillon }
61093db446aSBoris Brezillon 
61193db446aSBoris Brezillon /* Clears the BAM transaction indexes */
clear_bam_transaction(struct qcom_nand_controller * nandc)61293db446aSBoris Brezillon static void clear_bam_transaction(struct qcom_nand_controller *nandc)
61393db446aSBoris Brezillon {
61493db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
61593db446aSBoris Brezillon 
61693db446aSBoris Brezillon 	if (!nandc->props->is_bam)
61793db446aSBoris Brezillon 		return;
61893db446aSBoris Brezillon 
61993db446aSBoris Brezillon 	bam_txn->bam_ce_pos = 0;
62093db446aSBoris Brezillon 	bam_txn->bam_ce_start = 0;
62193db446aSBoris Brezillon 	bam_txn->cmd_sgl_pos = 0;
62293db446aSBoris Brezillon 	bam_txn->cmd_sgl_start = 0;
62393db446aSBoris Brezillon 	bam_txn->tx_sgl_pos = 0;
62493db446aSBoris Brezillon 	bam_txn->tx_sgl_start = 0;
62593db446aSBoris Brezillon 	bam_txn->rx_sgl_pos = 0;
62693db446aSBoris Brezillon 	bam_txn->rx_sgl_start = 0;
6276f20070dSAbhishek Sahu 	bam_txn->last_data_desc = NULL;
6286f20070dSAbhishek Sahu 	bam_txn->wait_second_completion = false;
62993db446aSBoris Brezillon 
63093db446aSBoris Brezillon 	sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
63193db446aSBoris Brezillon 		      QPIC_PER_CW_CMD_SGL);
63293db446aSBoris Brezillon 	sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
63393db446aSBoris Brezillon 		      QPIC_PER_CW_DATA_SGL);
6346f20070dSAbhishek Sahu 
6356f20070dSAbhishek Sahu 	reinit_completion(&bam_txn->txn_done);
6366f20070dSAbhishek Sahu }
6376f20070dSAbhishek Sahu 
6386f20070dSAbhishek Sahu /* Callback for DMA descriptor completion */
qpic_bam_dma_done(void * data)6396f20070dSAbhishek Sahu static void qpic_bam_dma_done(void *data)
6406f20070dSAbhishek Sahu {
6416f20070dSAbhishek Sahu 	struct bam_transaction *bam_txn = data;
6426f20070dSAbhishek Sahu 
6436f20070dSAbhishek Sahu 	/*
6446f20070dSAbhishek Sahu 	 * In case of data transfer with NAND, 2 callbacks will be generated.
6456f20070dSAbhishek Sahu 	 * One for command channel and another one for data channel.
6466f20070dSAbhishek Sahu 	 * If current transaction has data descriptors
6476f20070dSAbhishek Sahu 	 * (i.e. wait_second_completion is true), then set this to false
6486f20070dSAbhishek Sahu 	 * and wait for second DMA descriptor completion.
6496f20070dSAbhishek Sahu 	 */
6506f20070dSAbhishek Sahu 	if (bam_txn->wait_second_completion)
6516f20070dSAbhishek Sahu 		bam_txn->wait_second_completion = false;
6526f20070dSAbhishek Sahu 	else
6536f20070dSAbhishek Sahu 		complete(&bam_txn->txn_done);
65493db446aSBoris Brezillon }
65593db446aSBoris Brezillon 
to_qcom_nand_host(struct nand_chip * chip)65693db446aSBoris Brezillon static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
65793db446aSBoris Brezillon {
65893db446aSBoris Brezillon 	return container_of(chip, struct qcom_nand_host, chip);
65993db446aSBoris Brezillon }
66093db446aSBoris Brezillon 
66193db446aSBoris Brezillon static inline struct qcom_nand_controller *
get_qcom_nand_controller(struct nand_chip * chip)66293db446aSBoris Brezillon get_qcom_nand_controller(struct nand_chip *chip)
66393db446aSBoris Brezillon {
66493db446aSBoris Brezillon 	return container_of(chip->controller, struct qcom_nand_controller,
66593db446aSBoris Brezillon 			    controller);
66693db446aSBoris Brezillon }
66793db446aSBoris Brezillon 
nandc_read(struct qcom_nand_controller * nandc,int offset)66893db446aSBoris Brezillon static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
66993db446aSBoris Brezillon {
67093db446aSBoris Brezillon 	return ioread32(nandc->base + offset);
67193db446aSBoris Brezillon }
67293db446aSBoris Brezillon 
nandc_write(struct qcom_nand_controller * nandc,int offset,u32 val)67393db446aSBoris Brezillon static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
67493db446aSBoris Brezillon 			       u32 val)
67593db446aSBoris Brezillon {
67693db446aSBoris Brezillon 	iowrite32(val, nandc->base + offset);
67793db446aSBoris Brezillon }
67893db446aSBoris Brezillon 
nandc_read_buffer_sync(struct qcom_nand_controller * nandc,bool is_cpu)67993db446aSBoris Brezillon static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
68093db446aSBoris Brezillon 					  bool is_cpu)
68193db446aSBoris Brezillon {
68293db446aSBoris Brezillon 	if (!nandc->props->is_bam)
68393db446aSBoris Brezillon 		return;
68493db446aSBoris Brezillon 
68593db446aSBoris Brezillon 	if (is_cpu)
68693db446aSBoris Brezillon 		dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
68793db446aSBoris Brezillon 					MAX_REG_RD *
68893db446aSBoris Brezillon 					sizeof(*nandc->reg_read_buf),
68993db446aSBoris Brezillon 					DMA_FROM_DEVICE);
69093db446aSBoris Brezillon 	else
69193db446aSBoris Brezillon 		dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
69293db446aSBoris Brezillon 					   MAX_REG_RD *
69393db446aSBoris Brezillon 					   sizeof(*nandc->reg_read_buf),
69493db446aSBoris Brezillon 					   DMA_FROM_DEVICE);
69593db446aSBoris Brezillon }
69693db446aSBoris Brezillon 
offset_to_nandc_reg(struct nandc_regs * regs,int offset)69793db446aSBoris Brezillon static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
69893db446aSBoris Brezillon {
69993db446aSBoris Brezillon 	switch (offset) {
70093db446aSBoris Brezillon 	case NAND_FLASH_CMD:
70193db446aSBoris Brezillon 		return &regs->cmd;
70293db446aSBoris Brezillon 	case NAND_ADDR0:
70393db446aSBoris Brezillon 		return &regs->addr0;
70493db446aSBoris Brezillon 	case NAND_ADDR1:
70593db446aSBoris Brezillon 		return &regs->addr1;
70693db446aSBoris Brezillon 	case NAND_FLASH_CHIP_SELECT:
70793db446aSBoris Brezillon 		return &regs->chip_sel;
70893db446aSBoris Brezillon 	case NAND_EXEC_CMD:
70993db446aSBoris Brezillon 		return &regs->exec;
71093db446aSBoris Brezillon 	case NAND_FLASH_STATUS:
71193db446aSBoris Brezillon 		return &regs->clrflashstatus;
71293db446aSBoris Brezillon 	case NAND_DEV0_CFG0:
71393db446aSBoris Brezillon 		return &regs->cfg0;
71493db446aSBoris Brezillon 	case NAND_DEV0_CFG1:
71593db446aSBoris Brezillon 		return &regs->cfg1;
71693db446aSBoris Brezillon 	case NAND_DEV0_ECC_CFG:
71793db446aSBoris Brezillon 		return &regs->ecc_bch_cfg;
71893db446aSBoris Brezillon 	case NAND_READ_STATUS:
71993db446aSBoris Brezillon 		return &regs->clrreadstatus;
72093db446aSBoris Brezillon 	case NAND_DEV_CMD1:
72193db446aSBoris Brezillon 		return &regs->cmd1;
72293db446aSBoris Brezillon 	case NAND_DEV_CMD1_RESTORE:
72393db446aSBoris Brezillon 		return &regs->orig_cmd1;
72493db446aSBoris Brezillon 	case NAND_DEV_CMD_VLD:
72593db446aSBoris Brezillon 		return &regs->vld;
72693db446aSBoris Brezillon 	case NAND_DEV_CMD_VLD_RESTORE:
72793db446aSBoris Brezillon 		return &regs->orig_vld;
72893db446aSBoris Brezillon 	case NAND_EBI2_ECC_BUF_CFG:
72993db446aSBoris Brezillon 		return &regs->ecc_buf_cfg;
73093db446aSBoris Brezillon 	case NAND_READ_LOCATION_0:
73193db446aSBoris Brezillon 		return &regs->read_location0;
73293db446aSBoris Brezillon 	case NAND_READ_LOCATION_1:
73393db446aSBoris Brezillon 		return &regs->read_location1;
73493db446aSBoris Brezillon 	case NAND_READ_LOCATION_2:
73593db446aSBoris Brezillon 		return &regs->read_location2;
73693db446aSBoris Brezillon 	case NAND_READ_LOCATION_3:
73793db446aSBoris Brezillon 		return &regs->read_location3;
738503ee5aaSMd Sadre Alam 	case NAND_READ_LOCATION_LAST_CW_0:
739503ee5aaSMd Sadre Alam 		return &regs->read_location_last0;
740503ee5aaSMd Sadre Alam 	case NAND_READ_LOCATION_LAST_CW_1:
741503ee5aaSMd Sadre Alam 		return &regs->read_location_last1;
742503ee5aaSMd Sadre Alam 	case NAND_READ_LOCATION_LAST_CW_2:
743503ee5aaSMd Sadre Alam 		return &regs->read_location_last2;
744503ee5aaSMd Sadre Alam 	case NAND_READ_LOCATION_LAST_CW_3:
745503ee5aaSMd Sadre Alam 		return &regs->read_location_last3;
74693db446aSBoris Brezillon 	default:
74793db446aSBoris Brezillon 		return NULL;
74893db446aSBoris Brezillon 	}
74993db446aSBoris Brezillon }
75093db446aSBoris Brezillon 
nandc_set_reg(struct nand_chip * chip,int offset,u32 val)7519a7c39e2SMd Sadre Alam static void nandc_set_reg(struct nand_chip *chip, int offset,
75293db446aSBoris Brezillon 			  u32 val)
75393db446aSBoris Brezillon {
7549a7c39e2SMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
75593db446aSBoris Brezillon 	struct nandc_regs *regs = nandc->regs;
75693db446aSBoris Brezillon 	__le32 *reg;
75793db446aSBoris Brezillon 
75893db446aSBoris Brezillon 	reg = offset_to_nandc_reg(regs, offset);
75993db446aSBoris Brezillon 
76093db446aSBoris Brezillon 	if (reg)
76193db446aSBoris Brezillon 		*reg = cpu_to_le32(val);
76293db446aSBoris Brezillon }
76393db446aSBoris Brezillon 
764b057e498SMd Sadre Alam /* Helper to check the code word, whether it is last cw or not */
qcom_nandc_is_last_cw(struct nand_ecc_ctrl * ecc,int cw)765b057e498SMd Sadre Alam static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
766b057e498SMd Sadre Alam {
767b057e498SMd Sadre Alam 	return cw == (ecc->steps - 1);
768b057e498SMd Sadre Alam }
769b057e498SMd Sadre Alam 
770e7a307f2SMd Sadre Alam /* helper to configure location register values */
nandc_set_read_loc(struct nand_chip * chip,int cw,int reg,int cw_offset,int read_size,int is_last_read_loc)771e7a307f2SMd Sadre Alam static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
772e7a307f2SMd Sadre Alam 			       int cw_offset, int read_size, int is_last_read_loc)
773e7a307f2SMd Sadre Alam {
774503ee5aaSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
775503ee5aaSMd Sadre Alam 	struct nand_ecc_ctrl *ecc = &chip->ecc;
776e7a307f2SMd Sadre Alam 	int reg_base = NAND_READ_LOCATION_0;
777e7a307f2SMd Sadre Alam 
778503ee5aaSMd Sadre Alam 	if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
779503ee5aaSMd Sadre Alam 		reg_base = NAND_READ_LOCATION_LAST_CW_0;
780503ee5aaSMd Sadre Alam 
781e7a307f2SMd Sadre Alam 	reg_base += reg * 4;
782e7a307f2SMd Sadre Alam 
783503ee5aaSMd Sadre Alam 	if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
784503ee5aaSMd Sadre Alam 		return nandc_set_read_loc_last(chip, reg_base, cw_offset,
785503ee5aaSMd Sadre Alam 				read_size, is_last_read_loc);
786503ee5aaSMd Sadre Alam 	else
787e7a307f2SMd Sadre Alam 		return nandc_set_read_loc_first(chip, reg_base, cw_offset,
788e7a307f2SMd Sadre Alam 				read_size, is_last_read_loc);
789e7a307f2SMd Sadre Alam }
790e7a307f2SMd Sadre Alam 
79193db446aSBoris Brezillon /* helper to configure address register values */
set_address(struct qcom_nand_host * host,u16 column,int page)79293db446aSBoris Brezillon static void set_address(struct qcom_nand_host *host, u16 column, int page)
79393db446aSBoris Brezillon {
79493db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
79593db446aSBoris Brezillon 
79693db446aSBoris Brezillon 	if (chip->options & NAND_BUSWIDTH_16)
79793db446aSBoris Brezillon 		column >>= 1;
79893db446aSBoris Brezillon 
7999a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR0, page << 16 | column);
8009a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff);
80193db446aSBoris Brezillon }
80293db446aSBoris Brezillon 
80393db446aSBoris Brezillon /*
80493db446aSBoris Brezillon  * update_rw_regs:	set up read/write register values, these will be
80593db446aSBoris Brezillon  *			written to the NAND controller registers via DMA
80693db446aSBoris Brezillon  *
80793db446aSBoris Brezillon  * @num_cw:		number of steps for the read/write operation
80893db446aSBoris Brezillon  * @read:		read or write operation
809503ee5aaSMd Sadre Alam  * @cw	:		which code word
81093db446aSBoris Brezillon  */
update_rw_regs(struct qcom_nand_host * host,int num_cw,bool read,int cw)811503ee5aaSMd Sadre Alam static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
81293db446aSBoris Brezillon {
81393db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
81493db446aSBoris Brezillon 	u32 cmd, cfg0, cfg1, ecc_bch_cfg;
815bfb34eceSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
81693db446aSBoris Brezillon 
81793db446aSBoris Brezillon 	if (read) {
81893db446aSBoris Brezillon 		if (host->use_ecc)
81933bf5519SOlof Johansson 			cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
82093db446aSBoris Brezillon 		else
82133bf5519SOlof Johansson 			cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE;
82293db446aSBoris Brezillon 	} else {
82333bf5519SOlof Johansson 		cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
82493db446aSBoris Brezillon 	}
82593db446aSBoris Brezillon 
82693db446aSBoris Brezillon 	if (host->use_ecc) {
82793db446aSBoris Brezillon 		cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
82893db446aSBoris Brezillon 				(num_cw - 1) << CW_PER_PAGE;
82993db446aSBoris Brezillon 
83093db446aSBoris Brezillon 		cfg1 = host->cfg1;
83193db446aSBoris Brezillon 		ecc_bch_cfg = host->ecc_bch_cfg;
83293db446aSBoris Brezillon 	} else {
83393db446aSBoris Brezillon 		cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
83493db446aSBoris Brezillon 				(num_cw - 1) << CW_PER_PAGE;
83593db446aSBoris Brezillon 
83693db446aSBoris Brezillon 		cfg1 = host->cfg1_raw;
83793db446aSBoris Brezillon 		ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
83893db446aSBoris Brezillon 	}
83993db446aSBoris Brezillon 
8409a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
8419a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
8429a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
8439a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
844bfb34eceSMd Sadre Alam 	if (!nandc->props->qpic_v2)
8459a7c39e2SMd Sadre Alam 		nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
8469a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
8479a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
8489a7c39e2SMd Sadre Alam 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
84993db446aSBoris Brezillon 
85093db446aSBoris Brezillon 	if (read)
851503ee5aaSMd Sadre Alam 		nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ?
85293db446aSBoris Brezillon 				   host->cw_data : host->cw_size, 1);
85393db446aSBoris Brezillon }
85493db446aSBoris Brezillon 
85593db446aSBoris Brezillon /*
85693db446aSBoris Brezillon  * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
85793db446aSBoris Brezillon  * for BAM. This descriptor will be added in the NAND DMA descriptor queue
85893db446aSBoris Brezillon  * which will be submitted to DMA engine.
85993db446aSBoris Brezillon  */
prepare_bam_async_desc(struct qcom_nand_controller * nandc,struct dma_chan * chan,unsigned long flags)86093db446aSBoris Brezillon static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
86193db446aSBoris Brezillon 				  struct dma_chan *chan,
86293db446aSBoris Brezillon 				  unsigned long flags)
86393db446aSBoris Brezillon {
86493db446aSBoris Brezillon 	struct desc_info *desc;
86593db446aSBoris Brezillon 	struct scatterlist *sgl;
86693db446aSBoris Brezillon 	unsigned int sgl_cnt;
86793db446aSBoris Brezillon 	int ret;
86893db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
86993db446aSBoris Brezillon 	enum dma_transfer_direction dir_eng;
87093db446aSBoris Brezillon 	struct dma_async_tx_descriptor *dma_desc;
87193db446aSBoris Brezillon 
87293db446aSBoris Brezillon 	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
87393db446aSBoris Brezillon 	if (!desc)
87493db446aSBoris Brezillon 		return -ENOMEM;
87593db446aSBoris Brezillon 
87693db446aSBoris Brezillon 	if (chan == nandc->cmd_chan) {
87793db446aSBoris Brezillon 		sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
87893db446aSBoris Brezillon 		sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
87993db446aSBoris Brezillon 		bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
88093db446aSBoris Brezillon 		dir_eng = DMA_MEM_TO_DEV;
88193db446aSBoris Brezillon 		desc->dir = DMA_TO_DEVICE;
88293db446aSBoris Brezillon 	} else if (chan == nandc->tx_chan) {
88393db446aSBoris Brezillon 		sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
88493db446aSBoris Brezillon 		sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
88593db446aSBoris Brezillon 		bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
88693db446aSBoris Brezillon 		dir_eng = DMA_MEM_TO_DEV;
88793db446aSBoris Brezillon 		desc->dir = DMA_TO_DEVICE;
88893db446aSBoris Brezillon 	} else {
88993db446aSBoris Brezillon 		sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
89093db446aSBoris Brezillon 		sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
89193db446aSBoris Brezillon 		bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
89293db446aSBoris Brezillon 		dir_eng = DMA_DEV_TO_MEM;
89393db446aSBoris Brezillon 		desc->dir = DMA_FROM_DEVICE;
89493db446aSBoris Brezillon 	}
89593db446aSBoris Brezillon 
89693db446aSBoris Brezillon 	sg_mark_end(sgl + sgl_cnt - 1);
89793db446aSBoris Brezillon 	ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
89893db446aSBoris Brezillon 	if (ret == 0) {
89993db446aSBoris Brezillon 		dev_err(nandc->dev, "failure in mapping desc\n");
90093db446aSBoris Brezillon 		kfree(desc);
90193db446aSBoris Brezillon 		return -ENOMEM;
90293db446aSBoris Brezillon 	}
90393db446aSBoris Brezillon 
90493db446aSBoris Brezillon 	desc->sgl_cnt = sgl_cnt;
90593db446aSBoris Brezillon 	desc->bam_sgl = sgl;
90693db446aSBoris Brezillon 
90793db446aSBoris Brezillon 	dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
90893db446aSBoris Brezillon 					   flags);
90993db446aSBoris Brezillon 
91093db446aSBoris Brezillon 	if (!dma_desc) {
91193db446aSBoris Brezillon 		dev_err(nandc->dev, "failure in prep desc\n");
91293db446aSBoris Brezillon 		dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
91393db446aSBoris Brezillon 		kfree(desc);
91493db446aSBoris Brezillon 		return -EINVAL;
91593db446aSBoris Brezillon 	}
91693db446aSBoris Brezillon 
91793db446aSBoris Brezillon 	desc->dma_desc = dma_desc;
91893db446aSBoris Brezillon 
9196f20070dSAbhishek Sahu 	/* update last data/command descriptor */
9206f20070dSAbhishek Sahu 	if (chan == nandc->cmd_chan)
9216f20070dSAbhishek Sahu 		bam_txn->last_cmd_desc = dma_desc;
9226f20070dSAbhishek Sahu 	else
9236f20070dSAbhishek Sahu 		bam_txn->last_data_desc = dma_desc;
9246f20070dSAbhishek Sahu 
92593db446aSBoris Brezillon 	list_add_tail(&desc->node, &nandc->desc_list);
92693db446aSBoris Brezillon 
92793db446aSBoris Brezillon 	return 0;
92893db446aSBoris Brezillon }
92993db446aSBoris Brezillon 
93093db446aSBoris Brezillon /*
93193db446aSBoris Brezillon  * Prepares the command descriptor for BAM DMA which will be used for NAND
93293db446aSBoris Brezillon  * register reads and writes. The command descriptor requires the command
93393db446aSBoris Brezillon  * to be formed in command element type so this function uses the command
93493db446aSBoris Brezillon  * element from bam transaction ce array and fills the same with required
93593db446aSBoris Brezillon  * data. A single SGL can contain multiple command elements so
93693db446aSBoris Brezillon  * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
93793db446aSBoris Brezillon  * after the current command element.
93893db446aSBoris Brezillon  */
prep_bam_dma_desc_cmd(struct qcom_nand_controller * nandc,bool read,int reg_off,const void * vaddr,int size,unsigned int flags)93993db446aSBoris Brezillon static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
94093db446aSBoris Brezillon 				 int reg_off, const void *vaddr,
94193db446aSBoris Brezillon 				 int size, unsigned int flags)
94293db446aSBoris Brezillon {
94393db446aSBoris Brezillon 	int bam_ce_size;
94493db446aSBoris Brezillon 	int i, ret;
94593db446aSBoris Brezillon 	struct bam_cmd_element *bam_ce_buffer;
94693db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
94793db446aSBoris Brezillon 
94893db446aSBoris Brezillon 	bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
94993db446aSBoris Brezillon 
95093db446aSBoris Brezillon 	/* fill the command desc */
95193db446aSBoris Brezillon 	for (i = 0; i < size; i++) {
95293db446aSBoris Brezillon 		if (read)
95393db446aSBoris Brezillon 			bam_prep_ce(&bam_ce_buffer[i],
95493db446aSBoris Brezillon 				    nandc_reg_phys(nandc, reg_off + 4 * i),
95593db446aSBoris Brezillon 				    BAM_READ_COMMAND,
95693db446aSBoris Brezillon 				    reg_buf_dma_addr(nandc,
95793db446aSBoris Brezillon 						     (__le32 *)vaddr + i));
95893db446aSBoris Brezillon 		else
95993db446aSBoris Brezillon 			bam_prep_ce_le32(&bam_ce_buffer[i],
96093db446aSBoris Brezillon 					 nandc_reg_phys(nandc, reg_off + 4 * i),
96193db446aSBoris Brezillon 					 BAM_WRITE_COMMAND,
96293db446aSBoris Brezillon 					 *((__le32 *)vaddr + i));
96393db446aSBoris Brezillon 	}
96493db446aSBoris Brezillon 
96593db446aSBoris Brezillon 	bam_txn->bam_ce_pos += size;
96693db446aSBoris Brezillon 
96793db446aSBoris Brezillon 	/* use the separate sgl after this command */
96893db446aSBoris Brezillon 	if (flags & NAND_BAM_NEXT_SGL) {
96993db446aSBoris Brezillon 		bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
97093db446aSBoris Brezillon 		bam_ce_size = (bam_txn->bam_ce_pos -
97193db446aSBoris Brezillon 				bam_txn->bam_ce_start) *
97293db446aSBoris Brezillon 				sizeof(struct bam_cmd_element);
97393db446aSBoris Brezillon 		sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
97493db446aSBoris Brezillon 			   bam_ce_buffer, bam_ce_size);
97593db446aSBoris Brezillon 		bam_txn->cmd_sgl_pos++;
97693db446aSBoris Brezillon 		bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
97793db446aSBoris Brezillon 
97893db446aSBoris Brezillon 		if (flags & NAND_BAM_NWD) {
97993db446aSBoris Brezillon 			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
98093db446aSBoris Brezillon 						     DMA_PREP_FENCE |
98193db446aSBoris Brezillon 						     DMA_PREP_CMD);
98293db446aSBoris Brezillon 			if (ret)
98393db446aSBoris Brezillon 				return ret;
98493db446aSBoris Brezillon 		}
98593db446aSBoris Brezillon 	}
98693db446aSBoris Brezillon 
98793db446aSBoris Brezillon 	return 0;
98893db446aSBoris Brezillon }
98993db446aSBoris Brezillon 
99093db446aSBoris Brezillon /*
99193db446aSBoris Brezillon  * Prepares the data descriptor for BAM DMA which will be used for NAND
99293db446aSBoris Brezillon  * data reads and writes.
99393db446aSBoris Brezillon  */
prep_bam_dma_desc_data(struct qcom_nand_controller * nandc,bool read,const void * vaddr,int size,unsigned int flags)99493db446aSBoris Brezillon static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
99593db446aSBoris Brezillon 				  const void *vaddr,
99693db446aSBoris Brezillon 				  int size, unsigned int flags)
99793db446aSBoris Brezillon {
99893db446aSBoris Brezillon 	int ret;
99993db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
100093db446aSBoris Brezillon 
100193db446aSBoris Brezillon 	if (read) {
100293db446aSBoris Brezillon 		sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
100393db446aSBoris Brezillon 			   vaddr, size);
100493db446aSBoris Brezillon 		bam_txn->rx_sgl_pos++;
100593db446aSBoris Brezillon 	} else {
100693db446aSBoris Brezillon 		sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
100793db446aSBoris Brezillon 			   vaddr, size);
100893db446aSBoris Brezillon 		bam_txn->tx_sgl_pos++;
100993db446aSBoris Brezillon 
101093db446aSBoris Brezillon 		/*
101193db446aSBoris Brezillon 		 * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
101293db446aSBoris Brezillon 		 * is not set, form the DMA descriptor
101393db446aSBoris Brezillon 		 */
101493db446aSBoris Brezillon 		if (!(flags & NAND_BAM_NO_EOT)) {
101593db446aSBoris Brezillon 			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
101693db446aSBoris Brezillon 						     DMA_PREP_INTERRUPT);
101793db446aSBoris Brezillon 			if (ret)
101893db446aSBoris Brezillon 				return ret;
101993db446aSBoris Brezillon 		}
102093db446aSBoris Brezillon 	}
102193db446aSBoris Brezillon 
102293db446aSBoris Brezillon 	return 0;
102393db446aSBoris Brezillon }
102493db446aSBoris Brezillon 
prep_adm_dma_desc(struct qcom_nand_controller * nandc,bool read,int reg_off,const void * vaddr,int size,bool flow_control)102593db446aSBoris Brezillon static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
102693db446aSBoris Brezillon 			     int reg_off, const void *vaddr, int size,
102793db446aSBoris Brezillon 			     bool flow_control)
102893db446aSBoris Brezillon {
102993db446aSBoris Brezillon 	struct desc_info *desc;
103093db446aSBoris Brezillon 	struct dma_async_tx_descriptor *dma_desc;
103193db446aSBoris Brezillon 	struct scatterlist *sgl;
103293db446aSBoris Brezillon 	struct dma_slave_config slave_conf;
103303de6b27SArnd Bergmann 	struct qcom_adm_peripheral_config periph_conf = {};
103493db446aSBoris Brezillon 	enum dma_transfer_direction dir_eng;
103593db446aSBoris Brezillon 	int ret;
103693db446aSBoris Brezillon 
103793db446aSBoris Brezillon 	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
103893db446aSBoris Brezillon 	if (!desc)
103993db446aSBoris Brezillon 		return -ENOMEM;
104093db446aSBoris Brezillon 
104193db446aSBoris Brezillon 	sgl = &desc->adm_sgl;
104293db446aSBoris Brezillon 
104393db446aSBoris Brezillon 	sg_init_one(sgl, vaddr, size);
104493db446aSBoris Brezillon 
104593db446aSBoris Brezillon 	if (read) {
104693db446aSBoris Brezillon 		dir_eng = DMA_DEV_TO_MEM;
104793db446aSBoris Brezillon 		desc->dir = DMA_FROM_DEVICE;
104893db446aSBoris Brezillon 	} else {
104993db446aSBoris Brezillon 		dir_eng = DMA_MEM_TO_DEV;
105093db446aSBoris Brezillon 		desc->dir = DMA_TO_DEVICE;
105193db446aSBoris Brezillon 	}
105293db446aSBoris Brezillon 
105393db446aSBoris Brezillon 	ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
105493db446aSBoris Brezillon 	if (ret == 0) {
105593db446aSBoris Brezillon 		ret = -ENOMEM;
105693db446aSBoris Brezillon 		goto err;
105793db446aSBoris Brezillon 	}
105893db446aSBoris Brezillon 
105993db446aSBoris Brezillon 	memset(&slave_conf, 0x00, sizeof(slave_conf));
106093db446aSBoris Brezillon 
106193db446aSBoris Brezillon 	slave_conf.device_fc = flow_control;
106293db446aSBoris Brezillon 	if (read) {
106393db446aSBoris Brezillon 		slave_conf.src_maxburst = 16;
106493db446aSBoris Brezillon 		slave_conf.src_addr = nandc->base_dma + reg_off;
106503de6b27SArnd Bergmann 		if (nandc->data_crci) {
106603de6b27SArnd Bergmann 			periph_conf.crci = nandc->data_crci;
106703de6b27SArnd Bergmann 			slave_conf.peripheral_config = &periph_conf;
106803de6b27SArnd Bergmann 			slave_conf.peripheral_size = sizeof(periph_conf);
106903de6b27SArnd Bergmann 		}
107093db446aSBoris Brezillon 	} else {
107193db446aSBoris Brezillon 		slave_conf.dst_maxburst = 16;
107293db446aSBoris Brezillon 		slave_conf.dst_addr = nandc->base_dma + reg_off;
107303de6b27SArnd Bergmann 		if (nandc->cmd_crci) {
107403de6b27SArnd Bergmann 			periph_conf.crci = nandc->cmd_crci;
107503de6b27SArnd Bergmann 			slave_conf.peripheral_config = &periph_conf;
107603de6b27SArnd Bergmann 			slave_conf.peripheral_size = sizeof(periph_conf);
107703de6b27SArnd Bergmann 		}
107893db446aSBoris Brezillon 	}
107993db446aSBoris Brezillon 
108093db446aSBoris Brezillon 	ret = dmaengine_slave_config(nandc->chan, &slave_conf);
108193db446aSBoris Brezillon 	if (ret) {
108293db446aSBoris Brezillon 		dev_err(nandc->dev, "failed to configure dma channel\n");
108393db446aSBoris Brezillon 		goto err;
108493db446aSBoris Brezillon 	}
108593db446aSBoris Brezillon 
108693db446aSBoris Brezillon 	dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
108793db446aSBoris Brezillon 	if (!dma_desc) {
108893db446aSBoris Brezillon 		dev_err(nandc->dev, "failed to prepare desc\n");
108993db446aSBoris Brezillon 		ret = -EINVAL;
109093db446aSBoris Brezillon 		goto err;
109193db446aSBoris Brezillon 	}
109293db446aSBoris Brezillon 
109393db446aSBoris Brezillon 	desc->dma_desc = dma_desc;
109493db446aSBoris Brezillon 
109593db446aSBoris Brezillon 	list_add_tail(&desc->node, &nandc->desc_list);
109693db446aSBoris Brezillon 
109793db446aSBoris Brezillon 	return 0;
109893db446aSBoris Brezillon err:
109993db446aSBoris Brezillon 	kfree(desc);
110093db446aSBoris Brezillon 
110193db446aSBoris Brezillon 	return ret;
110293db446aSBoris Brezillon }
110393db446aSBoris Brezillon 
110493db446aSBoris Brezillon /*
110593db446aSBoris Brezillon  * read_reg_dma:	prepares a descriptor to read a given number of
110693db446aSBoris Brezillon  *			contiguous registers to the reg_read_buf pointer
110793db446aSBoris Brezillon  *
110893db446aSBoris Brezillon  * @first:		offset of the first register in the contiguous block
110993db446aSBoris Brezillon  * @num_regs:		number of registers to read
111093db446aSBoris Brezillon  * @flags:		flags to control DMA descriptor preparation
111193db446aSBoris Brezillon  */
read_reg_dma(struct qcom_nand_controller * nandc,int first,int num_regs,unsigned int flags)111293db446aSBoris Brezillon static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
111393db446aSBoris Brezillon 			int num_regs, unsigned int flags)
111493db446aSBoris Brezillon {
111593db446aSBoris Brezillon 	bool flow_control = false;
111693db446aSBoris Brezillon 	void *vaddr;
111793db446aSBoris Brezillon 
111893db446aSBoris Brezillon 	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
111993db446aSBoris Brezillon 	nandc->reg_read_pos += num_regs;
112093db446aSBoris Brezillon 
112193db446aSBoris Brezillon 	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
112293db446aSBoris Brezillon 		first = dev_cmd_reg_addr(nandc, first);
112393db446aSBoris Brezillon 
112493db446aSBoris Brezillon 	if (nandc->props->is_bam)
112593db446aSBoris Brezillon 		return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
112693db446aSBoris Brezillon 					     num_regs, flags);
112793db446aSBoris Brezillon 
112893db446aSBoris Brezillon 	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
112993db446aSBoris Brezillon 		flow_control = true;
113093db446aSBoris Brezillon 
113193db446aSBoris Brezillon 	return prep_adm_dma_desc(nandc, true, first, vaddr,
113293db446aSBoris Brezillon 				 num_regs * sizeof(u32), flow_control);
113393db446aSBoris Brezillon }
113493db446aSBoris Brezillon 
113593db446aSBoris Brezillon /*
113693db446aSBoris Brezillon  * write_reg_dma:	prepares a descriptor to write a given number of
113793db446aSBoris Brezillon  *			contiguous registers
113893db446aSBoris Brezillon  *
113993db446aSBoris Brezillon  * @first:		offset of the first register in the contiguous block
114093db446aSBoris Brezillon  * @num_regs:		number of registers to write
114193db446aSBoris Brezillon  * @flags:		flags to control DMA descriptor preparation
114293db446aSBoris Brezillon  */
write_reg_dma(struct qcom_nand_controller * nandc,int first,int num_regs,unsigned int flags)114393db446aSBoris Brezillon static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
114493db446aSBoris Brezillon 			 int num_regs, unsigned int flags)
114593db446aSBoris Brezillon {
114693db446aSBoris Brezillon 	bool flow_control = false;
114793db446aSBoris Brezillon 	struct nandc_regs *regs = nandc->regs;
114893db446aSBoris Brezillon 	void *vaddr;
114993db446aSBoris Brezillon 
115093db446aSBoris Brezillon 	vaddr = offset_to_nandc_reg(regs, first);
115193db446aSBoris Brezillon 
115293db446aSBoris Brezillon 	if (first == NAND_ERASED_CW_DETECT_CFG) {
115393db446aSBoris Brezillon 		if (flags & NAND_ERASED_CW_SET)
115493db446aSBoris Brezillon 			vaddr = &regs->erased_cw_detect_cfg_set;
115593db446aSBoris Brezillon 		else
115693db446aSBoris Brezillon 			vaddr = &regs->erased_cw_detect_cfg_clr;
115793db446aSBoris Brezillon 	}
115893db446aSBoris Brezillon 
115993db446aSBoris Brezillon 	if (first == NAND_EXEC_CMD)
116093db446aSBoris Brezillon 		flags |= NAND_BAM_NWD;
116193db446aSBoris Brezillon 
116293db446aSBoris Brezillon 	if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
116393db446aSBoris Brezillon 		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
116493db446aSBoris Brezillon 
116593db446aSBoris Brezillon 	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
116693db446aSBoris Brezillon 		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
116793db446aSBoris Brezillon 
116893db446aSBoris Brezillon 	if (nandc->props->is_bam)
116993db446aSBoris Brezillon 		return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
117093db446aSBoris Brezillon 					     num_regs, flags);
117193db446aSBoris Brezillon 
117293db446aSBoris Brezillon 	if (first == NAND_FLASH_CMD)
117393db446aSBoris Brezillon 		flow_control = true;
117493db446aSBoris Brezillon 
117593db446aSBoris Brezillon 	return prep_adm_dma_desc(nandc, false, first, vaddr,
117693db446aSBoris Brezillon 				 num_regs * sizeof(u32), flow_control);
117793db446aSBoris Brezillon }
117893db446aSBoris Brezillon 
117993db446aSBoris Brezillon /*
118093db446aSBoris Brezillon  * read_data_dma:	prepares a DMA descriptor to transfer data from the
118193db446aSBoris Brezillon  *			controller's internal buffer to the buffer 'vaddr'
118293db446aSBoris Brezillon  *
118393db446aSBoris Brezillon  * @reg_off:		offset within the controller's data buffer
118493db446aSBoris Brezillon  * @vaddr:		virtual address of the buffer we want to write to
118593db446aSBoris Brezillon  * @size:		DMA transaction size in bytes
118693db446aSBoris Brezillon  * @flags:		flags to control DMA descriptor preparation
118793db446aSBoris Brezillon  */
read_data_dma(struct qcom_nand_controller * nandc,int reg_off,const u8 * vaddr,int size,unsigned int flags)118893db446aSBoris Brezillon static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
118993db446aSBoris Brezillon 			 const u8 *vaddr, int size, unsigned int flags)
119093db446aSBoris Brezillon {
119193db446aSBoris Brezillon 	if (nandc->props->is_bam)
119293db446aSBoris Brezillon 		return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
119393db446aSBoris Brezillon 
119493db446aSBoris Brezillon 	return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
119593db446aSBoris Brezillon }
119693db446aSBoris Brezillon 
119793db446aSBoris Brezillon /*
119893db446aSBoris Brezillon  * write_data_dma:	prepares a DMA descriptor to transfer data from
119993db446aSBoris Brezillon  *			'vaddr' to the controller's internal buffer
120093db446aSBoris Brezillon  *
120193db446aSBoris Brezillon  * @reg_off:		offset within the controller's data buffer
120293db446aSBoris Brezillon  * @vaddr:		virtual address of the buffer we want to read from
120393db446aSBoris Brezillon  * @size:		DMA transaction size in bytes
120493db446aSBoris Brezillon  * @flags:		flags to control DMA descriptor preparation
120593db446aSBoris Brezillon  */
write_data_dma(struct qcom_nand_controller * nandc,int reg_off,const u8 * vaddr,int size,unsigned int flags)120693db446aSBoris Brezillon static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
120793db446aSBoris Brezillon 			  const u8 *vaddr, int size, unsigned int flags)
120893db446aSBoris Brezillon {
120993db446aSBoris Brezillon 	if (nandc->props->is_bam)
121093db446aSBoris Brezillon 		return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
121193db446aSBoris Brezillon 
121293db446aSBoris Brezillon 	return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
121393db446aSBoris Brezillon }
121493db446aSBoris Brezillon 
121593db446aSBoris Brezillon /*
121693db446aSBoris Brezillon  * Helper to prepare DMA descriptors for configuring registers
121793db446aSBoris Brezillon  * before reading a NAND page.
121893db446aSBoris Brezillon  */
config_nand_page_read(struct nand_chip * chip)12199a7c39e2SMd Sadre Alam static void config_nand_page_read(struct nand_chip *chip)
122093db446aSBoris Brezillon {
12219a7c39e2SMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
12229a7c39e2SMd Sadre Alam 
122393db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
122493db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
1225bfb34eceSMd Sadre Alam 	if (!nandc->props->qpic_v2)
122693db446aSBoris Brezillon 		write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
122793db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
122893db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
122993db446aSBoris Brezillon 		      NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
123093db446aSBoris Brezillon }
123193db446aSBoris Brezillon 
123293db446aSBoris Brezillon /*
123393db446aSBoris Brezillon  * Helper to prepare DMA descriptors for configuring registers
123493db446aSBoris Brezillon  * before reading each codeword in NAND page.
123593db446aSBoris Brezillon  */
12365bc36b2bSAbhishek Sahu static void
config_nand_cw_read(struct nand_chip * chip,bool use_ecc,int cw)1237503ee5aaSMd Sadre Alam config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw)
123893db446aSBoris Brezillon {
12399a7c39e2SMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
1240503ee5aaSMd Sadre Alam 	struct nand_ecc_ctrl *ecc = &chip->ecc;
1241503ee5aaSMd Sadre Alam 
1242503ee5aaSMd Sadre Alam 	int reg = NAND_READ_LOCATION_0;
1243503ee5aaSMd Sadre Alam 
1244503ee5aaSMd Sadre Alam 	if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
1245503ee5aaSMd Sadre Alam 		reg = NAND_READ_LOCATION_LAST_CW_0;
12469a7c39e2SMd Sadre Alam 
124793db446aSBoris Brezillon 	if (nandc->props->is_bam)
1248503ee5aaSMd Sadre Alam 		write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
124993db446aSBoris Brezillon 
125093db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
125193db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
125293db446aSBoris Brezillon 
12535bc36b2bSAbhishek Sahu 	if (use_ecc) {
125493db446aSBoris Brezillon 		read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
125593db446aSBoris Brezillon 		read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
125693db446aSBoris Brezillon 			     NAND_BAM_NEXT_SGL);
12575bc36b2bSAbhishek Sahu 	} else {
12585bc36b2bSAbhishek Sahu 		read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
12595bc36b2bSAbhishek Sahu 	}
126093db446aSBoris Brezillon }
126193db446aSBoris Brezillon 
126293db446aSBoris Brezillon /*
126393db446aSBoris Brezillon  * Helper to prepare dma descriptors to configure registers needed for reading a
126493db446aSBoris Brezillon  * single codeword in page
126593db446aSBoris Brezillon  */
12665bc36b2bSAbhishek Sahu static void
config_nand_single_cw_page_read(struct nand_chip * chip,bool use_ecc,int cw)12679a7c39e2SMd Sadre Alam config_nand_single_cw_page_read(struct nand_chip *chip,
1268503ee5aaSMd Sadre Alam 				bool use_ecc, int cw)
126993db446aSBoris Brezillon {
12709a7c39e2SMd Sadre Alam 	config_nand_page_read(chip);
1271503ee5aaSMd Sadre Alam 	config_nand_cw_read(chip, use_ecc, cw);
127293db446aSBoris Brezillon }
127393db446aSBoris Brezillon 
127493db446aSBoris Brezillon /*
127593db446aSBoris Brezillon  * Helper to prepare DMA descriptors used to configure registers needed for
127693db446aSBoris Brezillon  * before writing a NAND page.
127793db446aSBoris Brezillon  */
config_nand_page_write(struct nand_chip * chip)12789a7c39e2SMd Sadre Alam static void config_nand_page_write(struct nand_chip *chip)
127993db446aSBoris Brezillon {
12809a7c39e2SMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
12819a7c39e2SMd Sadre Alam 
128293db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
128393db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
1284bfb34eceSMd Sadre Alam 	if (!nandc->props->qpic_v2)
128593db446aSBoris Brezillon 		write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
128693db446aSBoris Brezillon 			      NAND_BAM_NEXT_SGL);
128793db446aSBoris Brezillon }
128893db446aSBoris Brezillon 
128993db446aSBoris Brezillon /*
129093db446aSBoris Brezillon  * Helper to prepare DMA descriptors for configuring registers
129193db446aSBoris Brezillon  * before writing each codeword in NAND page.
129293db446aSBoris Brezillon  */
config_nand_cw_write(struct nand_chip * chip)12939a7c39e2SMd Sadre Alam static void config_nand_cw_write(struct nand_chip *chip)
129493db446aSBoris Brezillon {
12959a7c39e2SMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
12969a7c39e2SMd Sadre Alam 
129793db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
129893db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
129993db446aSBoris Brezillon 
130093db446aSBoris Brezillon 	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
130193db446aSBoris Brezillon 
130293db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
130393db446aSBoris Brezillon 	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
130493db446aSBoris Brezillon }
130593db446aSBoris Brezillon 
130693db446aSBoris Brezillon /* helpers to submit/free our list of dma descriptors */
submit_descs(struct qcom_nand_controller * nandc)130793db446aSBoris Brezillon static int submit_descs(struct qcom_nand_controller *nandc)
130893db446aSBoris Brezillon {
1309bb7a103dSManivannan Sadhasivam 	struct desc_info *desc, *n;
131093db446aSBoris Brezillon 	dma_cookie_t cookie = 0;
131193db446aSBoris Brezillon 	struct bam_transaction *bam_txn = nandc->bam_txn;
1312bb7a103dSManivannan Sadhasivam 	int ret = 0;
131393db446aSBoris Brezillon 
131493db446aSBoris Brezillon 	if (nandc->props->is_bam) {
131593db446aSBoris Brezillon 		if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
1316bb7a103dSManivannan Sadhasivam 			ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
1317bb7a103dSManivannan Sadhasivam 			if (ret)
1318bb7a103dSManivannan Sadhasivam 				goto err_unmap_free_desc;
131993db446aSBoris Brezillon 		}
132093db446aSBoris Brezillon 
132193db446aSBoris Brezillon 		if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
1322bb7a103dSManivannan Sadhasivam 			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
132393db446aSBoris Brezillon 						   DMA_PREP_INTERRUPT);
1324bb7a103dSManivannan Sadhasivam 			if (ret)
1325bb7a103dSManivannan Sadhasivam 				goto err_unmap_free_desc;
132693db446aSBoris Brezillon 		}
132793db446aSBoris Brezillon 
132893db446aSBoris Brezillon 		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
1329bb7a103dSManivannan Sadhasivam 			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
133093db446aSBoris Brezillon 						   DMA_PREP_CMD);
1331bb7a103dSManivannan Sadhasivam 			if (ret)
1332bb7a103dSManivannan Sadhasivam 				goto err_unmap_free_desc;
133393db446aSBoris Brezillon 		}
133493db446aSBoris Brezillon 	}
133593db446aSBoris Brezillon 
133693db446aSBoris Brezillon 	list_for_each_entry(desc, &nandc->desc_list, node)
133793db446aSBoris Brezillon 		cookie = dmaengine_submit(desc->dma_desc);
133893db446aSBoris Brezillon 
133993db446aSBoris Brezillon 	if (nandc->props->is_bam) {
13406f20070dSAbhishek Sahu 		bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
13416f20070dSAbhishek Sahu 		bam_txn->last_cmd_desc->callback_param = bam_txn;
13426f20070dSAbhishek Sahu 		if (bam_txn->last_data_desc) {
13436f20070dSAbhishek Sahu 			bam_txn->last_data_desc->callback = qpic_bam_dma_done;
13446f20070dSAbhishek Sahu 			bam_txn->last_data_desc->callback_param = bam_txn;
13456f20070dSAbhishek Sahu 			bam_txn->wait_second_completion = true;
13466f20070dSAbhishek Sahu 		}
13476f20070dSAbhishek Sahu 
134893db446aSBoris Brezillon 		dma_async_issue_pending(nandc->tx_chan);
134993db446aSBoris Brezillon 		dma_async_issue_pending(nandc->rx_chan);
13506f20070dSAbhishek Sahu 		dma_async_issue_pending(nandc->cmd_chan);
135193db446aSBoris Brezillon 
13526f20070dSAbhishek Sahu 		if (!wait_for_completion_timeout(&bam_txn->txn_done,
13536f20070dSAbhishek Sahu 						 QPIC_NAND_COMPLETION_TIMEOUT))
1354bb7a103dSManivannan Sadhasivam 			ret = -ETIMEDOUT;
135593db446aSBoris Brezillon 	} else {
135693db446aSBoris Brezillon 		if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
1357bb7a103dSManivannan Sadhasivam 			ret = -ETIMEDOUT;
135893db446aSBoris Brezillon 	}
135993db446aSBoris Brezillon 
1360bb7a103dSManivannan Sadhasivam err_unmap_free_desc:
1361bb7a103dSManivannan Sadhasivam 	/*
1362bb7a103dSManivannan Sadhasivam 	 * Unmap the dma sg_list and free the desc allocated by both
1363bb7a103dSManivannan Sadhasivam 	 * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
1364bb7a103dSManivannan Sadhasivam 	 */
136593db446aSBoris Brezillon 	list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
136693db446aSBoris Brezillon 		list_del(&desc->node);
136793db446aSBoris Brezillon 
136893db446aSBoris Brezillon 		if (nandc->props->is_bam)
136993db446aSBoris Brezillon 			dma_unmap_sg(nandc->dev, desc->bam_sgl,
137093db446aSBoris Brezillon 				     desc->sgl_cnt, desc->dir);
137193db446aSBoris Brezillon 		else
137293db446aSBoris Brezillon 			dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
137393db446aSBoris Brezillon 				     desc->dir);
137493db446aSBoris Brezillon 
137593db446aSBoris Brezillon 		kfree(desc);
137693db446aSBoris Brezillon 	}
1377bb7a103dSManivannan Sadhasivam 
1378bb7a103dSManivannan Sadhasivam 	return ret;
137993db446aSBoris Brezillon }
138093db446aSBoris Brezillon 
138193db446aSBoris Brezillon /* reset the register read buffer for next NAND operation */
clear_read_regs(struct qcom_nand_controller * nandc)138293db446aSBoris Brezillon static void clear_read_regs(struct qcom_nand_controller *nandc)
138393db446aSBoris Brezillon {
138493db446aSBoris Brezillon 	nandc->reg_read_pos = 0;
138593db446aSBoris Brezillon 	nandc_read_buffer_sync(nandc, false);
138693db446aSBoris Brezillon }
138793db446aSBoris Brezillon 
138893db446aSBoris Brezillon /*
138993db446aSBoris Brezillon  * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
139093db446aSBoris Brezillon  * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
139193db446aSBoris Brezillon  *
139293db446aSBoris Brezillon  * when using RS ECC, the HW reports the same erros when reading an erased CW,
139393db446aSBoris Brezillon  * but it notifies that it is an erased CW by placing special characters at
139493db446aSBoris Brezillon  * certain offsets in the buffer.
139593db446aSBoris Brezillon  *
139693db446aSBoris Brezillon  * verify if the page is erased or not, and fix up the page for RS ECC by
139793db446aSBoris Brezillon  * replacing the special characters with 0xff.
139893db446aSBoris Brezillon  */
erased_chunk_check_and_fixup(u8 * data_buf,int data_len)139993db446aSBoris Brezillon static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
140093db446aSBoris Brezillon {
140193db446aSBoris Brezillon 	u8 empty1, empty2;
140293db446aSBoris Brezillon 
140393db446aSBoris Brezillon 	/*
140493db446aSBoris Brezillon 	 * an erased page flags an error in NAND_FLASH_STATUS, check if the page
140593db446aSBoris Brezillon 	 * is erased by looking for 0x54s at offsets 3 and 175 from the
140693db446aSBoris Brezillon 	 * beginning of each codeword
140793db446aSBoris Brezillon 	 */
140893db446aSBoris Brezillon 
140993db446aSBoris Brezillon 	empty1 = data_buf[3];
141093db446aSBoris Brezillon 	empty2 = data_buf[175];
141193db446aSBoris Brezillon 
141293db446aSBoris Brezillon 	/*
141393db446aSBoris Brezillon 	 * if the erased codework markers, if they exist override them with
141493db446aSBoris Brezillon 	 * 0xffs
141593db446aSBoris Brezillon 	 */
141693db446aSBoris Brezillon 	if ((empty1 == 0x54 && empty2 == 0xff) ||
141793db446aSBoris Brezillon 	    (empty1 == 0xff && empty2 == 0x54)) {
141893db446aSBoris Brezillon 		data_buf[3] = 0xff;
141993db446aSBoris Brezillon 		data_buf[175] = 0xff;
142093db446aSBoris Brezillon 	}
142193db446aSBoris Brezillon 
142293db446aSBoris Brezillon 	/*
142393db446aSBoris Brezillon 	 * check if the entire chunk contains 0xffs or not. if it doesn't, then
142493db446aSBoris Brezillon 	 * restore the original values at the special offsets
142593db446aSBoris Brezillon 	 */
142693db446aSBoris Brezillon 	if (memchr_inv(data_buf, 0xff, data_len)) {
142793db446aSBoris Brezillon 		data_buf[3] = empty1;
142893db446aSBoris Brezillon 		data_buf[175] = empty2;
142993db446aSBoris Brezillon 
143093db446aSBoris Brezillon 		return false;
143193db446aSBoris Brezillon 	}
143293db446aSBoris Brezillon 
143393db446aSBoris Brezillon 	return true;
143493db446aSBoris Brezillon }
143593db446aSBoris Brezillon 
143693db446aSBoris Brezillon struct read_stats {
143793db446aSBoris Brezillon 	__le32 flash;
143893db446aSBoris Brezillon 	__le32 buffer;
143993db446aSBoris Brezillon 	__le32 erased_cw;
144093db446aSBoris Brezillon };
144193db446aSBoris Brezillon 
14425bc36b2bSAbhishek Sahu /* reads back FLASH_STATUS register set by the controller */
check_flash_errors(struct qcom_nand_host * host,int cw_cnt)14435bc36b2bSAbhishek Sahu static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
14445bc36b2bSAbhishek Sahu {
14455bc36b2bSAbhishek Sahu 	struct nand_chip *chip = &host->chip;
14465bc36b2bSAbhishek Sahu 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
14475bc36b2bSAbhishek Sahu 	int i;
14485bc36b2bSAbhishek Sahu 
1449bc368602SPraveenkumar I 	nandc_read_buffer_sync(nandc, true);
1450bc368602SPraveenkumar I 
14515bc36b2bSAbhishek Sahu 	for (i = 0; i < cw_cnt; i++) {
14525bc36b2bSAbhishek Sahu 		u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
14535bc36b2bSAbhishek Sahu 
14545bc36b2bSAbhishek Sahu 		if (flash & (FS_OP_ERR | FS_MPU_ERR))
14555bc36b2bSAbhishek Sahu 			return -EIO;
14565bc36b2bSAbhishek Sahu 	}
14575bc36b2bSAbhishek Sahu 
14585bc36b2bSAbhishek Sahu 	return 0;
14595bc36b2bSAbhishek Sahu }
14605bc36b2bSAbhishek Sahu 
146185632c17SAbhishek Sahu /* performs raw read for one codeword */
146285632c17SAbhishek Sahu static int
qcom_nandc_read_cw_raw(struct mtd_info * mtd,struct nand_chip * chip,u8 * data_buf,u8 * oob_buf,int page,int cw)146385632c17SAbhishek Sahu qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
146485632c17SAbhishek Sahu 		       u8 *data_buf, u8 *oob_buf, int page, int cw)
146585632c17SAbhishek Sahu {
146685632c17SAbhishek Sahu 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
146785632c17SAbhishek Sahu 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
146885632c17SAbhishek Sahu 	struct nand_ecc_ctrl *ecc = &chip->ecc;
146985632c17SAbhishek Sahu 	int data_size1, data_size2, oob_size1, oob_size2;
147085632c17SAbhishek Sahu 	int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
1471f60f5741SMd Sadre Alam 	int raw_cw = cw;
147285632c17SAbhishek Sahu 
147385632c17SAbhishek Sahu 	nand_read_page_op(chip, page, 0, NULL, 0);
1474318207ffSMd Sadre Alam 	nandc->buf_count = 0;
1475318207ffSMd Sadre Alam 	nandc->buf_start = 0;
1476318207ffSMd Sadre Alam 	clear_read_regs(nandc);
147785632c17SAbhishek Sahu 	host->use_ecc = false;
147885632c17SAbhishek Sahu 
1479f60f5741SMd Sadre Alam 	if (nandc->props->qpic_v2)
1480f60f5741SMd Sadre Alam 		raw_cw = ecc->steps - 1;
1481f60f5741SMd Sadre Alam 
148285632c17SAbhishek Sahu 	clear_bam_transaction(nandc);
148385632c17SAbhishek Sahu 	set_address(host, host->cw_size * cw, page);
1484f60f5741SMd Sadre Alam 	update_rw_regs(host, 1, true, raw_cw);
14859a7c39e2SMd Sadre Alam 	config_nand_page_read(chip);
148685632c17SAbhishek Sahu 
148785632c17SAbhishek Sahu 	data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
148885632c17SAbhishek Sahu 	oob_size1 = host->bbm_size;
148985632c17SAbhishek Sahu 
1490862bdeddSChristian Marangi 	if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) {
149185632c17SAbhishek Sahu 		data_size2 = ecc->size - data_size1 -
149285632c17SAbhishek Sahu 			     ((ecc->steps - 1) * 4);
149385632c17SAbhishek Sahu 		oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
149485632c17SAbhishek Sahu 			    host->spare_bytes;
149585632c17SAbhishek Sahu 	} else {
149685632c17SAbhishek Sahu 		data_size2 = host->cw_data - data_size1;
149785632c17SAbhishek Sahu 		oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
149885632c17SAbhishek Sahu 	}
149985632c17SAbhishek Sahu 
150085632c17SAbhishek Sahu 	if (nandc->props->is_bam) {
1501e7a307f2SMd Sadre Alam 		nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0);
150285632c17SAbhishek Sahu 		read_loc += data_size1;
150385632c17SAbhishek Sahu 
1504e7a307f2SMd Sadre Alam 		nandc_set_read_loc(chip, cw, 1, read_loc, oob_size1, 0);
150585632c17SAbhishek Sahu 		read_loc += oob_size1;
150685632c17SAbhishek Sahu 
1507e7a307f2SMd Sadre Alam 		nandc_set_read_loc(chip, cw, 2, read_loc, data_size2, 0);
150885632c17SAbhishek Sahu 		read_loc += data_size2;
150985632c17SAbhishek Sahu 
1510e7a307f2SMd Sadre Alam 		nandc_set_read_loc(chip, cw, 3, read_loc, oob_size2, 1);
151185632c17SAbhishek Sahu 	}
151285632c17SAbhishek Sahu 
1513f60f5741SMd Sadre Alam 	config_nand_cw_read(chip, false, raw_cw);
151485632c17SAbhishek Sahu 
151585632c17SAbhishek Sahu 	read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
151685632c17SAbhishek Sahu 	reg_off += data_size1;
151785632c17SAbhishek Sahu 
151885632c17SAbhishek Sahu 	read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
151985632c17SAbhishek Sahu 	reg_off += oob_size1;
152085632c17SAbhishek Sahu 
152185632c17SAbhishek Sahu 	read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
152285632c17SAbhishek Sahu 	reg_off += data_size2;
152385632c17SAbhishek Sahu 
152485632c17SAbhishek Sahu 	read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
152585632c17SAbhishek Sahu 
152685632c17SAbhishek Sahu 	ret = submit_descs(nandc);
152785632c17SAbhishek Sahu 	if (ret) {
152885632c17SAbhishek Sahu 		dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
152985632c17SAbhishek Sahu 		return ret;
153085632c17SAbhishek Sahu 	}
153185632c17SAbhishek Sahu 
153285632c17SAbhishek Sahu 	return check_flash_errors(host, 1);
153385632c17SAbhishek Sahu }
153485632c17SAbhishek Sahu 
153593db446aSBoris Brezillon /*
15369f43deeeSAbhishek Sahu  * Bitflips can happen in erased codewords also so this function counts the
15379f43deeeSAbhishek Sahu  * number of 0 in each CW for which ECC engine returns the uncorrectable
15389f43deeeSAbhishek Sahu  * error. The page will be assumed as erased if this count is less than or
15399f43deeeSAbhishek Sahu  * equal to the ecc->strength for each CW.
15409f43deeeSAbhishek Sahu  *
15419f43deeeSAbhishek Sahu  * 1. Both DATA and OOB need to be checked for number of 0. The
15429f43deeeSAbhishek Sahu  *    top-level API can be called with only data buf or OOB buf so use
15439f43deeeSAbhishek Sahu  *    chip->data_buf if data buf is null and chip->oob_poi if oob buf
15449f43deeeSAbhishek Sahu  *    is null for copying the raw bytes.
15459f43deeeSAbhishek Sahu  * 2. Perform raw read for all the CW which has uncorrectable errors.
15469f43deeeSAbhishek Sahu  * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
15479f43deeeSAbhishek Sahu  *    The BBM and spare bytes bit flip won’t affect the ECC so don’t check
15489f43deeeSAbhishek Sahu  *    the number of bitflips in this area.
15499f43deeeSAbhishek Sahu  */
15509f43deeeSAbhishek Sahu static int
check_for_erased_page(struct qcom_nand_host * host,u8 * data_buf,u8 * oob_buf,unsigned long uncorrectable_cws,int page,unsigned int max_bitflips)15519f43deeeSAbhishek Sahu check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
15529f43deeeSAbhishek Sahu 		      u8 *oob_buf, unsigned long uncorrectable_cws,
15539f43deeeSAbhishek Sahu 		      int page, unsigned int max_bitflips)
15549f43deeeSAbhishek Sahu {
15559f43deeeSAbhishek Sahu 	struct nand_chip *chip = &host->chip;
15569f43deeeSAbhishek Sahu 	struct mtd_info *mtd = nand_to_mtd(chip);
15579f43deeeSAbhishek Sahu 	struct nand_ecc_ctrl *ecc = &chip->ecc;
15589f43deeeSAbhishek Sahu 	u8 *cw_data_buf, *cw_oob_buf;
1559847178feSManivannan Sadhasivam 	int cw, data_size, oob_size, ret;
15609f43deeeSAbhishek Sahu 
1561eeab7174SBoris Brezillon 	if (!data_buf)
1562eeab7174SBoris Brezillon 		data_buf = nand_get_data_buf(chip);
15639f43deeeSAbhishek Sahu 
15649f43deeeSAbhishek Sahu 	if (!oob_buf) {
1565eeab7174SBoris Brezillon 		nand_get_data_buf(chip);
15669f43deeeSAbhishek Sahu 		oob_buf = chip->oob_poi;
15679f43deeeSAbhishek Sahu 	}
15689f43deeeSAbhishek Sahu 
15699f43deeeSAbhishek Sahu 	for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
1570862bdeddSChristian Marangi 		if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) {
15719f43deeeSAbhishek Sahu 			data_size = ecc->size - ((ecc->steps - 1) * 4);
15729f43deeeSAbhishek Sahu 			oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
15739f43deeeSAbhishek Sahu 		} else {
15749f43deeeSAbhishek Sahu 			data_size = host->cw_data;
15759f43deeeSAbhishek Sahu 			oob_size = host->ecc_bytes_hw;
15769f43deeeSAbhishek Sahu 		}
15779f43deeeSAbhishek Sahu 
15789f43deeeSAbhishek Sahu 		/* determine starting buffer address for current CW */
15799f43deeeSAbhishek Sahu 		cw_data_buf = data_buf + (cw * host->cw_data);
15809f43deeeSAbhishek Sahu 		cw_oob_buf = oob_buf + (cw * ecc->bytes);
15819f43deeeSAbhishek Sahu 
15829f43deeeSAbhishek Sahu 		ret = qcom_nandc_read_cw_raw(mtd, chip, cw_data_buf,
15839f43deeeSAbhishek Sahu 					     cw_oob_buf, page, cw);
15849f43deeeSAbhishek Sahu 		if (ret)
15859f43deeeSAbhishek Sahu 			return ret;
15869f43deeeSAbhishek Sahu 
15879f43deeeSAbhishek Sahu 		/*
15889f43deeeSAbhishek Sahu 		 * make sure it isn't an erased page reported
15899f43deeeSAbhishek Sahu 		 * as not-erased by HW because of a few bitflips
15909f43deeeSAbhishek Sahu 		 */
15919f43deeeSAbhishek Sahu 		ret = nand_check_erased_ecc_chunk(cw_data_buf, data_size,
15929f43deeeSAbhishek Sahu 						  cw_oob_buf + host->bbm_size,
15939f43deeeSAbhishek Sahu 						  oob_size, NULL,
15949f43deeeSAbhishek Sahu 						  0, ecc->strength);
15959f43deeeSAbhishek Sahu 		if (ret < 0) {
15969f43deeeSAbhishek Sahu 			mtd->ecc_stats.failed++;
15979f43deeeSAbhishek Sahu 		} else {
15989f43deeeSAbhishek Sahu 			mtd->ecc_stats.corrected += ret;
15999f43deeeSAbhishek Sahu 			max_bitflips = max_t(unsigned int, max_bitflips, ret);
16009f43deeeSAbhishek Sahu 		}
16019f43deeeSAbhishek Sahu 	}
16029f43deeeSAbhishek Sahu 
16039f43deeeSAbhishek Sahu 	return max_bitflips;
16049f43deeeSAbhishek Sahu }
16059f43deeeSAbhishek Sahu 
16069f43deeeSAbhishek Sahu /*
160793db446aSBoris Brezillon  * reads back status registers set by the controller to notify page read
160893db446aSBoris Brezillon  * errors. this is equivalent to what 'ecc->correct()' would do.
160993db446aSBoris Brezillon  */
parse_read_errors(struct qcom_nand_host * host,u8 * data_buf,u8 * oob_buf,int page)161093db446aSBoris Brezillon static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
16119f43deeeSAbhishek Sahu 			     u8 *oob_buf, int page)
161293db446aSBoris Brezillon {
161393db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
161493db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
161593db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
161693db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
16179f43deeeSAbhishek Sahu 	unsigned int max_bitflips = 0, uncorrectable_cws = 0;
161893db446aSBoris Brezillon 	struct read_stats *buf;
16199f43deeeSAbhishek Sahu 	bool flash_op_err = false, erased;
162093db446aSBoris Brezillon 	int i;
16219f43deeeSAbhishek Sahu 	u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
162293db446aSBoris Brezillon 
162393db446aSBoris Brezillon 	buf = (struct read_stats *)nandc->reg_read_buf;
162493db446aSBoris Brezillon 	nandc_read_buffer_sync(nandc, true);
162593db446aSBoris Brezillon 
162693db446aSBoris Brezillon 	for (i = 0; i < ecc->steps; i++, buf++) {
162793db446aSBoris Brezillon 		u32 flash, buffer, erased_cw;
162893db446aSBoris Brezillon 		int data_len, oob_len;
162993db446aSBoris Brezillon 
1630b057e498SMd Sadre Alam 		if (qcom_nandc_is_last_cw(ecc, i)) {
163193db446aSBoris Brezillon 			data_len = ecc->size - ((ecc->steps - 1) << 2);
163293db446aSBoris Brezillon 			oob_len = ecc->steps << 2;
163393db446aSBoris Brezillon 		} else {
163493db446aSBoris Brezillon 			data_len = host->cw_data;
163593db446aSBoris Brezillon 			oob_len = 0;
163693db446aSBoris Brezillon 		}
163793db446aSBoris Brezillon 
163893db446aSBoris Brezillon 		flash = le32_to_cpu(buf->flash);
163993db446aSBoris Brezillon 		buffer = le32_to_cpu(buf->buffer);
164093db446aSBoris Brezillon 		erased_cw = le32_to_cpu(buf->erased_cw);
164193db446aSBoris Brezillon 
16428eab7214SAbhishek Sahu 		/*
16438eab7214SAbhishek Sahu 		 * Check ECC failure for each codeword. ECC failure can
16448eab7214SAbhishek Sahu 		 * happen in either of the following conditions
16458eab7214SAbhishek Sahu 		 * 1. If number of bitflips are greater than ECC engine
16468eab7214SAbhishek Sahu 		 *    capability.
16478eab7214SAbhishek Sahu 		 * 2. If this codeword contains all 0xff for which erased
16488eab7214SAbhishek Sahu 		 *    codeword detection check will be done.
16498eab7214SAbhishek Sahu 		 */
16508eab7214SAbhishek Sahu 		if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
16512f610386SAbhishek Sahu 			/*
16522f610386SAbhishek Sahu 			 * For BCH ECC, ignore erased codeword errors, if
16532f610386SAbhishek Sahu 			 * ERASED_CW bits are set.
16542f610386SAbhishek Sahu 			 */
165593db446aSBoris Brezillon 			if (host->bch_enabled) {
1656902f332eSZhen Lei 				erased = (erased_cw & ERASED_CW) == ERASED_CW;
16572f610386SAbhishek Sahu 			/*
16582f610386SAbhishek Sahu 			 * For RS ECC, HW reports the erased CW by placing
16592f610386SAbhishek Sahu 			 * special characters at certain offsets in the buffer.
16602f610386SAbhishek Sahu 			 * These special characters will be valid only if
16612f610386SAbhishek Sahu 			 * complete page is read i.e. data_buf is not NULL.
16622f610386SAbhishek Sahu 			 */
16632f610386SAbhishek Sahu 			} else if (data_buf) {
166493db446aSBoris Brezillon 				erased = erased_chunk_check_and_fixup(data_buf,
166593db446aSBoris Brezillon 								      data_len);
16662f610386SAbhishek Sahu 			} else {
16672f610386SAbhishek Sahu 				erased = false;
166893db446aSBoris Brezillon 			}
166993db446aSBoris Brezillon 
16709f43deeeSAbhishek Sahu 			if (!erased)
16719f43deeeSAbhishek Sahu 				uncorrectable_cws |= BIT(i);
16728eab7214SAbhishek Sahu 		/*
16738eab7214SAbhishek Sahu 		 * Check if MPU or any other operational error (timeout,
16748eab7214SAbhishek Sahu 		 * device failure, etc.) happened for this codeword and
16758eab7214SAbhishek Sahu 		 * make flash_op_err true. If flash_op_err is set, then
16768eab7214SAbhishek Sahu 		 * EIO will be returned for page read.
16778eab7214SAbhishek Sahu 		 */
16788eab7214SAbhishek Sahu 		} else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
16798eab7214SAbhishek Sahu 			flash_op_err = true;
16808eab7214SAbhishek Sahu 		/*
16818eab7214SAbhishek Sahu 		 * No ECC or operational errors happened. Check the number of
16828eab7214SAbhishek Sahu 		 * bits corrected and update the ecc_stats.corrected.
16838eab7214SAbhishek Sahu 		 */
168493db446aSBoris Brezillon 		} else {
168593db446aSBoris Brezillon 			unsigned int stat;
168693db446aSBoris Brezillon 
168793db446aSBoris Brezillon 			stat = buffer & BS_CORRECTABLE_ERR_MSK;
168893db446aSBoris Brezillon 			mtd->ecc_stats.corrected += stat;
168993db446aSBoris Brezillon 			max_bitflips = max(max_bitflips, stat);
169093db446aSBoris Brezillon 		}
169193db446aSBoris Brezillon 
16922f610386SAbhishek Sahu 		if (data_buf)
169393db446aSBoris Brezillon 			data_buf += data_len;
169493db446aSBoris Brezillon 		if (oob_buf)
169593db446aSBoris Brezillon 			oob_buf += oob_len + ecc->bytes;
169693db446aSBoris Brezillon 	}
169793db446aSBoris Brezillon 
16988eab7214SAbhishek Sahu 	if (flash_op_err)
16998eab7214SAbhishek Sahu 		return -EIO;
17008eab7214SAbhishek Sahu 
17019f43deeeSAbhishek Sahu 	if (!uncorrectable_cws)
170293db446aSBoris Brezillon 		return max_bitflips;
17039f43deeeSAbhishek Sahu 
17049f43deeeSAbhishek Sahu 	return check_for_erased_page(host, data_buf_start, oob_buf_start,
17059f43deeeSAbhishek Sahu 				     uncorrectable_cws, page,
17069f43deeeSAbhishek Sahu 				     max_bitflips);
170793db446aSBoris Brezillon }
170893db446aSBoris Brezillon 
170993db446aSBoris Brezillon /*
171093db446aSBoris Brezillon  * helper to perform the actual page read operation, used by ecc->read_page(),
171193db446aSBoris Brezillon  * ecc->read_oob()
171293db446aSBoris Brezillon  */
read_page_ecc(struct qcom_nand_host * host,u8 * data_buf,u8 * oob_buf,int page)171393db446aSBoris Brezillon static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
17149f43deeeSAbhishek Sahu 			 u8 *oob_buf, int page)
171593db446aSBoris Brezillon {
171693db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
171793db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
171893db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
1719add0cfa3SAbhishek Sahu 	u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
172093db446aSBoris Brezillon 	int i, ret;
172193db446aSBoris Brezillon 
17229a7c39e2SMd Sadre Alam 	config_nand_page_read(chip);
172393db446aSBoris Brezillon 
172493db446aSBoris Brezillon 	/* queue cmd descs for each codeword */
172593db446aSBoris Brezillon 	for (i = 0; i < ecc->steps; i++) {
172693db446aSBoris Brezillon 		int data_size, oob_size;
172793db446aSBoris Brezillon 
1728862bdeddSChristian Marangi 		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) {
172993db446aSBoris Brezillon 			data_size = ecc->size - ((ecc->steps - 1) << 2);
173093db446aSBoris Brezillon 			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
173193db446aSBoris Brezillon 				   host->spare_bytes;
173293db446aSBoris Brezillon 		} else {
173393db446aSBoris Brezillon 			data_size = host->cw_data;
173493db446aSBoris Brezillon 			oob_size = host->ecc_bytes_hw + host->spare_bytes;
173593db446aSBoris Brezillon 		}
173693db446aSBoris Brezillon 
173793db446aSBoris Brezillon 		if (nandc->props->is_bam) {
173893db446aSBoris Brezillon 			if (data_buf && oob_buf) {
1739e7a307f2SMd Sadre Alam 				nandc_set_read_loc(chip, i, 0, 0, data_size, 0);
1740e7a307f2SMd Sadre Alam 				nandc_set_read_loc(chip, i, 1, data_size,
174193db446aSBoris Brezillon 						   oob_size, 1);
174293db446aSBoris Brezillon 			} else if (data_buf) {
1743e7a307f2SMd Sadre Alam 				nandc_set_read_loc(chip, i, 0, 0, data_size, 1);
174493db446aSBoris Brezillon 			} else {
1745e7a307f2SMd Sadre Alam 				nandc_set_read_loc(chip, i, 0, data_size,
174693db446aSBoris Brezillon 						   oob_size, 1);
174793db446aSBoris Brezillon 			}
174893db446aSBoris Brezillon 		}
174993db446aSBoris Brezillon 
1750503ee5aaSMd Sadre Alam 		config_nand_cw_read(chip, true, i);
175193db446aSBoris Brezillon 
175293db446aSBoris Brezillon 		if (data_buf)
175393db446aSBoris Brezillon 			read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
175493db446aSBoris Brezillon 				      data_size, 0);
175593db446aSBoris Brezillon 
175693db446aSBoris Brezillon 		/*
175793db446aSBoris Brezillon 		 * when ecc is enabled, the controller doesn't read the real
175893db446aSBoris Brezillon 		 * or dummy bad block markers in each chunk. To maintain a
175993db446aSBoris Brezillon 		 * consistent layout across RAW and ECC reads, we just
176093db446aSBoris Brezillon 		 * leave the real/dummy BBM offsets empty (i.e, filled with
176193db446aSBoris Brezillon 		 * 0xffs)
176293db446aSBoris Brezillon 		 */
176393db446aSBoris Brezillon 		if (oob_buf) {
176493db446aSBoris Brezillon 			int j;
176593db446aSBoris Brezillon 
176693db446aSBoris Brezillon 			for (j = 0; j < host->bbm_size; j++)
176793db446aSBoris Brezillon 				*oob_buf++ = 0xff;
176893db446aSBoris Brezillon 
176993db446aSBoris Brezillon 			read_data_dma(nandc, FLASH_BUF_ACC + data_size,
177093db446aSBoris Brezillon 				      oob_buf, oob_size, 0);
177193db446aSBoris Brezillon 		}
177293db446aSBoris Brezillon 
177393db446aSBoris Brezillon 		if (data_buf)
177493db446aSBoris Brezillon 			data_buf += data_size;
177593db446aSBoris Brezillon 		if (oob_buf)
177693db446aSBoris Brezillon 			oob_buf += oob_size;
177793db446aSBoris Brezillon 	}
177893db446aSBoris Brezillon 
177993db446aSBoris Brezillon 	ret = submit_descs(nandc);
1780add0cfa3SAbhishek Sahu 	if (ret) {
1781add0cfa3SAbhishek Sahu 		dev_err(nandc->dev, "failure to read page/oob\n");
178293db446aSBoris Brezillon 		return ret;
178393db446aSBoris Brezillon 	}
178493db446aSBoris Brezillon 
17859f43deeeSAbhishek Sahu 	return parse_read_errors(host, data_buf_start, oob_buf_start, page);
1786add0cfa3SAbhishek Sahu }
1787add0cfa3SAbhishek Sahu 
178893db446aSBoris Brezillon /*
178993db446aSBoris Brezillon  * a helper that copies the last step/codeword of a page (containing free oob)
179093db446aSBoris Brezillon  * into our local buffer
179193db446aSBoris Brezillon  */
copy_last_cw(struct qcom_nand_host * host,int page)179293db446aSBoris Brezillon static int copy_last_cw(struct qcom_nand_host *host, int page)
179393db446aSBoris Brezillon {
179493db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
179593db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
179693db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
179793db446aSBoris Brezillon 	int size;
179893db446aSBoris Brezillon 	int ret;
179993db446aSBoris Brezillon 
180093db446aSBoris Brezillon 	clear_read_regs(nandc);
180193db446aSBoris Brezillon 
180293db446aSBoris Brezillon 	size = host->use_ecc ? host->cw_data : host->cw_size;
180393db446aSBoris Brezillon 
180493db446aSBoris Brezillon 	/* prepare a clean read buffer */
180593db446aSBoris Brezillon 	memset(nandc->data_buffer, 0xff, size);
180693db446aSBoris Brezillon 
180793db446aSBoris Brezillon 	set_address(host, host->cw_size * (ecc->steps - 1), page);
1808503ee5aaSMd Sadre Alam 	update_rw_regs(host, 1, true, ecc->steps - 1);
180993db446aSBoris Brezillon 
1810503ee5aaSMd Sadre Alam 	config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
181193db446aSBoris Brezillon 
181293db446aSBoris Brezillon 	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
181393db446aSBoris Brezillon 
181493db446aSBoris Brezillon 	ret = submit_descs(nandc);
181593db446aSBoris Brezillon 	if (ret)
181693db446aSBoris Brezillon 		dev_err(nandc->dev, "failed to copy last codeword\n");
181793db446aSBoris Brezillon 
181893db446aSBoris Brezillon 	return ret;
181993db446aSBoris Brezillon }
182093db446aSBoris Brezillon 
qcom_nandc_is_boot_partition(struct qcom_nand_host * host,int page)1821862bdeddSChristian Marangi static bool qcom_nandc_is_boot_partition(struct qcom_nand_host *host, int page)
1822862bdeddSChristian Marangi {
1823862bdeddSChristian Marangi 	struct qcom_nand_boot_partition *boot_partition;
1824862bdeddSChristian Marangi 	u32 start, end;
1825862bdeddSChristian Marangi 	int i;
1826862bdeddSChristian Marangi 
1827862bdeddSChristian Marangi 	/*
1828862bdeddSChristian Marangi 	 * Since the frequent access will be to the non-boot partitions like rootfs,
1829862bdeddSChristian Marangi 	 * optimize the page check by:
1830862bdeddSChristian Marangi 	 *
1831862bdeddSChristian Marangi 	 * 1. Checking if the page lies after the last boot partition.
1832862bdeddSChristian Marangi 	 * 2. Checking from the boot partition end.
1833862bdeddSChristian Marangi 	 */
1834862bdeddSChristian Marangi 
1835862bdeddSChristian Marangi 	/* First check the last boot partition */
1836862bdeddSChristian Marangi 	boot_partition = &host->boot_partitions[host->nr_boot_partitions - 1];
1837862bdeddSChristian Marangi 	start = boot_partition->page_offset;
1838862bdeddSChristian Marangi 	end = start + boot_partition->page_size;
1839862bdeddSChristian Marangi 
1840862bdeddSChristian Marangi 	/* Page is after the last boot partition end. This is NOT a boot partition */
1841862bdeddSChristian Marangi 	if (page > end)
1842862bdeddSChristian Marangi 		return false;
1843862bdeddSChristian Marangi 
1844862bdeddSChristian Marangi 	/* Actually check if it's a boot partition */
1845862bdeddSChristian Marangi 	if (page < end && page >= start)
1846862bdeddSChristian Marangi 		return true;
1847862bdeddSChristian Marangi 
1848862bdeddSChristian Marangi 	/* Check the other boot partitions starting from the second-last partition */
1849862bdeddSChristian Marangi 	for (i = host->nr_boot_partitions - 2; i >= 0; i--) {
1850862bdeddSChristian Marangi 		boot_partition = &host->boot_partitions[i];
1851862bdeddSChristian Marangi 		start = boot_partition->page_offset;
1852862bdeddSChristian Marangi 		end = start + boot_partition->page_size;
1853862bdeddSChristian Marangi 
1854862bdeddSChristian Marangi 		if (page < end && page >= start)
1855862bdeddSChristian Marangi 			return true;
1856862bdeddSChristian Marangi 	}
1857862bdeddSChristian Marangi 
1858862bdeddSChristian Marangi 	return false;
1859862bdeddSChristian Marangi }
1860862bdeddSChristian Marangi 
qcom_nandc_codeword_fixup(struct qcom_nand_host * host,int page)1861862bdeddSChristian Marangi static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page)
1862862bdeddSChristian Marangi {
1863862bdeddSChristian Marangi 	bool codeword_fixup = qcom_nandc_is_boot_partition(host, page);
1864862bdeddSChristian Marangi 
1865862bdeddSChristian Marangi 	/* Skip conf write if we are already in the correct mode */
1866862bdeddSChristian Marangi 	if (codeword_fixup == host->codeword_fixup)
1867862bdeddSChristian Marangi 		return;
1868862bdeddSChristian Marangi 
1869862bdeddSChristian Marangi 	host->codeword_fixup = codeword_fixup;
1870862bdeddSChristian Marangi 
1871862bdeddSChristian Marangi 	host->cw_data = codeword_fixup ? 512 : 516;
1872862bdeddSChristian Marangi 	host->spare_bytes = host->cw_size - host->ecc_bytes_hw -
1873862bdeddSChristian Marangi 			    host->bbm_size - host->cw_data;
1874862bdeddSChristian Marangi 
1875862bdeddSChristian Marangi 	host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK);
1876862bdeddSChristian Marangi 	host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES |
1877862bdeddSChristian Marangi 		      host->cw_data << UD_SIZE_BYTES;
1878862bdeddSChristian Marangi 
1879862bdeddSChristian Marangi 	host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK;
1880862bdeddSChristian Marangi 	host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES;
1881862bdeddSChristian Marangi 	host->ecc_buf_cfg = (host->cw_data - 1) << NUM_STEPS;
1882862bdeddSChristian Marangi }
1883862bdeddSChristian Marangi 
188493db446aSBoris Brezillon /* implements ecc->read_page() */
qcom_nandc_read_page(struct nand_chip * chip,u8 * buf,int oob_required,int page)1885428771b6SMiquel Raynal static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf,
1886b9761687SBoris Brezillon 				int oob_required, int page)
188793db446aSBoris Brezillon {
188893db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
188993db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
189089550bebSMd Sadre Alam 	struct nand_ecc_ctrl *ecc = &chip->ecc;
189193db446aSBoris Brezillon 	u8 *data_buf, *oob_buf = NULL;
189293db446aSBoris Brezillon 
1893862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
1894862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
1895862bdeddSChristian Marangi 
189693db446aSBoris Brezillon 	nand_read_page_op(chip, page, 0, NULL, 0);
189789550bebSMd Sadre Alam 	nandc->buf_count = 0;
189889550bebSMd Sadre Alam 	nandc->buf_start = 0;
189989550bebSMd Sadre Alam 	host->use_ecc = true;
190089550bebSMd Sadre Alam 	clear_read_regs(nandc);
190189550bebSMd Sadre Alam 	set_address(host, 0, page);
190289550bebSMd Sadre Alam 	update_rw_regs(host, ecc->steps, true, 0);
190389550bebSMd Sadre Alam 
190493db446aSBoris Brezillon 	data_buf = buf;
190593db446aSBoris Brezillon 	oob_buf = oob_required ? chip->oob_poi : NULL;
190693db446aSBoris Brezillon 
190793db446aSBoris Brezillon 	clear_bam_transaction(nandc);
190893db446aSBoris Brezillon 
19099f43deeeSAbhishek Sahu 	return read_page_ecc(host, data_buf, oob_buf, page);
191093db446aSBoris Brezillon }
191193db446aSBoris Brezillon 
191293db446aSBoris Brezillon /* implements ecc->read_page_raw() */
qcom_nandc_read_page_raw(struct nand_chip * chip,u8 * buf,int oob_required,int page)1913428771b6SMiquel Raynal static int qcom_nandc_read_page_raw(struct nand_chip *chip, u8 *buf,
191493db446aSBoris Brezillon 				    int oob_required, int page)
191593db446aSBoris Brezillon {
1916b9761687SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
191793db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
191893db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
191985632c17SAbhishek Sahu 	int cw, ret;
192085632c17SAbhishek Sahu 	u8 *data_buf = buf, *oob_buf = chip->oob_poi;
192193db446aSBoris Brezillon 
1922862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
1923862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
1924862bdeddSChristian Marangi 
192585632c17SAbhishek Sahu 	for (cw = 0; cw < ecc->steps; cw++) {
192685632c17SAbhishek Sahu 		ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
192785632c17SAbhishek Sahu 					     page, cw);
192885632c17SAbhishek Sahu 		if (ret)
1929783b5bf9SAbhishek Sahu 			return ret;
193085632c17SAbhishek Sahu 
193185632c17SAbhishek Sahu 		data_buf += host->cw_data;
193285632c17SAbhishek Sahu 		oob_buf += ecc->bytes;
193393db446aSBoris Brezillon 	}
193493db446aSBoris Brezillon 
193585632c17SAbhishek Sahu 	return 0;
19365bc36b2bSAbhishek Sahu }
19375bc36b2bSAbhishek Sahu 
193893db446aSBoris Brezillon /* implements ecc->read_oob() */
qcom_nandc_read_oob(struct nand_chip * chip,int page)1939b9761687SBoris Brezillon static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
194093db446aSBoris Brezillon {
194193db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
194293db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
194393db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
194493db446aSBoris Brezillon 
1945862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
1946862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
1947862bdeddSChristian Marangi 
194893db446aSBoris Brezillon 	clear_read_regs(nandc);
194993db446aSBoris Brezillon 	clear_bam_transaction(nandc);
195093db446aSBoris Brezillon 
195193db446aSBoris Brezillon 	host->use_ecc = true;
195293db446aSBoris Brezillon 	set_address(host, 0, page);
1953503ee5aaSMd Sadre Alam 	update_rw_regs(host, ecc->steps, true, 0);
195493db446aSBoris Brezillon 
19559f43deeeSAbhishek Sahu 	return read_page_ecc(host, NULL, chip->oob_poi, page);
195693db446aSBoris Brezillon }
195793db446aSBoris Brezillon 
195893db446aSBoris Brezillon /* implements ecc->write_page() */
qcom_nandc_write_page(struct nand_chip * chip,const u8 * buf,int oob_required,int page)1959428771b6SMiquel Raynal static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
1960767eb6fbSBoris Brezillon 				 int oob_required, int page)
196193db446aSBoris Brezillon {
196293db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
196393db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
196493db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
196593db446aSBoris Brezillon 	u8 *data_buf, *oob_buf;
196693db446aSBoris Brezillon 	int i, ret;
196793db446aSBoris Brezillon 
1968862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
1969862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
1970862bdeddSChristian Marangi 
197193db446aSBoris Brezillon 	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
197293db446aSBoris Brezillon 
197389550bebSMd Sadre Alam 	set_address(host, 0, page);
197489550bebSMd Sadre Alam 	nandc->buf_count = 0;
197589550bebSMd Sadre Alam 	nandc->buf_start = 0;
197693db446aSBoris Brezillon 	clear_read_regs(nandc);
197793db446aSBoris Brezillon 	clear_bam_transaction(nandc);
197893db446aSBoris Brezillon 
197993db446aSBoris Brezillon 	data_buf = (u8 *)buf;
198093db446aSBoris Brezillon 	oob_buf = chip->oob_poi;
198193db446aSBoris Brezillon 
198293db446aSBoris Brezillon 	host->use_ecc = true;
1983503ee5aaSMd Sadre Alam 	update_rw_regs(host, ecc->steps, false, 0);
19849a7c39e2SMd Sadre Alam 	config_nand_page_write(chip);
198593db446aSBoris Brezillon 
198693db446aSBoris Brezillon 	for (i = 0; i < ecc->steps; i++) {
198793db446aSBoris Brezillon 		int data_size, oob_size;
198893db446aSBoris Brezillon 
1989862bdeddSChristian Marangi 		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) {
199093db446aSBoris Brezillon 			data_size = ecc->size - ((ecc->steps - 1) << 2);
199193db446aSBoris Brezillon 			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
199293db446aSBoris Brezillon 				   host->spare_bytes;
199393db446aSBoris Brezillon 		} else {
199493db446aSBoris Brezillon 			data_size = host->cw_data;
199593db446aSBoris Brezillon 			oob_size = ecc->bytes;
199693db446aSBoris Brezillon 		}
199793db446aSBoris Brezillon 
199893db446aSBoris Brezillon 		write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
199993db446aSBoris Brezillon 			       i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
200093db446aSBoris Brezillon 
200193db446aSBoris Brezillon 		/*
200293db446aSBoris Brezillon 		 * when ECC is enabled, we don't really need to write anything
200393db446aSBoris Brezillon 		 * to oob for the first n - 1 codewords since these oob regions
200493db446aSBoris Brezillon 		 * just contain ECC bytes that's written by the controller
200593db446aSBoris Brezillon 		 * itself. For the last codeword, we skip the bbm positions and
200693db446aSBoris Brezillon 		 * write to the free oob area.
200793db446aSBoris Brezillon 		 */
2008b057e498SMd Sadre Alam 		if (qcom_nandc_is_last_cw(ecc, i)) {
200993db446aSBoris Brezillon 			oob_buf += host->bbm_size;
201093db446aSBoris Brezillon 
201193db446aSBoris Brezillon 			write_data_dma(nandc, FLASH_BUF_ACC + data_size,
201293db446aSBoris Brezillon 				       oob_buf, oob_size, 0);
201393db446aSBoris Brezillon 		}
201493db446aSBoris Brezillon 
20159a7c39e2SMd Sadre Alam 		config_nand_cw_write(chip);
201693db446aSBoris Brezillon 
201793db446aSBoris Brezillon 		data_buf += data_size;
201893db446aSBoris Brezillon 		oob_buf += oob_size;
201993db446aSBoris Brezillon 	}
202093db446aSBoris Brezillon 
202193db446aSBoris Brezillon 	ret = submit_descs(nandc);
2022c56de1e5SManivannan Sadhasivam 	if (ret) {
202393db446aSBoris Brezillon 		dev_err(nandc->dev, "failure to write page\n");
202493db446aSBoris Brezillon 		return ret;
202593db446aSBoris Brezillon 	}
202693db446aSBoris Brezillon 
2027c56de1e5SManivannan Sadhasivam 	return nand_prog_page_end_op(chip);
2028c56de1e5SManivannan Sadhasivam }
2029c56de1e5SManivannan Sadhasivam 
203093db446aSBoris Brezillon /* implements ecc->write_page_raw() */
qcom_nandc_write_page_raw(struct nand_chip * chip,const u8 * buf,int oob_required,int page)2031767eb6fbSBoris Brezillon static int qcom_nandc_write_page_raw(struct nand_chip *chip,
2032428771b6SMiquel Raynal 				     const u8 *buf, int oob_required,
2033767eb6fbSBoris Brezillon 				     int page)
203493db446aSBoris Brezillon {
2035767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
203693db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
203793db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
203893db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
203993db446aSBoris Brezillon 	u8 *data_buf, *oob_buf;
204093db446aSBoris Brezillon 	int i, ret;
204193db446aSBoris Brezillon 
2042862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
2043862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
2044862bdeddSChristian Marangi 
204593db446aSBoris Brezillon 	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
204693db446aSBoris Brezillon 	clear_read_regs(nandc);
204793db446aSBoris Brezillon 	clear_bam_transaction(nandc);
204893db446aSBoris Brezillon 
204993db446aSBoris Brezillon 	data_buf = (u8 *)buf;
205093db446aSBoris Brezillon 	oob_buf = chip->oob_poi;
205193db446aSBoris Brezillon 
205293db446aSBoris Brezillon 	host->use_ecc = false;
2053503ee5aaSMd Sadre Alam 	update_rw_regs(host, ecc->steps, false, 0);
20549a7c39e2SMd Sadre Alam 	config_nand_page_write(chip);
205593db446aSBoris Brezillon 
205693db446aSBoris Brezillon 	for (i = 0; i < ecc->steps; i++) {
205793db446aSBoris Brezillon 		int data_size1, data_size2, oob_size1, oob_size2;
205893db446aSBoris Brezillon 		int reg_off = FLASH_BUF_ACC;
205993db446aSBoris Brezillon 
206093db446aSBoris Brezillon 		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
206193db446aSBoris Brezillon 		oob_size1 = host->bbm_size;
206293db446aSBoris Brezillon 
2063862bdeddSChristian Marangi 		if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) {
206493db446aSBoris Brezillon 			data_size2 = ecc->size - data_size1 -
206593db446aSBoris Brezillon 				     ((ecc->steps - 1) << 2);
206693db446aSBoris Brezillon 			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
206793db446aSBoris Brezillon 				    host->spare_bytes;
206893db446aSBoris Brezillon 		} else {
206993db446aSBoris Brezillon 			data_size2 = host->cw_data - data_size1;
207093db446aSBoris Brezillon 			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
207193db446aSBoris Brezillon 		}
207293db446aSBoris Brezillon 
207393db446aSBoris Brezillon 		write_data_dma(nandc, reg_off, data_buf, data_size1,
207493db446aSBoris Brezillon 			       NAND_BAM_NO_EOT);
207593db446aSBoris Brezillon 		reg_off += data_size1;
207693db446aSBoris Brezillon 		data_buf += data_size1;
207793db446aSBoris Brezillon 
207893db446aSBoris Brezillon 		write_data_dma(nandc, reg_off, oob_buf, oob_size1,
207993db446aSBoris Brezillon 			       NAND_BAM_NO_EOT);
208093db446aSBoris Brezillon 		reg_off += oob_size1;
208193db446aSBoris Brezillon 		oob_buf += oob_size1;
208293db446aSBoris Brezillon 
208393db446aSBoris Brezillon 		write_data_dma(nandc, reg_off, data_buf, data_size2,
208493db446aSBoris Brezillon 			       NAND_BAM_NO_EOT);
208593db446aSBoris Brezillon 		reg_off += data_size2;
208693db446aSBoris Brezillon 		data_buf += data_size2;
208793db446aSBoris Brezillon 
208893db446aSBoris Brezillon 		write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
208993db446aSBoris Brezillon 		oob_buf += oob_size2;
209093db446aSBoris Brezillon 
20919a7c39e2SMd Sadre Alam 		config_nand_cw_write(chip);
209293db446aSBoris Brezillon 	}
209393db446aSBoris Brezillon 
209493db446aSBoris Brezillon 	ret = submit_descs(nandc);
2095c56de1e5SManivannan Sadhasivam 	if (ret) {
209693db446aSBoris Brezillon 		dev_err(nandc->dev, "failure to write raw page\n");
209793db446aSBoris Brezillon 		return ret;
209893db446aSBoris Brezillon 	}
209993db446aSBoris Brezillon 
2100c56de1e5SManivannan Sadhasivam 	return nand_prog_page_end_op(chip);
2101c56de1e5SManivannan Sadhasivam }
2102c56de1e5SManivannan Sadhasivam 
210393db446aSBoris Brezillon /*
210493db446aSBoris Brezillon  * implements ecc->write_oob()
210593db446aSBoris Brezillon  *
210628eed9f6SAbhishek Sahu  * the NAND controller cannot write only data or only OOB within a codeword
210728eed9f6SAbhishek Sahu  * since ECC is calculated for the combined codeword. So update the OOB from
210828eed9f6SAbhishek Sahu  * chip->oob_poi, and pad the data area with OxFF before writing.
210993db446aSBoris Brezillon  */
qcom_nandc_write_oob(struct nand_chip * chip,int page)2110767eb6fbSBoris Brezillon static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
211193db446aSBoris Brezillon {
2112767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
211393db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
211493db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
211593db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
211693db446aSBoris Brezillon 	u8 *oob = chip->oob_poi;
211793db446aSBoris Brezillon 	int data_size, oob_size;
211893db446aSBoris Brezillon 	int ret;
211993db446aSBoris Brezillon 
2120862bdeddSChristian Marangi 	if (host->nr_boot_partitions)
2121862bdeddSChristian Marangi 		qcom_nandc_codeword_fixup(host, page);
2122862bdeddSChristian Marangi 
212393db446aSBoris Brezillon 	host->use_ecc = true;
212493db446aSBoris Brezillon 	clear_bam_transaction(nandc);
212593db446aSBoris Brezillon 
212693db446aSBoris Brezillon 	/* calculate the data and oob size for the last codeword/step */
212793db446aSBoris Brezillon 	data_size = ecc->size - ((ecc->steps - 1) << 2);
212893db446aSBoris Brezillon 	oob_size = mtd->oobavail;
212993db446aSBoris Brezillon 
213028eed9f6SAbhishek Sahu 	memset(nandc->data_buffer, 0xff, host->cw_data);
213193db446aSBoris Brezillon 	/* override new oob content to last codeword */
213293db446aSBoris Brezillon 	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
213393db446aSBoris Brezillon 				    0, mtd->oobavail);
213493db446aSBoris Brezillon 
213593db446aSBoris Brezillon 	set_address(host, host->cw_size * (ecc->steps - 1), page);
2136503ee5aaSMd Sadre Alam 	update_rw_regs(host, 1, false, 0);
213793db446aSBoris Brezillon 
21389a7c39e2SMd Sadre Alam 	config_nand_page_write(chip);
213993db446aSBoris Brezillon 	write_data_dma(nandc, FLASH_BUF_ACC,
214093db446aSBoris Brezillon 		       nandc->data_buffer, data_size + oob_size, 0);
21419a7c39e2SMd Sadre Alam 	config_nand_cw_write(chip);
214293db446aSBoris Brezillon 
214393db446aSBoris Brezillon 	ret = submit_descs(nandc);
214493db446aSBoris Brezillon 	if (ret) {
214593db446aSBoris Brezillon 		dev_err(nandc->dev, "failure to write oob\n");
2146dcd1e618SManivannan Sadhasivam 		return ret;
214793db446aSBoris Brezillon 	}
214893db446aSBoris Brezillon 
214993db446aSBoris Brezillon 	return nand_prog_page_end_op(chip);
215093db446aSBoris Brezillon }
215193db446aSBoris Brezillon 
qcom_nandc_block_bad(struct nand_chip * chip,loff_t ofs)2152c17556f5SBoris Brezillon static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
215393db446aSBoris Brezillon {
2154c17556f5SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
215593db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
215693db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
215793db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
215893db446aSBoris Brezillon 	int page, ret, bbpos, bad = 0;
215993db446aSBoris Brezillon 
216093db446aSBoris Brezillon 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
216193db446aSBoris Brezillon 
216293db446aSBoris Brezillon 	/*
216393db446aSBoris Brezillon 	 * configure registers for a raw sub page read, the address is set to
216493db446aSBoris Brezillon 	 * the beginning of the last codeword, we don't care about reading ecc
216593db446aSBoris Brezillon 	 * portion of oob. we just want the first few bytes from this codeword
216693db446aSBoris Brezillon 	 * that contains the BBM
216793db446aSBoris Brezillon 	 */
216893db446aSBoris Brezillon 	host->use_ecc = false;
216993db446aSBoris Brezillon 
217093db446aSBoris Brezillon 	clear_bam_transaction(nandc);
217193db446aSBoris Brezillon 	ret = copy_last_cw(host, page);
217293db446aSBoris Brezillon 	if (ret)
217393db446aSBoris Brezillon 		goto err;
217493db446aSBoris Brezillon 
21755bc36b2bSAbhishek Sahu 	if (check_flash_errors(host, 1)) {
217693db446aSBoris Brezillon 		dev_warn(nandc->dev, "error when trying to read BBM\n");
217793db446aSBoris Brezillon 		goto err;
217893db446aSBoris Brezillon 	}
217993db446aSBoris Brezillon 
218093db446aSBoris Brezillon 	bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
218193db446aSBoris Brezillon 
218293db446aSBoris Brezillon 	bad = nandc->data_buffer[bbpos] != 0xff;
218393db446aSBoris Brezillon 
218493db446aSBoris Brezillon 	if (chip->options & NAND_BUSWIDTH_16)
218593db446aSBoris Brezillon 		bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
218693db446aSBoris Brezillon err:
218793db446aSBoris Brezillon 	return bad;
218893db446aSBoris Brezillon }
218993db446aSBoris Brezillon 
qcom_nandc_block_markbad(struct nand_chip * chip,loff_t ofs)2190c17556f5SBoris Brezillon static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
219193db446aSBoris Brezillon {
219293db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
219393db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
219493db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
219593db446aSBoris Brezillon 	int page, ret;
219693db446aSBoris Brezillon 
219793db446aSBoris Brezillon 	clear_read_regs(nandc);
219893db446aSBoris Brezillon 	clear_bam_transaction(nandc);
219993db446aSBoris Brezillon 
220093db446aSBoris Brezillon 	/*
220193db446aSBoris Brezillon 	 * to mark the BBM as bad, we flash the entire last codeword with 0s.
220293db446aSBoris Brezillon 	 * we don't care about the rest of the content in the codeword since
220393db446aSBoris Brezillon 	 * we aren't going to use this block again
220493db446aSBoris Brezillon 	 */
220593db446aSBoris Brezillon 	memset(nandc->data_buffer, 0x00, host->cw_size);
220693db446aSBoris Brezillon 
220793db446aSBoris Brezillon 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
220893db446aSBoris Brezillon 
220993db446aSBoris Brezillon 	/* prepare write */
221093db446aSBoris Brezillon 	host->use_ecc = false;
221193db446aSBoris Brezillon 	set_address(host, host->cw_size * (ecc->steps - 1), page);
2212503ee5aaSMd Sadre Alam 	update_rw_regs(host, 1, false, ecc->steps - 1);
221393db446aSBoris Brezillon 
22149a7c39e2SMd Sadre Alam 	config_nand_page_write(chip);
221593db446aSBoris Brezillon 	write_data_dma(nandc, FLASH_BUF_ACC,
221693db446aSBoris Brezillon 		       nandc->data_buffer, host->cw_size, 0);
22179a7c39e2SMd Sadre Alam 	config_nand_cw_write(chip);
221893db446aSBoris Brezillon 
221993db446aSBoris Brezillon 	ret = submit_descs(nandc);
222093db446aSBoris Brezillon 	if (ret) {
222193db446aSBoris Brezillon 		dev_err(nandc->dev, "failure to update BBM\n");
2222dcd1e618SManivannan Sadhasivam 		return ret;
222393db446aSBoris Brezillon 	}
222493db446aSBoris Brezillon 
222593db446aSBoris Brezillon 	return nand_prog_page_end_op(chip);
222693db446aSBoris Brezillon }
222793db446aSBoris Brezillon 
222893db446aSBoris Brezillon /*
222993db446aSBoris Brezillon  * NAND controller page layout info
223093db446aSBoris Brezillon  *
223193db446aSBoris Brezillon  * Layout with ECC enabled:
223293db446aSBoris Brezillon  *
223393db446aSBoris Brezillon  * |----------------------|  |---------------------------------|
223493db446aSBoris Brezillon  * |           xx.......yy|  |             *********xx.......yy|
223593db446aSBoris Brezillon  * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
223693db446aSBoris Brezillon  * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
223793db446aSBoris Brezillon  * |           xx.......yy|  |             *********xx.......yy|
223893db446aSBoris Brezillon  * |----------------------|  |---------------------------------|
223993db446aSBoris Brezillon  *     codeword 1,2..n-1                  codeword n
224093db446aSBoris Brezillon  *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
224193db446aSBoris Brezillon  *
224293db446aSBoris Brezillon  * n = Number of codewords in the page
224393db446aSBoris Brezillon  * . = ECC bytes
224493db446aSBoris Brezillon  * * = Spare/free bytes
224593db446aSBoris Brezillon  * x = Unused byte(s)
224693db446aSBoris Brezillon  * y = Reserved byte(s)
224793db446aSBoris Brezillon  *
224893db446aSBoris Brezillon  * 2K page: n = 4, spare = 16 bytes
224993db446aSBoris Brezillon  * 4K page: n = 8, spare = 32 bytes
225093db446aSBoris Brezillon  * 8K page: n = 16, spare = 64 bytes
225193db446aSBoris Brezillon  *
225293db446aSBoris Brezillon  * the qcom nand controller operates at a sub page/codeword level. each
225393db446aSBoris Brezillon  * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
225493db446aSBoris Brezillon  * the number of ECC bytes vary based on the ECC strength and the bus width.
225593db446aSBoris Brezillon  *
225693db446aSBoris Brezillon  * the first n - 1 codewords contains 516 bytes of user data, the remaining
225793db446aSBoris Brezillon  * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
225893db446aSBoris Brezillon  * both user data and spare(oobavail) bytes that sum up to 516 bytes.
225993db446aSBoris Brezillon  *
226093db446aSBoris Brezillon  * When we access a page with ECC enabled, the reserved bytes(s) are not
226193db446aSBoris Brezillon  * accessible at all. When reading, we fill up these unreadable positions
226293db446aSBoris Brezillon  * with 0xffs. When writing, the controller skips writing the inaccessible
226393db446aSBoris Brezillon  * bytes.
226493db446aSBoris Brezillon  *
226593db446aSBoris Brezillon  * Layout with ECC disabled:
226693db446aSBoris Brezillon  *
226793db446aSBoris Brezillon  * |------------------------------|  |---------------------------------------|
226893db446aSBoris Brezillon  * |         yy          xx.......|  |         bb          *********xx.......|
226993db446aSBoris Brezillon  * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
227093db446aSBoris Brezillon  * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
227193db446aSBoris Brezillon  * |         yy          xx.......|  |         bb          *********xx.......|
227293db446aSBoris Brezillon  * |------------------------------|  |---------------------------------------|
227393db446aSBoris Brezillon  *         codeword 1,2..n-1                        codeword n
227493db446aSBoris Brezillon  *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
227593db446aSBoris Brezillon  *
227693db446aSBoris Brezillon  * n = Number of codewords in the page
227793db446aSBoris Brezillon  * . = ECC bytes
227893db446aSBoris Brezillon  * * = Spare/free bytes
227993db446aSBoris Brezillon  * x = Unused byte(s)
228093db446aSBoris Brezillon  * y = Dummy Bad Bock byte(s)
228193db446aSBoris Brezillon  * b = Real Bad Block byte(s)
228293db446aSBoris Brezillon  * size1/size2 = function of codeword size and 'n'
228393db446aSBoris Brezillon  *
228493db446aSBoris Brezillon  * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
228593db446aSBoris Brezillon  * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
228693db446aSBoris Brezillon  * Block Markers. In the last codeword, this position contains the real BBM
228793db446aSBoris Brezillon  *
228893db446aSBoris Brezillon  * In order to have a consistent layout between RAW and ECC modes, we assume
228993db446aSBoris Brezillon  * the following OOB layout arrangement:
229093db446aSBoris Brezillon  *
229193db446aSBoris Brezillon  * |-----------|  |--------------------|
229293db446aSBoris Brezillon  * |yyxx.......|  |bb*********xx.......|
229393db446aSBoris Brezillon  * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
229493db446aSBoris Brezillon  * |yyxx.......|  |bb*********xx.......|
229593db446aSBoris Brezillon  * |yyxx.......|  |bb*********xx.......|
229693db446aSBoris Brezillon  * |-----------|  |--------------------|
229793db446aSBoris Brezillon  *  first n - 1       nth OOB region
229893db446aSBoris Brezillon  *  OOB regions
229993db446aSBoris Brezillon  *
230093db446aSBoris Brezillon  * n = Number of codewords in the page
230193db446aSBoris Brezillon  * . = ECC bytes
230293db446aSBoris Brezillon  * * = FREE OOB bytes
230393db446aSBoris Brezillon  * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
230493db446aSBoris Brezillon  * x = Unused byte(s)
230593db446aSBoris Brezillon  * b = Real bad block byte(s) (inaccessible when ECC enabled)
230693db446aSBoris Brezillon  *
230793db446aSBoris Brezillon  * This layout is read as is when ECC is disabled. When ECC is enabled, the
230893db446aSBoris Brezillon  * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
230993db446aSBoris Brezillon  * and assumed as 0xffs when we read a page/oob. The ECC, unused and
231093db446aSBoris Brezillon  * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
231193db446aSBoris Brezillon  * the sum of the three).
231293db446aSBoris Brezillon  */
qcom_nand_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)231393db446aSBoris Brezillon static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
231493db446aSBoris Brezillon 				   struct mtd_oob_region *oobregion)
231593db446aSBoris Brezillon {
231693db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
231793db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
231893db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
231993db446aSBoris Brezillon 
232093db446aSBoris Brezillon 	if (section > 1)
232193db446aSBoris Brezillon 		return -ERANGE;
232293db446aSBoris Brezillon 
232393db446aSBoris Brezillon 	if (!section) {
232493db446aSBoris Brezillon 		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
232593db446aSBoris Brezillon 				    host->bbm_size;
232693db446aSBoris Brezillon 		oobregion->offset = 0;
232793db446aSBoris Brezillon 	} else {
232893db446aSBoris Brezillon 		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
232993db446aSBoris Brezillon 		oobregion->offset = mtd->oobsize - oobregion->length;
233093db446aSBoris Brezillon 	}
233193db446aSBoris Brezillon 
233293db446aSBoris Brezillon 	return 0;
233393db446aSBoris Brezillon }
233493db446aSBoris Brezillon 
qcom_nand_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)233593db446aSBoris Brezillon static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
233693db446aSBoris Brezillon 				    struct mtd_oob_region *oobregion)
233793db446aSBoris Brezillon {
233893db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
233993db446aSBoris Brezillon 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
234093db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
234193db446aSBoris Brezillon 
234293db446aSBoris Brezillon 	if (section)
234393db446aSBoris Brezillon 		return -ERANGE;
234493db446aSBoris Brezillon 
234593db446aSBoris Brezillon 	oobregion->length = ecc->steps * 4;
234693db446aSBoris Brezillon 	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
234793db446aSBoris Brezillon 
234893db446aSBoris Brezillon 	return 0;
234993db446aSBoris Brezillon }
235093db446aSBoris Brezillon 
235193db446aSBoris Brezillon static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
235293db446aSBoris Brezillon 	.ecc = qcom_nand_ooblayout_ecc,
235393db446aSBoris Brezillon 	.free = qcom_nand_ooblayout_free,
235493db446aSBoris Brezillon };
235593db446aSBoris Brezillon 
23567ddb937fSAbhishek Sahu static int
qcom_nandc_calc_ecc_bytes(int step_size,int strength)23577ddb937fSAbhishek Sahu qcom_nandc_calc_ecc_bytes(int step_size, int strength)
23587ddb937fSAbhishek Sahu {
23597ddb937fSAbhishek Sahu 	return strength == 4 ? 12 : 16;
23607ddb937fSAbhishek Sahu }
23613b645b38SMiquel Raynal 
23627ddb937fSAbhishek Sahu NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
23637ddb937fSAbhishek Sahu 		     NANDC_STEP_SIZE, 4, 8);
23647ddb937fSAbhishek Sahu 
qcom_nand_attach_chip(struct nand_chip * chip)23656a3cec64SMiquel Raynal static int qcom_nand_attach_chip(struct nand_chip *chip)
236693db446aSBoris Brezillon {
236793db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
23686a3cec64SMiquel Raynal 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
236993db446aSBoris Brezillon 	struct nand_ecc_ctrl *ecc = &chip->ecc;
237093db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
23717ddb937fSAbhishek Sahu 	int cwperpage, bad_block_byte, ret;
237293db446aSBoris Brezillon 	bool wide_bus;
237393db446aSBoris Brezillon 	int ecc_mode = 1;
237493db446aSBoris Brezillon 
2375320bdb5fSAbhishek Sahu 	/* controller only supports 512 bytes data steps */
2376320bdb5fSAbhishek Sahu 	ecc->size = NANDC_STEP_SIZE;
237793db446aSBoris Brezillon 	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
23787ddb937fSAbhishek Sahu 	cwperpage = mtd->writesize / NANDC_STEP_SIZE;
23797ddb937fSAbhishek Sahu 
23807ddb937fSAbhishek Sahu 	/*
23817ddb937fSAbhishek Sahu 	 * Each CW has 4 available OOB bytes which will be protected with ECC
23827ddb937fSAbhishek Sahu 	 * so remaining bytes can be used for ECC.
23837ddb937fSAbhishek Sahu 	 */
23847ddb937fSAbhishek Sahu 	ret = nand_ecc_choose_conf(chip, &qcom_nandc_ecc_caps,
23857ddb937fSAbhishek Sahu 				   mtd->oobsize - (cwperpage * 4));
23867ddb937fSAbhishek Sahu 	if (ret) {
23877ddb937fSAbhishek Sahu 		dev_err(nandc->dev, "No valid ECC settings possible\n");
23887ddb937fSAbhishek Sahu 		return ret;
23897ddb937fSAbhishek Sahu 	}
239093db446aSBoris Brezillon 
239193db446aSBoris Brezillon 	if (ecc->strength >= 8) {
239293db446aSBoris Brezillon 		/* 8 bit ECC defaults to BCH ECC on all platforms */
239393db446aSBoris Brezillon 		host->bch_enabled = true;
239493db446aSBoris Brezillon 		ecc_mode = 1;
239593db446aSBoris Brezillon 
239693db446aSBoris Brezillon 		if (wide_bus) {
239793db446aSBoris Brezillon 			host->ecc_bytes_hw = 14;
239893db446aSBoris Brezillon 			host->spare_bytes = 0;
239993db446aSBoris Brezillon 			host->bbm_size = 2;
240093db446aSBoris Brezillon 		} else {
240193db446aSBoris Brezillon 			host->ecc_bytes_hw = 13;
240293db446aSBoris Brezillon 			host->spare_bytes = 2;
240393db446aSBoris Brezillon 			host->bbm_size = 1;
240493db446aSBoris Brezillon 		}
240593db446aSBoris Brezillon 	} else {
240693db446aSBoris Brezillon 		/*
240793db446aSBoris Brezillon 		 * if the controller supports BCH for 4 bit ECC, the controller
240893db446aSBoris Brezillon 		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
240993db446aSBoris Brezillon 		 * always 10 bytes
241093db446aSBoris Brezillon 		 */
241193db446aSBoris Brezillon 		if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
241293db446aSBoris Brezillon 			/* BCH */
241393db446aSBoris Brezillon 			host->bch_enabled = true;
241493db446aSBoris Brezillon 			ecc_mode = 0;
241593db446aSBoris Brezillon 
241693db446aSBoris Brezillon 			if (wide_bus) {
241793db446aSBoris Brezillon 				host->ecc_bytes_hw = 8;
241893db446aSBoris Brezillon 				host->spare_bytes = 2;
241993db446aSBoris Brezillon 				host->bbm_size = 2;
242093db446aSBoris Brezillon 			} else {
242193db446aSBoris Brezillon 				host->ecc_bytes_hw = 7;
242293db446aSBoris Brezillon 				host->spare_bytes = 4;
242393db446aSBoris Brezillon 				host->bbm_size = 1;
242493db446aSBoris Brezillon 			}
242593db446aSBoris Brezillon 		} else {
242693db446aSBoris Brezillon 			/* RS */
242793db446aSBoris Brezillon 			host->ecc_bytes_hw = 10;
242893db446aSBoris Brezillon 
242993db446aSBoris Brezillon 			if (wide_bus) {
243093db446aSBoris Brezillon 				host->spare_bytes = 0;
243193db446aSBoris Brezillon 				host->bbm_size = 2;
243293db446aSBoris Brezillon 			} else {
243393db446aSBoris Brezillon 				host->spare_bytes = 1;
243493db446aSBoris Brezillon 				host->bbm_size = 1;
243593db446aSBoris Brezillon 			}
243693db446aSBoris Brezillon 		}
243793db446aSBoris Brezillon 	}
243893db446aSBoris Brezillon 
243993db446aSBoris Brezillon 	/*
244093db446aSBoris Brezillon 	 * we consider ecc->bytes as the sum of all the non-data content in a
244193db446aSBoris Brezillon 	 * step. It gives us a clean representation of the oob area (even if
244293db446aSBoris Brezillon 	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
244393db446aSBoris Brezillon 	 * ECC and 12 bytes for 4 bit ECC
244493db446aSBoris Brezillon 	 */
244593db446aSBoris Brezillon 	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
244693db446aSBoris Brezillon 
244793db446aSBoris Brezillon 	ecc->read_page		= qcom_nandc_read_page;
244893db446aSBoris Brezillon 	ecc->read_page_raw	= qcom_nandc_read_page_raw;
244993db446aSBoris Brezillon 	ecc->read_oob		= qcom_nandc_read_oob;
245093db446aSBoris Brezillon 	ecc->write_page		= qcom_nandc_write_page;
245193db446aSBoris Brezillon 	ecc->write_page_raw	= qcom_nandc_write_page_raw;
245293db446aSBoris Brezillon 	ecc->write_oob		= qcom_nandc_write_oob;
245393db446aSBoris Brezillon 
2454bace41f8SMiquel Raynal 	ecc->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
245593db446aSBoris Brezillon 
245693db446aSBoris Brezillon 	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
2457ba7542ebSMd Sadre Alam 	/* Free the initially allocated BAM transaction for reading the ONFI params */
2458ba7542ebSMd Sadre Alam 	if (nandc->props->is_bam)
2459ba7542ebSMd Sadre Alam 		free_bam_transaction(nandc);
246093db446aSBoris Brezillon 
246193db446aSBoris Brezillon 	nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
246293db446aSBoris Brezillon 				     cwperpage);
246393db446aSBoris Brezillon 
2464ba7542ebSMd Sadre Alam 	/* Now allocate the BAM transaction based on updated max_cwperpage */
2465ba7542ebSMd Sadre Alam 	if (nandc->props->is_bam) {
2466ba7542ebSMd Sadre Alam 		nandc->bam_txn = alloc_bam_transaction(nandc);
2467ba7542ebSMd Sadre Alam 		if (!nandc->bam_txn) {
2468ba7542ebSMd Sadre Alam 			dev_err(nandc->dev,
2469ba7542ebSMd Sadre Alam 				"failed to allocate bam transaction\n");
2470ba7542ebSMd Sadre Alam 			return -ENOMEM;
2471ba7542ebSMd Sadre Alam 		}
2472ba7542ebSMd Sadre Alam 	}
2473ba7542ebSMd Sadre Alam 
247493db446aSBoris Brezillon 	/*
247593db446aSBoris Brezillon 	 * DATA_UD_BYTES varies based on whether the read/write command protects
247693db446aSBoris Brezillon 	 * spare data with ECC too. We protect spare data by default, so we set
247793db446aSBoris Brezillon 	 * it to main + spare data, which are 512 and 4 bytes respectively.
247893db446aSBoris Brezillon 	 */
247993db446aSBoris Brezillon 	host->cw_data = 516;
248093db446aSBoris Brezillon 
248193db446aSBoris Brezillon 	/*
248293db446aSBoris Brezillon 	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
248393db446aSBoris Brezillon 	 * for 8 bit ECC
248493db446aSBoris Brezillon 	 */
248593db446aSBoris Brezillon 	host->cw_size = host->cw_data + ecc->bytes;
248693db446aSBoris Brezillon 	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
248793db446aSBoris Brezillon 
248893db446aSBoris Brezillon 	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
248993db446aSBoris Brezillon 				| host->cw_data << UD_SIZE_BYTES
249093db446aSBoris Brezillon 				| 0 << DISABLE_STATUS_AFTER_WRITE
249193db446aSBoris Brezillon 				| 5 << NUM_ADDR_CYCLES
249293db446aSBoris Brezillon 				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
249393db446aSBoris Brezillon 				| 0 << STATUS_BFR_READ
249493db446aSBoris Brezillon 				| 1 << SET_RD_MODE_AFTER_STATUS
249593db446aSBoris Brezillon 				| host->spare_bytes << SPARE_SIZE_BYTES;
249693db446aSBoris Brezillon 
249793db446aSBoris Brezillon 	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
249893db446aSBoris Brezillon 				| 0 <<  CS_ACTIVE_BSY
249993db446aSBoris Brezillon 				| bad_block_byte << BAD_BLOCK_BYTE_NUM
250093db446aSBoris Brezillon 				| 0 << BAD_BLOCK_IN_SPARE_AREA
250193db446aSBoris Brezillon 				| 2 << WR_RD_BSY_GAP
250293db446aSBoris Brezillon 				| wide_bus << WIDE_FLASH
250393db446aSBoris Brezillon 				| host->bch_enabled << ENABLE_BCH_ECC;
250493db446aSBoris Brezillon 
250593db446aSBoris Brezillon 	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
250693db446aSBoris Brezillon 				| host->cw_size << UD_SIZE_BYTES
250793db446aSBoris Brezillon 				| 5 << NUM_ADDR_CYCLES
250893db446aSBoris Brezillon 				| 0 << SPARE_SIZE_BYTES;
250993db446aSBoris Brezillon 
251093db446aSBoris Brezillon 	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
251193db446aSBoris Brezillon 				| 0 << CS_ACTIVE_BSY
251293db446aSBoris Brezillon 				| 17 << BAD_BLOCK_BYTE_NUM
251393db446aSBoris Brezillon 				| 1 << BAD_BLOCK_IN_SPARE_AREA
251493db446aSBoris Brezillon 				| 2 << WR_RD_BSY_GAP
251593db446aSBoris Brezillon 				| wide_bus << WIDE_FLASH
251693db446aSBoris Brezillon 				| 1 << DEV0_CFG1_ECC_DISABLE;
251793db446aSBoris Brezillon 
251893db446aSBoris Brezillon 	host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
251993db446aSBoris Brezillon 				| 0 << ECC_SW_RESET
252093db446aSBoris Brezillon 				| host->cw_data << ECC_NUM_DATA_BYTES
252193db446aSBoris Brezillon 				| 1 << ECC_FORCE_CLK_OPEN
252293db446aSBoris Brezillon 				| ecc_mode << ECC_MODE
252393db446aSBoris Brezillon 				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
252493db446aSBoris Brezillon 
2525bfb34eceSMd Sadre Alam 	if (!nandc->props->qpic_v2)
252693db446aSBoris Brezillon 		host->ecc_buf_cfg = 0x203 << NUM_STEPS;
252793db446aSBoris Brezillon 
252893db446aSBoris Brezillon 	host->clrflashstatus = FS_READY_BSY_N;
252993db446aSBoris Brezillon 	host->clrreadstatus = 0xc0;
253093db446aSBoris Brezillon 	nandc->regs->erased_cw_detect_cfg_clr =
253193db446aSBoris Brezillon 		cpu_to_le32(CLR_ERASED_PAGE_DET);
253293db446aSBoris Brezillon 	nandc->regs->erased_cw_detect_cfg_set =
253393db446aSBoris Brezillon 		cpu_to_le32(SET_ERASED_PAGE_DET);
253493db446aSBoris Brezillon 
253593db446aSBoris Brezillon 	dev_dbg(nandc->dev,
253693db446aSBoris Brezillon 		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
253793db446aSBoris Brezillon 		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
253893db446aSBoris Brezillon 		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
253993db446aSBoris Brezillon 		cwperpage);
254093db446aSBoris Brezillon 
254193db446aSBoris Brezillon 	return 0;
254293db446aSBoris Brezillon }
254393db446aSBoris Brezillon 
qcom_op_cmd_mapping(struct nand_chip * chip,u8 opcode,struct qcom_op * q_op)2544a82990c8SSricharan Ramabadhran static int qcom_op_cmd_mapping(struct nand_chip *chip, u8 opcode,
254589550bebSMd Sadre Alam 			       struct qcom_op *q_op)
254689550bebSMd Sadre Alam {
2547a82990c8SSricharan Ramabadhran 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
2548a82990c8SSricharan Ramabadhran 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
2549d68b7e5fSManivannan Sadhasivam 	int cmd;
255089550bebSMd Sadre Alam 
2551d68b7e5fSManivannan Sadhasivam 	switch (opcode) {
255289550bebSMd Sadre Alam 	case NAND_CMD_RESET:
2553d68b7e5fSManivannan Sadhasivam 		cmd = OP_RESET_DEVICE;
255489550bebSMd Sadre Alam 		break;
255589550bebSMd Sadre Alam 	case NAND_CMD_READID:
2556d68b7e5fSManivannan Sadhasivam 		cmd = OP_FETCH_ID;
255789550bebSMd Sadre Alam 		break;
255889550bebSMd Sadre Alam 	case NAND_CMD_PARAM:
255989550bebSMd Sadre Alam 		if (nandc->props->qpic_v2)
2560d68b7e5fSManivannan Sadhasivam 			cmd = OP_PAGE_READ_ONFI_READ;
256189550bebSMd Sadre Alam 		else
2562d68b7e5fSManivannan Sadhasivam 			cmd = OP_PAGE_READ;
256389550bebSMd Sadre Alam 		break;
256489550bebSMd Sadre Alam 	case NAND_CMD_ERASE1:
256589550bebSMd Sadre Alam 	case NAND_CMD_ERASE2:
2566d68b7e5fSManivannan Sadhasivam 		cmd = OP_BLOCK_ERASE;
256789550bebSMd Sadre Alam 		break;
256889550bebSMd Sadre Alam 	case NAND_CMD_STATUS:
2569d68b7e5fSManivannan Sadhasivam 		cmd = OP_CHECK_STATUS;
257089550bebSMd Sadre Alam 		break;
257189550bebSMd Sadre Alam 	case NAND_CMD_PAGEPROG:
2572d68b7e5fSManivannan Sadhasivam 		cmd = OP_PROGRAM_PAGE;
257389550bebSMd Sadre Alam 		q_op->flag = OP_PROGRAM_PAGE;
257489550bebSMd Sadre Alam 		nandc->exec_opwrite = true;
257589550bebSMd Sadre Alam 		break;
2576a82990c8SSricharan Ramabadhran 	case NAND_CMD_READ0:
2577a82990c8SSricharan Ramabadhran 	case NAND_CMD_READSTART:
2578a82990c8SSricharan Ramabadhran 		if (host->use_ecc)
2579a82990c8SSricharan Ramabadhran 			cmd = OP_PAGE_READ_WITH_ECC;
2580a82990c8SSricharan Ramabadhran 		else
2581a82990c8SSricharan Ramabadhran 			cmd = OP_PAGE_READ;
2582a82990c8SSricharan Ramabadhran 		break;
2583dd3c8f4aSManivannan Sadhasivam 	default:
2584dd3c8f4aSManivannan Sadhasivam 		dev_err(nandc->dev, "Opcode not supported: %u\n", opcode);
2585dd3c8f4aSManivannan Sadhasivam 		return -EOPNOTSUPP;
258689550bebSMd Sadre Alam 	}
258789550bebSMd Sadre Alam 
2588d68b7e5fSManivannan Sadhasivam 	return cmd;
258989550bebSMd Sadre Alam }
259089550bebSMd Sadre Alam 
259189550bebSMd Sadre Alam /* NAND framework ->exec_op() hooks and related helpers */
qcom_parse_instructions(struct nand_chip * chip,const struct nand_subop * subop,struct qcom_op * q_op)2592dd3c8f4aSManivannan Sadhasivam static int qcom_parse_instructions(struct nand_chip *chip,
259389550bebSMd Sadre Alam 				    const struct nand_subop *subop,
259489550bebSMd Sadre Alam 				    struct qcom_op *q_op)
259589550bebSMd Sadre Alam {
259689550bebSMd Sadre Alam 	const struct nand_op_instr *instr = NULL;
259789550bebSMd Sadre Alam 	unsigned int op_id;
2598dd3c8f4aSManivannan Sadhasivam 	int i, ret;
259989550bebSMd Sadre Alam 
260089550bebSMd Sadre Alam 	for (op_id = 0; op_id < subop->ninstrs; op_id++) {
260189550bebSMd Sadre Alam 		unsigned int offset, naddrs;
260289550bebSMd Sadre Alam 		const u8 *addrs;
260389550bebSMd Sadre Alam 
260489550bebSMd Sadre Alam 		instr = &subop->instrs[op_id];
260589550bebSMd Sadre Alam 
260689550bebSMd Sadre Alam 		switch (instr->type) {
260789550bebSMd Sadre Alam 		case NAND_OP_CMD_INSTR:
2608a82990c8SSricharan Ramabadhran 			ret = qcom_op_cmd_mapping(chip, instr->ctx.cmd.opcode, q_op);
2609dd3c8f4aSManivannan Sadhasivam 			if (ret < 0)
2610dd3c8f4aSManivannan Sadhasivam 				return ret;
2611dd3c8f4aSManivannan Sadhasivam 
2612dd3c8f4aSManivannan Sadhasivam 			q_op->cmd_reg = ret;
261389550bebSMd Sadre Alam 			q_op->rdy_delay_ns = instr->delay_ns;
261489550bebSMd Sadre Alam 			break;
261589550bebSMd Sadre Alam 
261689550bebSMd Sadre Alam 		case NAND_OP_ADDR_INSTR:
261789550bebSMd Sadre Alam 			offset = nand_subop_get_addr_start_off(subop, op_id);
261889550bebSMd Sadre Alam 			naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
261989550bebSMd Sadre Alam 			addrs = &instr->ctx.addr.addrs[offset];
2620e2532429SMiquel Raynal 
2621e2532429SMiquel Raynal 			for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
2622e2532429SMiquel Raynal 				q_op->addr1_reg |= addrs[i] << (i * 8);
2623e2532429SMiquel Raynal 
2624e2532429SMiquel Raynal 			if (naddrs > 4)
2625e2532429SMiquel Raynal 				q_op->addr2_reg |= addrs[4];
2626e2532429SMiquel Raynal 
262789550bebSMd Sadre Alam 			q_op->rdy_delay_ns = instr->delay_ns;
262889550bebSMd Sadre Alam 			break;
262989550bebSMd Sadre Alam 
263089550bebSMd Sadre Alam 		case NAND_OP_DATA_IN_INSTR:
263189550bebSMd Sadre Alam 			q_op->data_instr = instr;
263289550bebSMd Sadre Alam 			q_op->data_instr_idx = op_id;
263389550bebSMd Sadre Alam 			q_op->rdy_delay_ns = instr->delay_ns;
263489550bebSMd Sadre Alam 			fallthrough;
263589550bebSMd Sadre Alam 		case NAND_OP_DATA_OUT_INSTR:
263689550bebSMd Sadre Alam 			q_op->rdy_delay_ns = instr->delay_ns;
263789550bebSMd Sadre Alam 			break;
263889550bebSMd Sadre Alam 
263989550bebSMd Sadre Alam 		case NAND_OP_WAITRDY_INSTR:
264089550bebSMd Sadre Alam 			q_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
264189550bebSMd Sadre Alam 			q_op->rdy_delay_ns = instr->delay_ns;
264289550bebSMd Sadre Alam 			break;
264389550bebSMd Sadre Alam 		}
264489550bebSMd Sadre Alam 	}
2645dd3c8f4aSManivannan Sadhasivam 
2646dd3c8f4aSManivannan Sadhasivam 	return 0;
264789550bebSMd Sadre Alam }
264889550bebSMd Sadre Alam 
qcom_delay_ns(unsigned int ns)264989550bebSMd Sadre Alam static void qcom_delay_ns(unsigned int ns)
265089550bebSMd Sadre Alam {
265189550bebSMd Sadre Alam 	if (!ns)
265289550bebSMd Sadre Alam 		return;
265389550bebSMd Sadre Alam 
265489550bebSMd Sadre Alam 	if (ns < 10000)
265589550bebSMd Sadre Alam 		ndelay(ns);
265689550bebSMd Sadre Alam 	else
265789550bebSMd Sadre Alam 		udelay(DIV_ROUND_UP(ns, 1000));
265889550bebSMd Sadre Alam }
265989550bebSMd Sadre Alam 
qcom_wait_rdy_poll(struct nand_chip * chip,unsigned int time_ms)266089550bebSMd Sadre Alam static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms)
266189550bebSMd Sadre Alam {
266289550bebSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
266389550bebSMd Sadre Alam 	unsigned long start = jiffies + msecs_to_jiffies(time_ms);
266489550bebSMd Sadre Alam 	u32 flash;
266589550bebSMd Sadre Alam 
266689550bebSMd Sadre Alam 	nandc_read_buffer_sync(nandc, true);
266789550bebSMd Sadre Alam 
266889550bebSMd Sadre Alam 	do {
266989550bebSMd Sadre Alam 		flash = le32_to_cpu(nandc->reg_read_buf[0]);
267089550bebSMd Sadre Alam 		if (flash & FS_READY_BSY_N)
267189550bebSMd Sadre Alam 			return 0;
267289550bebSMd Sadre Alam 		cpu_relax();
267389550bebSMd Sadre Alam 	} while (time_after(start, jiffies));
267489550bebSMd Sadre Alam 
267589550bebSMd Sadre Alam 	dev_err(nandc->dev, "Timeout waiting for device to be ready:0x%08x\n", flash);
267689550bebSMd Sadre Alam 
267789550bebSMd Sadre Alam 	return -ETIMEDOUT;
267889550bebSMd Sadre Alam }
267989550bebSMd Sadre Alam 
qcom_read_status_exec(struct nand_chip * chip,const struct nand_subop * subop)268089550bebSMd Sadre Alam static int qcom_read_status_exec(struct nand_chip *chip,
268189550bebSMd Sadre Alam 				 const struct nand_subop *subop)
268289550bebSMd Sadre Alam {
268389550bebSMd Sadre Alam 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
268489550bebSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
268589550bebSMd Sadre Alam 	struct nand_ecc_ctrl *ecc = &chip->ecc;
2686e260efeaSMiquel Raynal 	struct qcom_op q_op = {};
268789550bebSMd Sadre Alam 	const struct nand_op_instr *instr = NULL;
268889550bebSMd Sadre Alam 	unsigned int op_id = 0;
268989550bebSMd Sadre Alam 	unsigned int len = 0;
2690847178feSManivannan Sadhasivam 	int ret, num_cw, i;
269189550bebSMd Sadre Alam 	u32 flash_status;
269289550bebSMd Sadre Alam 
269389550bebSMd Sadre Alam 	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
269489550bebSMd Sadre Alam 
2695dd3c8f4aSManivannan Sadhasivam 	ret = qcom_parse_instructions(chip, subop, &q_op);
2696dd3c8f4aSManivannan Sadhasivam 	if (ret)
2697dd3c8f4aSManivannan Sadhasivam 		return ret;
269889550bebSMd Sadre Alam 
269989550bebSMd Sadre Alam 	num_cw = nandc->exec_opwrite ? ecc->steps : 1;
270089550bebSMd Sadre Alam 	nandc->exec_opwrite = false;
270189550bebSMd Sadre Alam 
270289550bebSMd Sadre Alam 	nandc->buf_count = 0;
270389550bebSMd Sadre Alam 	nandc->buf_start = 0;
270489550bebSMd Sadre Alam 	host->use_ecc = false;
270589550bebSMd Sadre Alam 
270689550bebSMd Sadre Alam 	clear_read_regs(nandc);
270789550bebSMd Sadre Alam 	clear_bam_transaction(nandc);
270889550bebSMd Sadre Alam 
270989550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
271089550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
271189550bebSMd Sadre Alam 
271289550bebSMd Sadre Alam 	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
271389550bebSMd Sadre Alam 	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
271489550bebSMd Sadre Alam 	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
271589550bebSMd Sadre Alam 
271689550bebSMd Sadre Alam 	ret = submit_descs(nandc);
271789550bebSMd Sadre Alam 	if (ret) {
271889550bebSMd Sadre Alam 		dev_err(nandc->dev, "failure in submitting status descriptor\n");
271989550bebSMd Sadre Alam 		goto err_out;
272089550bebSMd Sadre Alam 	}
272189550bebSMd Sadre Alam 
272289550bebSMd Sadre Alam 	nandc_read_buffer_sync(nandc, true);
272389550bebSMd Sadre Alam 
272489550bebSMd Sadre Alam 	for (i = 0; i < num_cw; i++) {
272589550bebSMd Sadre Alam 		flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
272689550bebSMd Sadre Alam 
272789550bebSMd Sadre Alam 		if (flash_status & FS_MPU_ERR)
272889550bebSMd Sadre Alam 			host->status &= ~NAND_STATUS_WP;
272989550bebSMd Sadre Alam 
273089550bebSMd Sadre Alam 		if (flash_status & FS_OP_ERR ||
273189550bebSMd Sadre Alam 		    (i == (num_cw - 1) && (flash_status & FS_DEVICE_STS_ERR)))
273289550bebSMd Sadre Alam 			host->status |= NAND_STATUS_FAIL;
273389550bebSMd Sadre Alam 	}
273489550bebSMd Sadre Alam 
273589550bebSMd Sadre Alam 	flash_status = host->status;
273689550bebSMd Sadre Alam 	instr = q_op.data_instr;
273789550bebSMd Sadre Alam 	op_id = q_op.data_instr_idx;
273889550bebSMd Sadre Alam 	len = nand_subop_get_data_len(subop, op_id);
273989550bebSMd Sadre Alam 	memcpy(instr->ctx.data.buf.in, &flash_status, len);
274089550bebSMd Sadre Alam 
274189550bebSMd Sadre Alam err_out:
274289550bebSMd Sadre Alam 	return ret;
274389550bebSMd Sadre Alam }
274489550bebSMd Sadre Alam 
qcom_read_id_type_exec(struct nand_chip * chip,const struct nand_subop * subop)274589550bebSMd Sadre Alam static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop)
274689550bebSMd Sadre Alam {
274789550bebSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
274889550bebSMd Sadre Alam 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
2749e260efeaSMiquel Raynal 	struct qcom_op q_op = {};
275089550bebSMd Sadre Alam 	const struct nand_op_instr *instr = NULL;
275189550bebSMd Sadre Alam 	unsigned int op_id = 0;
275289550bebSMd Sadre Alam 	unsigned int len = 0;
2753847178feSManivannan Sadhasivam 	int ret;
275489550bebSMd Sadre Alam 
2755dd3c8f4aSManivannan Sadhasivam 	ret = qcom_parse_instructions(chip, subop, &q_op);
2756dd3c8f4aSManivannan Sadhasivam 	if (ret)
2757dd3c8f4aSManivannan Sadhasivam 		return ret;
275889550bebSMd Sadre Alam 
275989550bebSMd Sadre Alam 	nandc->buf_count = 0;
276089550bebSMd Sadre Alam 	nandc->buf_start = 0;
276189550bebSMd Sadre Alam 	host->use_ecc = false;
276289550bebSMd Sadre Alam 
276389550bebSMd Sadre Alam 	clear_read_regs(nandc);
276489550bebSMd Sadre Alam 	clear_bam_transaction(nandc);
276589550bebSMd Sadre Alam 
276689550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
276789550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
276889550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
276989550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
277089550bebSMd Sadre Alam 		      nandc->props->is_bam ? 0 : DM_EN);
277189550bebSMd Sadre Alam 
277289550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
277389550bebSMd Sadre Alam 
277489550bebSMd Sadre Alam 	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
277589550bebSMd Sadre Alam 	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
277689550bebSMd Sadre Alam 
277789550bebSMd Sadre Alam 	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
277889550bebSMd Sadre Alam 
277989550bebSMd Sadre Alam 	ret = submit_descs(nandc);
278089550bebSMd Sadre Alam 	if (ret) {
278189550bebSMd Sadre Alam 		dev_err(nandc->dev, "failure in submitting read id descriptor\n");
278289550bebSMd Sadre Alam 		goto err_out;
278389550bebSMd Sadre Alam 	}
278489550bebSMd Sadre Alam 
278589550bebSMd Sadre Alam 	instr = q_op.data_instr;
278689550bebSMd Sadre Alam 	op_id = q_op.data_instr_idx;
278789550bebSMd Sadre Alam 	len = nand_subop_get_data_len(subop, op_id);
278889550bebSMd Sadre Alam 
278989550bebSMd Sadre Alam 	nandc_read_buffer_sync(nandc, true);
279089550bebSMd Sadre Alam 	memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
279189550bebSMd Sadre Alam 
279289550bebSMd Sadre Alam err_out:
279389550bebSMd Sadre Alam 	return ret;
279489550bebSMd Sadre Alam }
279589550bebSMd Sadre Alam 
qcom_misc_cmd_type_exec(struct nand_chip * chip,const struct nand_subop * subop)279689550bebSMd Sadre Alam static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop)
279789550bebSMd Sadre Alam {
279889550bebSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
279989550bebSMd Sadre Alam 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
2800e260efeaSMiquel Raynal 	struct qcom_op q_op = {};
2801847178feSManivannan Sadhasivam 	int ret;
2802a82990c8SSricharan Ramabadhran 	int instrs = 1;
280389550bebSMd Sadre Alam 
2804dd3c8f4aSManivannan Sadhasivam 	ret = qcom_parse_instructions(chip, subop, &q_op);
2805dd3c8f4aSManivannan Sadhasivam 	if (ret)
2806dd3c8f4aSManivannan Sadhasivam 		return ret;
280789550bebSMd Sadre Alam 
2808a82990c8SSricharan Ramabadhran 	if (q_op.flag == OP_PROGRAM_PAGE) {
280989550bebSMd Sadre Alam 		goto wait_rdy;
2810a82990c8SSricharan Ramabadhran 	} else if (q_op.cmd_reg == OP_BLOCK_ERASE) {
2811a82990c8SSricharan Ramabadhran 		q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
2812a82990c8SSricharan Ramabadhran 		nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
2813a82990c8SSricharan Ramabadhran 		nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
2814a82990c8SSricharan Ramabadhran 		nandc_set_reg(chip, NAND_DEV0_CFG0,
2815a82990c8SSricharan Ramabadhran 			      host->cfg0_raw & ~(7 << CW_PER_PAGE));
2816a82990c8SSricharan Ramabadhran 		nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
2817a82990c8SSricharan Ramabadhran 		instrs = 3;
2818*87fc30dbSChristian Marangi 	} else if (q_op.cmd_reg != OP_RESET_DEVICE) {
2819a82990c8SSricharan Ramabadhran 		return 0;
2820a82990c8SSricharan Ramabadhran 	}
282189550bebSMd Sadre Alam 
282289550bebSMd Sadre Alam 	nandc->buf_count = 0;
282389550bebSMd Sadre Alam 	nandc->buf_start = 0;
282489550bebSMd Sadre Alam 	host->use_ecc = false;
282589550bebSMd Sadre Alam 
282689550bebSMd Sadre Alam 	clear_read_regs(nandc);
282789550bebSMd Sadre Alam 	clear_bam_transaction(nandc);
282889550bebSMd Sadre Alam 
282989550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
283089550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
283189550bebSMd Sadre Alam 
2832a82990c8SSricharan Ramabadhran 	write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
2833*87fc30dbSChristian Marangi 	if (q_op.cmd_reg == OP_BLOCK_ERASE)
2834*87fc30dbSChristian Marangi 		write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
283589550bebSMd Sadre Alam 
2836a82990c8SSricharan Ramabadhran 	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
283789550bebSMd Sadre Alam 	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
283889550bebSMd Sadre Alam 
283989550bebSMd Sadre Alam 	ret = submit_descs(nandc);
284089550bebSMd Sadre Alam 	if (ret) {
284189550bebSMd Sadre Alam 		dev_err(nandc->dev, "failure in submitting misc descriptor\n");
284289550bebSMd Sadre Alam 		goto err_out;
284389550bebSMd Sadre Alam 	}
284489550bebSMd Sadre Alam 
284589550bebSMd Sadre Alam wait_rdy:
284689550bebSMd Sadre Alam 	qcom_delay_ns(q_op.rdy_delay_ns);
284789550bebSMd Sadre Alam 	ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms);
284889550bebSMd Sadre Alam 
284989550bebSMd Sadre Alam err_out:
285089550bebSMd Sadre Alam 	return ret;
285189550bebSMd Sadre Alam }
285289550bebSMd Sadre Alam 
qcom_param_page_type_exec(struct nand_chip * chip,const struct nand_subop * subop)285389550bebSMd Sadre Alam static int qcom_param_page_type_exec(struct nand_chip *chip,  const struct nand_subop *subop)
285489550bebSMd Sadre Alam {
285589550bebSMd Sadre Alam 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
285689550bebSMd Sadre Alam 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
2857e260efeaSMiquel Raynal 	struct qcom_op q_op = {};
285889550bebSMd Sadre Alam 	const struct nand_op_instr *instr = NULL;
285989550bebSMd Sadre Alam 	unsigned int op_id = 0;
286089550bebSMd Sadre Alam 	unsigned int len = 0;
2861847178feSManivannan Sadhasivam 	int ret;
286289550bebSMd Sadre Alam 
2863dd3c8f4aSManivannan Sadhasivam 	ret = qcom_parse_instructions(chip, subop, &q_op);
2864dd3c8f4aSManivannan Sadhasivam 	if (ret)
2865dd3c8f4aSManivannan Sadhasivam 		return ret;
286689550bebSMd Sadre Alam 
286789550bebSMd Sadre Alam 	q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
286889550bebSMd Sadre Alam 
286989550bebSMd Sadre Alam 	nandc->buf_count = 0;
287089550bebSMd Sadre Alam 	nandc->buf_start = 0;
287189550bebSMd Sadre Alam 	host->use_ecc = false;
287289550bebSMd Sadre Alam 	clear_read_regs(nandc);
287389550bebSMd Sadre Alam 	clear_bam_transaction(nandc);
287489550bebSMd Sadre Alam 
287589550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
287689550bebSMd Sadre Alam 
287789550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR0, 0);
287889550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_ADDR1, 0);
287989550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
288089550bebSMd Sadre Alam 					| 512 << UD_SIZE_BYTES
288189550bebSMd Sadre Alam 					| 5 << NUM_ADDR_CYCLES
288289550bebSMd Sadre Alam 					| 0 << SPARE_SIZE_BYTES);
288389550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
288489550bebSMd Sadre Alam 					| 0 << CS_ACTIVE_BSY
288589550bebSMd Sadre Alam 					| 17 << BAD_BLOCK_BYTE_NUM
288689550bebSMd Sadre Alam 					| 1 << BAD_BLOCK_IN_SPARE_AREA
288789550bebSMd Sadre Alam 					| 2 << WR_RD_BSY_GAP
288889550bebSMd Sadre Alam 					| 0 << WIDE_FLASH
288989550bebSMd Sadre Alam 					| 1 << DEV0_CFG1_ECC_DISABLE);
289089550bebSMd Sadre Alam 	if (!nandc->props->qpic_v2)
289189550bebSMd Sadre Alam 		nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
289289550bebSMd Sadre Alam 
289389550bebSMd Sadre Alam 	/* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
289489550bebSMd Sadre Alam 	if (!nandc->props->qpic_v2) {
289589550bebSMd Sadre Alam 		nandc_set_reg(chip, NAND_DEV_CMD_VLD,
289689550bebSMd Sadre Alam 			      (nandc->vld & ~READ_START_VLD));
289789550bebSMd Sadre Alam 		nandc_set_reg(chip, NAND_DEV_CMD1,
289889550bebSMd Sadre Alam 			      (nandc->cmd1 & ~(0xFF << READ_ADDR))
289989550bebSMd Sadre Alam 			      | NAND_CMD_PARAM << READ_ADDR);
290089550bebSMd Sadre Alam 	}
290189550bebSMd Sadre Alam 
290289550bebSMd Sadre Alam 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
290389550bebSMd Sadre Alam 
290489550bebSMd Sadre Alam 	if (!nandc->props->qpic_v2) {
290589550bebSMd Sadre Alam 		nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
290689550bebSMd Sadre Alam 		nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
290789550bebSMd Sadre Alam 	}
290889550bebSMd Sadre Alam 
290989550bebSMd Sadre Alam 	instr = q_op.data_instr;
291089550bebSMd Sadre Alam 	op_id = q_op.data_instr_idx;
291189550bebSMd Sadre Alam 	len = nand_subop_get_data_len(subop, op_id);
291289550bebSMd Sadre Alam 
291389550bebSMd Sadre Alam 	nandc_set_read_loc(chip, 0, 0, 0, len, 1);
291489550bebSMd Sadre Alam 
291589550bebSMd Sadre Alam 	if (!nandc->props->qpic_v2) {
291689550bebSMd Sadre Alam 		write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
291789550bebSMd Sadre Alam 		write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
291889550bebSMd Sadre Alam 	}
291989550bebSMd Sadre Alam 
292089550bebSMd Sadre Alam 	nandc->buf_count = len;
292189550bebSMd Sadre Alam 	memset(nandc->data_buffer, 0xff, nandc->buf_count);
292289550bebSMd Sadre Alam 
292389550bebSMd Sadre Alam 	config_nand_single_cw_page_read(chip, false, 0);
292489550bebSMd Sadre Alam 
292589550bebSMd Sadre Alam 	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
292689550bebSMd Sadre Alam 		      nandc->buf_count, 0);
292789550bebSMd Sadre Alam 
292889550bebSMd Sadre Alam 	/* restore CMD1 and VLD regs */
292989550bebSMd Sadre Alam 	if (!nandc->props->qpic_v2) {
293089550bebSMd Sadre Alam 		write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
293189550bebSMd Sadre Alam 		write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
293289550bebSMd Sadre Alam 	}
293389550bebSMd Sadre Alam 
293489550bebSMd Sadre Alam 	ret = submit_descs(nandc);
293589550bebSMd Sadre Alam 	if (ret) {
293689550bebSMd Sadre Alam 		dev_err(nandc->dev, "failure in submitting param page descriptor\n");
293789550bebSMd Sadre Alam 		goto err_out;
293889550bebSMd Sadre Alam 	}
293989550bebSMd Sadre Alam 
294089550bebSMd Sadre Alam 	ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms);
294189550bebSMd Sadre Alam 	if (ret)
294289550bebSMd Sadre Alam 		goto err_out;
294389550bebSMd Sadre Alam 
294489550bebSMd Sadre Alam 	memcpy(instr->ctx.data.buf.in, nandc->data_buffer, len);
294589550bebSMd Sadre Alam 
294689550bebSMd Sadre Alam err_out:
294789550bebSMd Sadre Alam 	return ret;
294889550bebSMd Sadre Alam }
294989550bebSMd Sadre Alam 
295089550bebSMd Sadre Alam static const struct nand_op_parser qcom_op_parser = NAND_OP_PARSER(
295189550bebSMd Sadre Alam 		NAND_OP_PARSER_PATTERN(
295289550bebSMd Sadre Alam 			qcom_read_id_type_exec,
295389550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_CMD_ELEM(false),
295489550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYCLE),
295589550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
295689550bebSMd Sadre Alam 		NAND_OP_PARSER_PATTERN(
295789550bebSMd Sadre Alam 			qcom_read_status_exec,
295889550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_CMD_ELEM(false),
295989550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)),
296089550bebSMd Sadre Alam 		NAND_OP_PARSER_PATTERN(
296189550bebSMd Sadre Alam 			qcom_param_page_type_exec,
296289550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_CMD_ELEM(false),
296389550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYCLE),
296489550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
296589550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 512)),
296689550bebSMd Sadre Alam 		NAND_OP_PARSER_PATTERN(
2967a82990c8SSricharan Ramabadhran 			qcom_misc_cmd_type_exec,
296889550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_CMD_ELEM(false),
2969a82990c8SSricharan Ramabadhran 			NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYCLE),
2970a82990c8SSricharan Ramabadhran 			NAND_OP_PARSER_PAT_CMD_ELEM(true),
297189550bebSMd Sadre Alam 			NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
297289550bebSMd Sadre Alam 		);
297389550bebSMd Sadre Alam 
qcom_check_op(struct nand_chip * chip,const struct nand_operation * op)297489550bebSMd Sadre Alam static int qcom_check_op(struct nand_chip *chip,
297589550bebSMd Sadre Alam 			 const struct nand_operation *op)
297689550bebSMd Sadre Alam {
297789550bebSMd Sadre Alam 	const struct nand_op_instr *instr;
297889550bebSMd Sadre Alam 	int op_id;
297989550bebSMd Sadre Alam 
298089550bebSMd Sadre Alam 	for (op_id = 0; op_id < op->ninstrs; op_id++) {
298189550bebSMd Sadre Alam 		instr = &op->instrs[op_id];
298289550bebSMd Sadre Alam 
298389550bebSMd Sadre Alam 		switch (instr->type) {
298489550bebSMd Sadre Alam 		case NAND_OP_CMD_INSTR:
2985b4bb4800SManivannan Sadhasivam 			if (instr->ctx.cmd.opcode != NAND_CMD_RESET  &&
2986b4bb4800SManivannan Sadhasivam 			    instr->ctx.cmd.opcode != NAND_CMD_READID &&
2987b4bb4800SManivannan Sadhasivam 			    instr->ctx.cmd.opcode != NAND_CMD_PARAM  &&
2988b4bb4800SManivannan Sadhasivam 			    instr->ctx.cmd.opcode != NAND_CMD_ERASE1 &&
2989b4bb4800SManivannan Sadhasivam 			    instr->ctx.cmd.opcode != NAND_CMD_ERASE2 &&
2990b4bb4800SManivannan Sadhasivam 			    instr->ctx.cmd.opcode != NAND_CMD_STATUS &&
2991a82990c8SSricharan Ramabadhran 			    instr->ctx.cmd.opcode != NAND_CMD_PAGEPROG &&
2992a82990c8SSricharan Ramabadhran 			    instr->ctx.cmd.opcode != NAND_CMD_READ0 &&
2993a82990c8SSricharan Ramabadhran 			    instr->ctx.cmd.opcode != NAND_CMD_READSTART)
2994ab15aabaSManivannan Sadhasivam 				return -EOPNOTSUPP;
299589550bebSMd Sadre Alam 			break;
299689550bebSMd Sadre Alam 		default:
299789550bebSMd Sadre Alam 			break;
299889550bebSMd Sadre Alam 		}
299989550bebSMd Sadre Alam 	}
300089550bebSMd Sadre Alam 
300189550bebSMd Sadre Alam 	return 0;
300289550bebSMd Sadre Alam }
300389550bebSMd Sadre Alam 
qcom_nand_exec_op(struct nand_chip * chip,const struct nand_operation * op,bool check_only)300489550bebSMd Sadre Alam static int qcom_nand_exec_op(struct nand_chip *chip,
3005cf82436dSManivannan Sadhasivam 			     const struct nand_operation *op, bool check_only)
300689550bebSMd Sadre Alam {
300789550bebSMd Sadre Alam 	if (check_only)
300889550bebSMd Sadre Alam 		return qcom_check_op(chip, op);
300989550bebSMd Sadre Alam 
3010cf82436dSManivannan Sadhasivam 	return nand_op_parser_exec_op(chip, &qcom_op_parser, op, check_only);
301189550bebSMd Sadre Alam }
301289550bebSMd Sadre Alam 
30136a3cec64SMiquel Raynal static const struct nand_controller_ops qcom_nandc_ops = {
30146a3cec64SMiquel Raynal 	.attach_chip = qcom_nand_attach_chip,
301589550bebSMd Sadre Alam 	.exec_op = qcom_nand_exec_op,
30166a3cec64SMiquel Raynal };
30176a3cec64SMiquel Raynal 
qcom_nandc_unalloc(struct qcom_nand_controller * nandc)301880c3012eSPeter Ujfalusi static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
301980c3012eSPeter Ujfalusi {
302080c3012eSPeter Ujfalusi 	if (nandc->props->is_bam) {
302180c3012eSPeter Ujfalusi 		if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
302280c3012eSPeter Ujfalusi 			dma_unmap_single(nandc->dev, nandc->reg_read_dma,
302380c3012eSPeter Ujfalusi 					 MAX_REG_RD *
302480c3012eSPeter Ujfalusi 					 sizeof(*nandc->reg_read_buf),
302580c3012eSPeter Ujfalusi 					 DMA_FROM_DEVICE);
302680c3012eSPeter Ujfalusi 
302780c3012eSPeter Ujfalusi 		if (nandc->tx_chan)
302880c3012eSPeter Ujfalusi 			dma_release_channel(nandc->tx_chan);
302980c3012eSPeter Ujfalusi 
303080c3012eSPeter Ujfalusi 		if (nandc->rx_chan)
303180c3012eSPeter Ujfalusi 			dma_release_channel(nandc->rx_chan);
303280c3012eSPeter Ujfalusi 
303380c3012eSPeter Ujfalusi 		if (nandc->cmd_chan)
303480c3012eSPeter Ujfalusi 			dma_release_channel(nandc->cmd_chan);
303580c3012eSPeter Ujfalusi 	} else {
303680c3012eSPeter Ujfalusi 		if (nandc->chan)
303780c3012eSPeter Ujfalusi 			dma_release_channel(nandc->chan);
303880c3012eSPeter Ujfalusi 	}
303980c3012eSPeter Ujfalusi }
304080c3012eSPeter Ujfalusi 
qcom_nandc_alloc(struct qcom_nand_controller * nandc)304193db446aSBoris Brezillon static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
304293db446aSBoris Brezillon {
304393db446aSBoris Brezillon 	int ret;
304493db446aSBoris Brezillon 
304593db446aSBoris Brezillon 	ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
304693db446aSBoris Brezillon 	if (ret) {
304793db446aSBoris Brezillon 		dev_err(nandc->dev, "failed to set DMA mask\n");
304893db446aSBoris Brezillon 		return ret;
304993db446aSBoris Brezillon 	}
305093db446aSBoris Brezillon 
305193db446aSBoris Brezillon 	/*
305293db446aSBoris Brezillon 	 * we use the internal buffer for reading ONFI params, reading small
305393db446aSBoris Brezillon 	 * data like ID and status, and preforming read-copy-write operations
305493db446aSBoris Brezillon 	 * when writing to a codeword partially. 532 is the maximum possible
305593db446aSBoris Brezillon 	 * size of a codeword for our nand controller
305693db446aSBoris Brezillon 	 */
305793db446aSBoris Brezillon 	nandc->buf_size = 532;
305893db446aSBoris Brezillon 
3059062d8acbSMiquel Raynal 	nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
306093db446aSBoris Brezillon 	if (!nandc->data_buffer)
306193db446aSBoris Brezillon 		return -ENOMEM;
306293db446aSBoris Brezillon 
3063062d8acbSMiquel Raynal 	nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
306493db446aSBoris Brezillon 	if (!nandc->regs)
306593db446aSBoris Brezillon 		return -ENOMEM;
306693db446aSBoris Brezillon 
3067062d8acbSMiquel Raynal 	nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
3068062d8acbSMiquel Raynal 					   sizeof(*nandc->reg_read_buf),
306993db446aSBoris Brezillon 					   GFP_KERNEL);
307093db446aSBoris Brezillon 	if (!nandc->reg_read_buf)
307193db446aSBoris Brezillon 		return -ENOMEM;
307293db446aSBoris Brezillon 
307393db446aSBoris Brezillon 	if (nandc->props->is_bam) {
307493db446aSBoris Brezillon 		nandc->reg_read_dma =
307593db446aSBoris Brezillon 			dma_map_single(nandc->dev, nandc->reg_read_buf,
307693db446aSBoris Brezillon 				       MAX_REG_RD *
307793db446aSBoris Brezillon 				       sizeof(*nandc->reg_read_buf),
307893db446aSBoris Brezillon 				       DMA_FROM_DEVICE);
307993db446aSBoris Brezillon 		if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
308093db446aSBoris Brezillon 			dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
308193db446aSBoris Brezillon 			return -EIO;
308293db446aSBoris Brezillon 		}
308393db446aSBoris Brezillon 
308492f0f8efSPeter Ujfalusi 		nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
308592f0f8efSPeter Ujfalusi 		if (IS_ERR(nandc->tx_chan)) {
308692f0f8efSPeter Ujfalusi 			ret = PTR_ERR(nandc->tx_chan);
308792f0f8efSPeter Ujfalusi 			nandc->tx_chan = NULL;
308807eb014fSKrzysztof Kozlowski 			dev_err_probe(nandc->dev, ret,
308907eb014fSKrzysztof Kozlowski 				      "tx DMA channel request failed\n");
309080c3012eSPeter Ujfalusi 			goto unalloc;
309193db446aSBoris Brezillon 		}
309293db446aSBoris Brezillon 
309392f0f8efSPeter Ujfalusi 		nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
309492f0f8efSPeter Ujfalusi 		if (IS_ERR(nandc->rx_chan)) {
309592f0f8efSPeter Ujfalusi 			ret = PTR_ERR(nandc->rx_chan);
309692f0f8efSPeter Ujfalusi 			nandc->rx_chan = NULL;
309707eb014fSKrzysztof Kozlowski 			dev_err_probe(nandc->dev, ret,
309807eb014fSKrzysztof Kozlowski 				      "rx DMA channel request failed\n");
309980c3012eSPeter Ujfalusi 			goto unalloc;
310093db446aSBoris Brezillon 		}
310193db446aSBoris Brezillon 
310292f0f8efSPeter Ujfalusi 		nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
310392f0f8efSPeter Ujfalusi 		if (IS_ERR(nandc->cmd_chan)) {
310492f0f8efSPeter Ujfalusi 			ret = PTR_ERR(nandc->cmd_chan);
310592f0f8efSPeter Ujfalusi 			nandc->cmd_chan = NULL;
310607eb014fSKrzysztof Kozlowski 			dev_err_probe(nandc->dev, ret,
310707eb014fSKrzysztof Kozlowski 				      "cmd DMA channel request failed\n");
310880c3012eSPeter Ujfalusi 			goto unalloc;
310993db446aSBoris Brezillon 		}
311093db446aSBoris Brezillon 
311193db446aSBoris Brezillon 		/*
311293db446aSBoris Brezillon 		 * Initially allocate BAM transaction to read ONFI param page.
311393db446aSBoris Brezillon 		 * After detecting all the devices, this BAM transaction will
3114548b7509SMiquel Raynal 		 * be freed and the next BAM transaction will be allocated with
311593db446aSBoris Brezillon 		 * maximum codeword size
311693db446aSBoris Brezillon 		 */
311793db446aSBoris Brezillon 		nandc->max_cwperpage = 1;
311893db446aSBoris Brezillon 		nandc->bam_txn = alloc_bam_transaction(nandc);
311993db446aSBoris Brezillon 		if (!nandc->bam_txn) {
312093db446aSBoris Brezillon 			dev_err(nandc->dev,
312193db446aSBoris Brezillon 				"failed to allocate bam transaction\n");
312280c3012eSPeter Ujfalusi 			ret = -ENOMEM;
312380c3012eSPeter Ujfalusi 			goto unalloc;
312493db446aSBoris Brezillon 		}
312593db446aSBoris Brezillon 	} else {
312692f0f8efSPeter Ujfalusi 		nandc->chan = dma_request_chan(nandc->dev, "rxtx");
312792f0f8efSPeter Ujfalusi 		if (IS_ERR(nandc->chan)) {
312892f0f8efSPeter Ujfalusi 			ret = PTR_ERR(nandc->chan);
312992f0f8efSPeter Ujfalusi 			nandc->chan = NULL;
313007eb014fSKrzysztof Kozlowski 			dev_err_probe(nandc->dev, ret,
313107eb014fSKrzysztof Kozlowski 				      "rxtx DMA channel request failed\n");
313292f0f8efSPeter Ujfalusi 			return ret;
313393db446aSBoris Brezillon 		}
313493db446aSBoris Brezillon 	}
313593db446aSBoris Brezillon 
313693db446aSBoris Brezillon 	INIT_LIST_HEAD(&nandc->desc_list);
313793db446aSBoris Brezillon 	INIT_LIST_HEAD(&nandc->host_list);
313893db446aSBoris Brezillon 
31397da45139SMiquel Raynal 	nand_controller_init(&nandc->controller);
31406a3cec64SMiquel Raynal 	nandc->controller.ops = &qcom_nandc_ops;
314193db446aSBoris Brezillon 
314293db446aSBoris Brezillon 	return 0;
314380c3012eSPeter Ujfalusi unalloc:
314480c3012eSPeter Ujfalusi 	qcom_nandc_unalloc(nandc);
314580c3012eSPeter Ujfalusi 	return ret;
314693db446aSBoris Brezillon }
314793db446aSBoris Brezillon 
314893db446aSBoris Brezillon /* one time setup of a few nand controller registers */
qcom_nandc_setup(struct qcom_nand_controller * nandc)314993db446aSBoris Brezillon static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
315093db446aSBoris Brezillon {
315193db446aSBoris Brezillon 	u32 nand_ctrl;
315293db446aSBoris Brezillon 
315393db446aSBoris Brezillon 	/* kill onenand */
3154443440ccSSivaprakash Murugesan 	if (!nandc->props->is_qpic)
315593db446aSBoris Brezillon 		nandc_write(nandc, SFLASHC_BURST_CFG, 0);
3156b1209582SManivannan Sadhasivam 
3157b1209582SManivannan Sadhasivam 	if (!nandc->props->qpic_v2)
315893db446aSBoris Brezillon 		nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
315993db446aSBoris Brezillon 			    NAND_DEV_CMD_VLD_VAL);
316093db446aSBoris Brezillon 
316193db446aSBoris Brezillon 	/* enable ADM or BAM DMA */
316293db446aSBoris Brezillon 	if (nandc->props->is_bam) {
316393db446aSBoris Brezillon 		nand_ctrl = nandc_read(nandc, NAND_CTRL);
3164cb272395SSivaprakash Murugesan 
3165cb272395SSivaprakash Murugesan 		/*
3166cb272395SSivaprakash Murugesan 		 *NAND_CTRL is an operational registers, and CPU
3167cb272395SSivaprakash Murugesan 		 * access to operational registers are read only
3168cb272395SSivaprakash Murugesan 		 * in BAM mode. So update the NAND_CTRL register
3169cb272395SSivaprakash Murugesan 		 * only if it is not in BAM mode. In most cases BAM
3170cb272395SSivaprakash Murugesan 		 * mode will be enabled in bootloader
3171cb272395SSivaprakash Murugesan 		 */
3172cb272395SSivaprakash Murugesan 		if (!(nand_ctrl & BAM_MODE_EN))
317393db446aSBoris Brezillon 			nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
317493db446aSBoris Brezillon 	} else {
317593db446aSBoris Brezillon 		nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
317693db446aSBoris Brezillon 	}
317793db446aSBoris Brezillon 
317893db446aSBoris Brezillon 	/* save the original values of these registers */
3179b1209582SManivannan Sadhasivam 	if (!nandc->props->qpic_v2) {
318093db446aSBoris Brezillon 		nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
318193db446aSBoris Brezillon 		nandc->vld = NAND_DEV_CMD_VLD_VAL;
3182b1209582SManivannan Sadhasivam 	}
318393db446aSBoris Brezillon 
318493db446aSBoris Brezillon 	return 0;
318593db446aSBoris Brezillon }
318693db446aSBoris Brezillon 
318721020becSBaruch Siach static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL };
318882bfd11fSManivannan Sadhasivam 
qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller * nandc,struct qcom_nand_host * host,struct device_node * dn)3189862bdeddSChristian Marangi static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nandc,
3190862bdeddSChristian Marangi 						struct qcom_nand_host *host,
3191862bdeddSChristian Marangi 						struct device_node *dn)
3192862bdeddSChristian Marangi {
3193862bdeddSChristian Marangi 	struct nand_chip *chip = &host->chip;
3194862bdeddSChristian Marangi 	struct mtd_info *mtd = nand_to_mtd(chip);
3195862bdeddSChristian Marangi 	struct qcom_nand_boot_partition *boot_partition;
3196862bdeddSChristian Marangi 	struct device *dev = nandc->dev;
3197862bdeddSChristian Marangi 	int partitions_count, i, j, ret;
3198862bdeddSChristian Marangi 
31997c09abbaSRob Herring 	if (!of_property_present(dn, "qcom,boot-partitions"))
3200862bdeddSChristian Marangi 		return 0;
3201862bdeddSChristian Marangi 
3202862bdeddSChristian Marangi 	partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions");
3203862bdeddSChristian Marangi 	if (partitions_count <= 0) {
3204862bdeddSChristian Marangi 		dev_err(dev, "Error parsing boot partition\n");
3205862bdeddSChristian Marangi 		return partitions_count ? partitions_count : -EINVAL;
3206862bdeddSChristian Marangi 	}
3207862bdeddSChristian Marangi 
3208862bdeddSChristian Marangi 	host->nr_boot_partitions = partitions_count / 2;
3209862bdeddSChristian Marangi 	host->boot_partitions = devm_kcalloc(dev, host->nr_boot_partitions,
3210862bdeddSChristian Marangi 					     sizeof(*host->boot_partitions), GFP_KERNEL);
3211862bdeddSChristian Marangi 	if (!host->boot_partitions) {
3212862bdeddSChristian Marangi 		host->nr_boot_partitions = 0;
3213862bdeddSChristian Marangi 		return -ENOMEM;
3214862bdeddSChristian Marangi 	}
3215862bdeddSChristian Marangi 
3216862bdeddSChristian Marangi 	for (i = 0, j = 0; i < host->nr_boot_partitions; i++, j += 2) {
3217862bdeddSChristian Marangi 		boot_partition = &host->boot_partitions[i];
3218862bdeddSChristian Marangi 
3219862bdeddSChristian Marangi 		ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j,
3220862bdeddSChristian Marangi 						 &boot_partition->page_offset);
3221862bdeddSChristian Marangi 		if (ret) {
3222862bdeddSChristian Marangi 			dev_err(dev, "Error parsing boot partition offset at index %d\n", i);
3223862bdeddSChristian Marangi 			host->nr_boot_partitions = 0;
3224862bdeddSChristian Marangi 			return ret;
3225862bdeddSChristian Marangi 		}
3226862bdeddSChristian Marangi 
3227862bdeddSChristian Marangi 		if (boot_partition->page_offset % mtd->writesize) {
3228862bdeddSChristian Marangi 			dev_err(dev, "Boot partition offset not multiple of writesize at index %i\n",
3229862bdeddSChristian Marangi 				i);
3230862bdeddSChristian Marangi 			host->nr_boot_partitions = 0;
3231862bdeddSChristian Marangi 			return -EINVAL;
3232862bdeddSChristian Marangi 		}
3233862bdeddSChristian Marangi 		/* Convert offset to nand pages */
3234862bdeddSChristian Marangi 		boot_partition->page_offset /= mtd->writesize;
3235862bdeddSChristian Marangi 
3236862bdeddSChristian Marangi 		ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j + 1,
3237862bdeddSChristian Marangi 						 &boot_partition->page_size);
3238862bdeddSChristian Marangi 		if (ret) {
3239862bdeddSChristian Marangi 			dev_err(dev, "Error parsing boot partition size at index %d\n", i);
3240862bdeddSChristian Marangi 			host->nr_boot_partitions = 0;
3241862bdeddSChristian Marangi 			return ret;
3242862bdeddSChristian Marangi 		}
3243862bdeddSChristian Marangi 
3244862bdeddSChristian Marangi 		if (boot_partition->page_size % mtd->writesize) {
3245862bdeddSChristian Marangi 			dev_err(dev, "Boot partition size not multiple of writesize at index %i\n",
3246862bdeddSChristian Marangi 				i);
3247862bdeddSChristian Marangi 			host->nr_boot_partitions = 0;
3248862bdeddSChristian Marangi 			return -EINVAL;
3249862bdeddSChristian Marangi 		}
3250862bdeddSChristian Marangi 		/* Convert size to nand pages */
3251862bdeddSChristian Marangi 		boot_partition->page_size /= mtd->writesize;
3252862bdeddSChristian Marangi 	}
3253862bdeddSChristian Marangi 
3254862bdeddSChristian Marangi 	return 0;
3255862bdeddSChristian Marangi }
3256862bdeddSChristian Marangi 
qcom_nand_host_init_and_register(struct qcom_nand_controller * nandc,struct qcom_nand_host * host,struct device_node * dn)32576a3cec64SMiquel Raynal static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
325893db446aSBoris Brezillon 					    struct qcom_nand_host *host,
325993db446aSBoris Brezillon 					    struct device_node *dn)
326093db446aSBoris Brezillon {
326193db446aSBoris Brezillon 	struct nand_chip *chip = &host->chip;
326293db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
326393db446aSBoris Brezillon 	struct device *dev = nandc->dev;
326493db446aSBoris Brezillon 	int ret;
326593db446aSBoris Brezillon 
326693db446aSBoris Brezillon 	ret = of_property_read_u32(dn, "reg", &host->cs);
326793db446aSBoris Brezillon 	if (ret) {
326893db446aSBoris Brezillon 		dev_err(dev, "can't get chip-select\n");
326993db446aSBoris Brezillon 		return -ENXIO;
327093db446aSBoris Brezillon 	}
327193db446aSBoris Brezillon 
327293db446aSBoris Brezillon 	nand_set_flash_node(chip, dn);
327393db446aSBoris Brezillon 	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
327493db446aSBoris Brezillon 	if (!mtd->name)
327593db446aSBoris Brezillon 		return -ENOMEM;
327693db446aSBoris Brezillon 
327793db446aSBoris Brezillon 	mtd->owner = THIS_MODULE;
327893db446aSBoris Brezillon 	mtd->dev.parent = dev;
327993db446aSBoris Brezillon 
328093db446aSBoris Brezillon 	/*
328193db446aSBoris Brezillon 	 * the bad block marker is readable only when we read the last codeword
328293db446aSBoris Brezillon 	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
328393db446aSBoris Brezillon 	 * helpers don't allow us to read BB from a nand chip with ECC
328493db446aSBoris Brezillon 	 * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
328593db446aSBoris Brezillon 	 * and block_markbad helpers until we permanently switch to using
328693db446aSBoris Brezillon 	 * MTD_OPS_RAW for all drivers (with the help of badblockbits)
328793db446aSBoris Brezillon 	 */
3288cdc784c7SBoris Brezillon 	chip->legacy.block_bad		= qcom_nandc_block_bad;
3289cdc784c7SBoris Brezillon 	chip->legacy.block_markbad	= qcom_nandc_block_markbad;
329093db446aSBoris Brezillon 
329193db446aSBoris Brezillon 	chip->controller = &nandc->controller;
3292ce8148d7SMiquel Raynal 	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
329393db446aSBoris Brezillon 			 NAND_SKIP_BBTSCAN;
329493db446aSBoris Brezillon 
329593db446aSBoris Brezillon 	/* set up initial status value */
329693db446aSBoris Brezillon 	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
329793db446aSBoris Brezillon 
329800ad378fSBoris Brezillon 	ret = nand_scan(chip, 1);
329993db446aSBoris Brezillon 	if (ret)
330093db446aSBoris Brezillon 		return ret;
330193db446aSBoris Brezillon 
330282bfd11fSManivannan Sadhasivam 	ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
330393db446aSBoris Brezillon 	if (ret)
33047df140e8SChristian Marangi 		goto err;
330593db446aSBoris Brezillon 
3306862bdeddSChristian Marangi 	if (nandc->props->use_codeword_fixup) {
3307862bdeddSChristian Marangi 		ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn);
33087df140e8SChristian Marangi 		if (ret)
33097df140e8SChristian Marangi 			goto err;
3310862bdeddSChristian Marangi 	}
3311862bdeddSChristian Marangi 
33127df140e8SChristian Marangi 	return 0;
33137df140e8SChristian Marangi 
33147df140e8SChristian Marangi err:
33157df140e8SChristian Marangi 	nand_cleanup(chip);
331693db446aSBoris Brezillon 	return ret;
331793db446aSBoris Brezillon }
331893db446aSBoris Brezillon 
qcom_probe_nand_devices(struct qcom_nand_controller * nandc)331993db446aSBoris Brezillon static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
332093db446aSBoris Brezillon {
332193db446aSBoris Brezillon 	struct device *dev = nandc->dev;
332293db446aSBoris Brezillon 	struct device_node *dn = dev->of_node, *child;
33236a3cec64SMiquel Raynal 	struct qcom_nand_host *host;
332455fbb9baSManivannan Sadhasivam 	int ret = -ENODEV;
332593db446aSBoris Brezillon 
33266a3cec64SMiquel Raynal 	for_each_available_child_of_node(dn, child) {
33276a3cec64SMiquel Raynal 		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
33286a3cec64SMiquel Raynal 		if (!host) {
33296a3cec64SMiquel Raynal 			of_node_put(child);
33306a3cec64SMiquel Raynal 			return -ENOMEM;
333193db446aSBoris Brezillon 		}
33326a3cec64SMiquel Raynal 
33336a3cec64SMiquel Raynal 		ret = qcom_nand_host_init_and_register(nandc, host, child);
33346a3cec64SMiquel Raynal 		if (ret) {
33356a3cec64SMiquel Raynal 			devm_kfree(dev, host);
33366a3cec64SMiquel Raynal 			continue;
33376a3cec64SMiquel Raynal 		}
33386a3cec64SMiquel Raynal 
33396a3cec64SMiquel Raynal 		list_add_tail(&host->node, &nandc->host_list);
334093db446aSBoris Brezillon 	}
334193db446aSBoris Brezillon 
334255fbb9baSManivannan Sadhasivam 	return ret;
334393db446aSBoris Brezillon }
334493db446aSBoris Brezillon 
334593db446aSBoris Brezillon /* parse custom DT properties here */
qcom_nandc_parse_dt(struct platform_device * pdev)334693db446aSBoris Brezillon static int qcom_nandc_parse_dt(struct platform_device *pdev)
334793db446aSBoris Brezillon {
334893db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
334993db446aSBoris Brezillon 	struct device_node *np = nandc->dev->of_node;
335093db446aSBoris Brezillon 	int ret;
335193db446aSBoris Brezillon 
335293db446aSBoris Brezillon 	if (!nandc->props->is_bam) {
335393db446aSBoris Brezillon 		ret = of_property_read_u32(np, "qcom,cmd-crci",
335493db446aSBoris Brezillon 					   &nandc->cmd_crci);
335593db446aSBoris Brezillon 		if (ret) {
335693db446aSBoris Brezillon 			dev_err(nandc->dev, "command CRCI unspecified\n");
335793db446aSBoris Brezillon 			return ret;
335893db446aSBoris Brezillon 		}
335993db446aSBoris Brezillon 
336093db446aSBoris Brezillon 		ret = of_property_read_u32(np, "qcom,data-crci",
336193db446aSBoris Brezillon 					   &nandc->data_crci);
336293db446aSBoris Brezillon 		if (ret) {
336393db446aSBoris Brezillon 			dev_err(nandc->dev, "data CRCI unspecified\n");
336493db446aSBoris Brezillon 			return ret;
336593db446aSBoris Brezillon 		}
336693db446aSBoris Brezillon 	}
336793db446aSBoris Brezillon 
336893db446aSBoris Brezillon 	return 0;
336993db446aSBoris Brezillon }
337093db446aSBoris Brezillon 
qcom_nandc_probe(struct platform_device * pdev)337193db446aSBoris Brezillon static int qcom_nandc_probe(struct platform_device *pdev)
337293db446aSBoris Brezillon {
337393db446aSBoris Brezillon 	struct qcom_nand_controller *nandc;
337493db446aSBoris Brezillon 	const void *dev_data;
337593db446aSBoris Brezillon 	struct device *dev = &pdev->dev;
337693db446aSBoris Brezillon 	struct resource *res;
337793db446aSBoris Brezillon 	int ret;
337893db446aSBoris Brezillon 
337993db446aSBoris Brezillon 	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
338093db446aSBoris Brezillon 	if (!nandc)
338193db446aSBoris Brezillon 		return -ENOMEM;
338293db446aSBoris Brezillon 
338393db446aSBoris Brezillon 	platform_set_drvdata(pdev, nandc);
338493db446aSBoris Brezillon 	nandc->dev = dev;
338593db446aSBoris Brezillon 
338693db446aSBoris Brezillon 	dev_data = of_device_get_match_data(dev);
338793db446aSBoris Brezillon 	if (!dev_data) {
338893db446aSBoris Brezillon 		dev_err(&pdev->dev, "failed to get device data\n");
338993db446aSBoris Brezillon 		return -ENODEV;
339093db446aSBoris Brezillon 	}
339193db446aSBoris Brezillon 
339293db446aSBoris Brezillon 	nandc->props = dev_data;
339393db446aSBoris Brezillon 
339493db446aSBoris Brezillon 	nandc->core_clk = devm_clk_get(dev, "core");
339593db446aSBoris Brezillon 	if (IS_ERR(nandc->core_clk))
339693db446aSBoris Brezillon 		return PTR_ERR(nandc->core_clk);
339793db446aSBoris Brezillon 
339893db446aSBoris Brezillon 	nandc->aon_clk = devm_clk_get(dev, "aon");
339993db446aSBoris Brezillon 	if (IS_ERR(nandc->aon_clk))
340093db446aSBoris Brezillon 		return PTR_ERR(nandc->aon_clk);
340193db446aSBoris Brezillon 
340293db446aSBoris Brezillon 	ret = qcom_nandc_parse_dt(pdev);
340393db446aSBoris Brezillon 	if (ret)
340493db446aSBoris Brezillon 		return ret;
340593db446aSBoris Brezillon 
3406bcf09d7eSMd Sadre Alam 	nandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
34077330fc50SArnd Bergmann 	if (IS_ERR(nandc->base))
34087330fc50SArnd Bergmann 		return PTR_ERR(nandc->base);
34097330fc50SArnd Bergmann 
34107330fc50SArnd Bergmann 	nandc->base_phys = res->start;
34117330fc50SArnd Bergmann 	nandc->base_dma = dma_map_resource(dev, res->start,
34127330fc50SArnd Bergmann 					   resource_size(res),
34137330fc50SArnd Bergmann 					   DMA_BIDIRECTIONAL, 0);
341432cbc7cbSManivannan Sadhasivam 	if (dma_mapping_error(dev, nandc->base_dma))
34157330fc50SArnd Bergmann 		return -ENXIO;
34167330fc50SArnd Bergmann 
341793db446aSBoris Brezillon 	ret = clk_prepare_enable(nandc->core_clk);
341893db446aSBoris Brezillon 	if (ret)
341993db446aSBoris Brezillon 		goto err_core_clk;
342093db446aSBoris Brezillon 
342193db446aSBoris Brezillon 	ret = clk_prepare_enable(nandc->aon_clk);
342293db446aSBoris Brezillon 	if (ret)
342393db446aSBoris Brezillon 		goto err_aon_clk;
342493db446aSBoris Brezillon 
34255c23b3f9SBryan O'Donoghue 	ret = qcom_nandc_alloc(nandc);
34265c23b3f9SBryan O'Donoghue 	if (ret)
34275c23b3f9SBryan O'Donoghue 		goto err_nandc_alloc;
34285c23b3f9SBryan O'Donoghue 
342993db446aSBoris Brezillon 	ret = qcom_nandc_setup(nandc);
343093db446aSBoris Brezillon 	if (ret)
343193db446aSBoris Brezillon 		goto err_setup;
343293db446aSBoris Brezillon 
343393db446aSBoris Brezillon 	ret = qcom_probe_nand_devices(nandc);
343493db446aSBoris Brezillon 	if (ret)
343593db446aSBoris Brezillon 		goto err_setup;
343693db446aSBoris Brezillon 
343793db446aSBoris Brezillon 	return 0;
343893db446aSBoris Brezillon 
343993db446aSBoris Brezillon err_setup:
34405c23b3f9SBryan O'Donoghue 	qcom_nandc_unalloc(nandc);
34415c23b3f9SBryan O'Donoghue err_nandc_alloc:
344293db446aSBoris Brezillon 	clk_disable_unprepare(nandc->aon_clk);
344393db446aSBoris Brezillon err_aon_clk:
344493db446aSBoris Brezillon 	clk_disable_unprepare(nandc->core_clk);
344593db446aSBoris Brezillon err_core_clk:
34465279f4a9SBibek Kumar Patro 	dma_unmap_resource(dev, nandc->base_dma, resource_size(res),
34477330fc50SArnd Bergmann 			   DMA_BIDIRECTIONAL, 0);
344893db446aSBoris Brezillon 	return ret;
344993db446aSBoris Brezillon }
345093db446aSBoris Brezillon 
qcom_nandc_remove(struct platform_device * pdev)3451ec185b18SUwe Kleine-König static void qcom_nandc_remove(struct platform_device *pdev)
345293db446aSBoris Brezillon {
345393db446aSBoris Brezillon 	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
34547330fc50SArnd Bergmann 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
345593db446aSBoris Brezillon 	struct qcom_nand_host *host;
34560a2bc991SMiquel Raynal 	struct nand_chip *chip;
34570a2bc991SMiquel Raynal 	int ret;
345893db446aSBoris Brezillon 
34590a2bc991SMiquel Raynal 	list_for_each_entry(host, &nandc->host_list, node) {
34600a2bc991SMiquel Raynal 		chip = &host->chip;
34610a2bc991SMiquel Raynal 		ret = mtd_device_unregister(nand_to_mtd(chip));
34620a2bc991SMiquel Raynal 		WARN_ON(ret);
34630a2bc991SMiquel Raynal 		nand_cleanup(chip);
34640a2bc991SMiquel Raynal 	}
34657330fc50SArnd Bergmann 
346693db446aSBoris Brezillon 	qcom_nandc_unalloc(nandc);
346793db446aSBoris Brezillon 
346893db446aSBoris Brezillon 	clk_disable_unprepare(nandc->aon_clk);
346993db446aSBoris Brezillon 	clk_disable_unprepare(nandc->core_clk);
347093db446aSBoris Brezillon 
34717330fc50SArnd Bergmann 	dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res),
34727330fc50SArnd Bergmann 			   DMA_BIDIRECTIONAL, 0);
347393db446aSBoris Brezillon }
347493db446aSBoris Brezillon 
347593db446aSBoris Brezillon static const struct qcom_nandc_props ipq806x_nandc_props = {
347693db446aSBoris Brezillon 	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
347793db446aSBoris Brezillon 	.is_bam = false,
3478862bdeddSChristian Marangi 	.use_codeword_fixup = true,
347993db446aSBoris Brezillon 	.dev_cmd_reg_start = 0x0,
348093db446aSBoris Brezillon };
348193db446aSBoris Brezillon 
348293db446aSBoris Brezillon static const struct qcom_nandc_props ipq4019_nandc_props = {
348393db446aSBoris Brezillon 	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
348493db446aSBoris Brezillon 	.is_bam = true,
3485443440ccSSivaprakash Murugesan 	.is_qpic = true,
348693db446aSBoris Brezillon 	.dev_cmd_reg_start = 0x0,
348793db446aSBoris Brezillon };
348893db446aSBoris Brezillon 
348993db446aSBoris Brezillon static const struct qcom_nandc_props ipq8074_nandc_props = {
349093db446aSBoris Brezillon 	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
349193db446aSBoris Brezillon 	.is_bam = true,
3492443440ccSSivaprakash Murugesan 	.is_qpic = true,
349393db446aSBoris Brezillon 	.dev_cmd_reg_start = 0x7000,
349493db446aSBoris Brezillon };
349593db446aSBoris Brezillon 
3496b1209582SManivannan Sadhasivam static const struct qcom_nandc_props sdx55_nandc_props = {
3497b1209582SManivannan Sadhasivam 	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
3498b1209582SManivannan Sadhasivam 	.is_bam = true,
3499b1209582SManivannan Sadhasivam 	.is_qpic = true,
3500b1209582SManivannan Sadhasivam 	.qpic_v2 = true,
3501b1209582SManivannan Sadhasivam 	.dev_cmd_reg_start = 0x7000,
3502b1209582SManivannan Sadhasivam };
3503b1209582SManivannan Sadhasivam 
350493db446aSBoris Brezillon /*
350593db446aSBoris Brezillon  * data will hold a struct pointer containing more differences once we support
350693db446aSBoris Brezillon  * more controller variants
350793db446aSBoris Brezillon  */
350893db446aSBoris Brezillon static const struct of_device_id qcom_nandc_of_match[] = {
350993db446aSBoris Brezillon 	{
351093db446aSBoris Brezillon 		.compatible = "qcom,ipq806x-nand",
351193db446aSBoris Brezillon 		.data = &ipq806x_nandc_props,
351293db446aSBoris Brezillon 	},
351393db446aSBoris Brezillon 	{
351493db446aSBoris Brezillon 		.compatible = "qcom,ipq4019-nand",
351593db446aSBoris Brezillon 		.data = &ipq4019_nandc_props,
351693db446aSBoris Brezillon 	},
351793db446aSBoris Brezillon 	{
351862858625SKathiravan T 		.compatible = "qcom,ipq6018-nand",
351962858625SKathiravan T 		.data = &ipq8074_nandc_props,
352062858625SKathiravan T 	},
352162858625SKathiravan T 	{
352293db446aSBoris Brezillon 		.compatible = "qcom,ipq8074-nand",
352393db446aSBoris Brezillon 		.data = &ipq8074_nandc_props,
352493db446aSBoris Brezillon 	},
3525b1209582SManivannan Sadhasivam 	{
3526b1209582SManivannan Sadhasivam 		.compatible = "qcom,sdx55-nand",
3527b1209582SManivannan Sadhasivam 		.data = &sdx55_nandc_props,
3528b1209582SManivannan Sadhasivam 	},
352993db446aSBoris Brezillon 	{}
353093db446aSBoris Brezillon };
353193db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
353293db446aSBoris Brezillon 
353393db446aSBoris Brezillon static struct platform_driver qcom_nandc_driver = {
353493db446aSBoris Brezillon 	.driver = {
353593db446aSBoris Brezillon 		.name = "qcom-nandc",
353693db446aSBoris Brezillon 		.of_match_table = qcom_nandc_of_match,
353793db446aSBoris Brezillon 	},
353893db446aSBoris Brezillon 	.probe   = qcom_nandc_probe,
3539ec185b18SUwe Kleine-König 	.remove_new = qcom_nandc_remove,
354093db446aSBoris Brezillon };
354193db446aSBoris Brezillon module_platform_driver(qcom_nandc_driver);
354293db446aSBoris Brezillon 
354393db446aSBoris Brezillon MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
354493db446aSBoris Brezillon MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
354593db446aSBoris Brezillon MODULE_LICENSE("GPL v2");
3546