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 ®s->cmd;
70293db446aSBoris Brezillon case NAND_ADDR0:
70393db446aSBoris Brezillon return ®s->addr0;
70493db446aSBoris Brezillon case NAND_ADDR1:
70593db446aSBoris Brezillon return ®s->addr1;
70693db446aSBoris Brezillon case NAND_FLASH_CHIP_SELECT:
70793db446aSBoris Brezillon return ®s->chip_sel;
70893db446aSBoris Brezillon case NAND_EXEC_CMD:
70993db446aSBoris Brezillon return ®s->exec;
71093db446aSBoris Brezillon case NAND_FLASH_STATUS:
71193db446aSBoris Brezillon return ®s->clrflashstatus;
71293db446aSBoris Brezillon case NAND_DEV0_CFG0:
71393db446aSBoris Brezillon return ®s->cfg0;
71493db446aSBoris Brezillon case NAND_DEV0_CFG1:
71593db446aSBoris Brezillon return ®s->cfg1;
71693db446aSBoris Brezillon case NAND_DEV0_ECC_CFG:
71793db446aSBoris Brezillon return ®s->ecc_bch_cfg;
71893db446aSBoris Brezillon case NAND_READ_STATUS:
71993db446aSBoris Brezillon return ®s->clrreadstatus;
72093db446aSBoris Brezillon case NAND_DEV_CMD1:
72193db446aSBoris Brezillon return ®s->cmd1;
72293db446aSBoris Brezillon case NAND_DEV_CMD1_RESTORE:
72393db446aSBoris Brezillon return ®s->orig_cmd1;
72493db446aSBoris Brezillon case NAND_DEV_CMD_VLD:
72593db446aSBoris Brezillon return ®s->vld;
72693db446aSBoris Brezillon case NAND_DEV_CMD_VLD_RESTORE:
72793db446aSBoris Brezillon return ®s->orig_vld;
72893db446aSBoris Brezillon case NAND_EBI2_ECC_BUF_CFG:
72993db446aSBoris Brezillon return ®s->ecc_buf_cfg;
73093db446aSBoris Brezillon case NAND_READ_LOCATION_0:
73193db446aSBoris Brezillon return ®s->read_location0;
73293db446aSBoris Brezillon case NAND_READ_LOCATION_1:
73393db446aSBoris Brezillon return ®s->read_location1;
73493db446aSBoris Brezillon case NAND_READ_LOCATION_2:
73593db446aSBoris Brezillon return ®s->read_location2;
73693db446aSBoris Brezillon case NAND_READ_LOCATION_3:
73793db446aSBoris Brezillon return ®s->read_location3;
738503ee5aaSMd Sadre Alam case NAND_READ_LOCATION_LAST_CW_0:
739503ee5aaSMd Sadre Alam return ®s->read_location_last0;
740503ee5aaSMd Sadre Alam case NAND_READ_LOCATION_LAST_CW_1:
741503ee5aaSMd Sadre Alam return ®s->read_location_last1;
742503ee5aaSMd Sadre Alam case NAND_READ_LOCATION_LAST_CW_2:
743503ee5aaSMd Sadre Alam return ®s->read_location_last2;
744503ee5aaSMd Sadre Alam case NAND_READ_LOCATION_LAST_CW_3:
745503ee5aaSMd Sadre Alam return ®s->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 = ®s->erased_cw_detect_cfg_set;
115593db446aSBoris Brezillon else
115693db446aSBoris Brezillon vaddr = ®s->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