linux/drivers/mtd/nand/raw/qcom_nandc.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
 */
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/dma/qcom_adm.h>
#include <linux/dma/qcom_bam_dma.h>
#include <linux/module.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/rawnand.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

/* NANDc reg offsets */
#define NAND_FLASH_CMD
#define NAND_ADDR0
#define NAND_ADDR1
#define NAND_FLASH_CHIP_SELECT
#define NAND_EXEC_CMD
#define NAND_FLASH_STATUS
#define NAND_BUFFER_STATUS
#define NAND_DEV0_CFG0
#define NAND_DEV0_CFG1
#define NAND_DEV0_ECC_CFG
#define NAND_AUTO_STATUS_EN
#define NAND_DEV1_CFG0
#define NAND_DEV1_CFG1
#define NAND_READ_ID
#define NAND_READ_STATUS
#define NAND_DEV_CMD0
#define NAND_DEV_CMD1
#define NAND_DEV_CMD2
#define NAND_DEV_CMD_VLD
#define SFLASHC_BURST_CFG
#define NAND_ERASED_CW_DETECT_CFG
#define NAND_ERASED_CW_DETECT_STATUS
#define NAND_EBI2_ECC_BUF_CFG
#define FLASH_BUF_ACC

#define NAND_CTRL
#define NAND_VERSION
#define NAND_READ_LOCATION_0
#define NAND_READ_LOCATION_1
#define NAND_READ_LOCATION_2
#define NAND_READ_LOCATION_3
#define NAND_READ_LOCATION_LAST_CW_0
#define NAND_READ_LOCATION_LAST_CW_1
#define NAND_READ_LOCATION_LAST_CW_2
#define NAND_READ_LOCATION_LAST_CW_3

/* dummy register offsets, used by write_reg_dma */
#define NAND_DEV_CMD1_RESTORE
#define NAND_DEV_CMD_VLD_RESTORE

/* NAND_FLASH_CMD bits */
#define PAGE_ACC
#define LAST_PAGE

/* NAND_FLASH_CHIP_SELECT bits */
#define NAND_DEV_SEL
#define DM_EN

/* NAND_FLASH_STATUS bits */
#define FS_OP_ERR
#define FS_READY_BSY_N
#define FS_MPU_ERR
#define FS_DEVICE_STS_ERR
#define FS_DEVICE_WP

/* NAND_BUFFER_STATUS bits */
#define BS_UNCORRECTABLE_BIT
#define BS_CORRECTABLE_ERR_MSK

/* NAND_DEVn_CFG0 bits */
#define DISABLE_STATUS_AFTER_WRITE
#define CW_PER_PAGE
#define UD_SIZE_BYTES
#define UD_SIZE_BYTES_MASK
#define ECC_PARITY_SIZE_BYTES_RS
#define SPARE_SIZE_BYTES
#define SPARE_SIZE_BYTES_MASK
#define NUM_ADDR_CYCLES
#define STATUS_BFR_READ
#define SET_RD_MODE_AFTER_STATUS

/* NAND_DEVn_CFG0 bits */
#define DEV0_CFG1_ECC_DISABLE
#define WIDE_FLASH
#define NAND_RECOVERY_CYCLES
#define CS_ACTIVE_BSY
#define BAD_BLOCK_BYTE_NUM
#define BAD_BLOCK_IN_SPARE_AREA
#define WR_RD_BSY_GAP
#define ENABLE_BCH_ECC

/* NAND_DEV0_ECC_CFG bits */
#define ECC_CFG_ECC_DISABLE
#define ECC_SW_RESET
#define ECC_MODE
#define ECC_PARITY_SIZE_BYTES_BCH
#define ECC_NUM_DATA_BYTES
#define ECC_NUM_DATA_BYTES_MASK
#define ECC_FORCE_CLK_OPEN

/* NAND_DEV_CMD1 bits */
#define READ_ADDR

/* NAND_DEV_CMD_VLD bits */
#define READ_START_VLD
#define READ_STOP_VLD
#define WRITE_START_VLD
#define ERASE_START_VLD
#define SEQ_READ_START_VLD

/* NAND_EBI2_ECC_BUF_CFG bits */
#define NUM_STEPS

/* NAND_ERASED_CW_DETECT_CFG bits */
#define ERASED_CW_ECC_MASK
#define AUTO_DETECT_RES
#define MASK_ECC
#define RESET_ERASED_DET
#define ACTIVE_ERASED_DET
#define CLR_ERASED_PAGE_DET
#define SET_ERASED_PAGE_DET

/* NAND_ERASED_CW_DETECT_STATUS bits */
#define PAGE_ALL_ERASED
#define CODEWORD_ALL_ERASED
#define PAGE_ERASED
#define CODEWORD_ERASED
#define ERASED_PAGE
#define ERASED_CW

/* NAND_READ_LOCATION_n bits */
#define READ_LOCATION_OFFSET
#define READ_LOCATION_SIZE
#define READ_LOCATION_LAST

/* Version Mask */
#define NAND_VERSION_MAJOR_MASK
#define NAND_VERSION_MAJOR_SHIFT
#define NAND_VERSION_MINOR_MASK
#define NAND_VERSION_MINOR_SHIFT

/* NAND OP_CMDs */
#define OP_PAGE_READ
#define OP_PAGE_READ_WITH_ECC
#define OP_PAGE_READ_WITH_ECC_SPARE
#define OP_PAGE_READ_ONFI_READ
#define OP_PROGRAM_PAGE
#define OP_PAGE_PROGRAM_WITH_ECC
#define OP_PROGRAM_PAGE_SPARE
#define OP_BLOCK_ERASE
#define OP_CHECK_STATUS
#define OP_FETCH_ID
#define OP_RESET_DEVICE

/* Default Value for NAND_DEV_CMD_VLD */
#define NAND_DEV_CMD_VLD_VAL

/* NAND_CTRL bits */
#define BAM_MODE_EN

/*
 * the NAND controller performs reads/writes with ECC in 516 byte chunks.
 * the driver calls the chunks 'step' or 'codeword' interchangeably
 */
#define NANDC_STEP_SIZE

/*
 * the largest page size we support is 8K, this will have 16 steps/codewords
 * of 512 bytes each
 */
#define MAX_NUM_STEPS

/* we read at most 3 registers per codeword scan */
#define MAX_REG_RD

/* ECC modes supported by the controller */
#define ECC_NONE
#define ECC_RS_4BIT
#define ECC_BCH_4BIT
#define ECC_BCH_8BIT

#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc)

#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc)
/*
 * Returns the actual register address for all NAND_DEV_ registers
 * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
 */
#define dev_cmd_reg_addr(nandc, reg)

/* Returns the NAND register physical address */
#define nandc_reg_phys(chip, offset)

/* Returns the dma address for reg read buffer */
#define reg_buf_dma_addr(chip, vaddr)

#define QPIC_PER_CW_CMD_ELEMENTS
#define QPIC_PER_CW_CMD_SGL
#define QPIC_PER_CW_DATA_SGL

#define QPIC_NAND_COMPLETION_TIMEOUT

/*
 * Flags used in DMA descriptor preparation helper functions
 * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
 */
/* Don't set the EOT in current tx BAM sgl */
#define NAND_BAM_NO_EOT
/* Set the NWD flag in current BAM sgl */
#define NAND_BAM_NWD
/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
#define NAND_BAM_NEXT_SGL
/*
 * Erased codeword status is being used two times in single transfer so this
 * flag will determine the current value of erased codeword status register
 */
#define NAND_ERASED_CW_SET

#define MAX_ADDRESS_CYCLE

/*
 * This data type corresponds to the BAM transaction which will be used for all
 * NAND transfers.
 * @bam_ce - the array of BAM command elements
 * @cmd_sgl - sgl for NAND BAM command pipe
 * @data_sgl - sgl for NAND BAM consumer/producer pipe
 * @last_data_desc - last DMA desc in data channel (tx/rx).
 * @last_cmd_desc - last DMA desc in command channel.
 * @txn_done - completion for NAND transfer.
 * @bam_ce_pos - the index in bam_ce which is available for next sgl
 * @bam_ce_start - the index in bam_ce which marks the start position ce
 *		   for current sgl. It will be used for size calculation
 *		   for current sgl
 * @cmd_sgl_pos - current index in command sgl.
 * @cmd_sgl_start - start index in command sgl.
 * @tx_sgl_pos - current index in data sgl for tx.
 * @tx_sgl_start - start index in data sgl for tx.
 * @rx_sgl_pos - current index in data sgl for rx.
 * @rx_sgl_start - start index in data sgl for rx.
 * @wait_second_completion - wait for second DMA desc completion before making
 *			     the NAND transfer completion.
 */
struct bam_transaction {};

/*
 * This data type corresponds to the nand dma descriptor
 * @dma_desc - low level DMA engine descriptor
 * @list - list for desc_info
 *
 * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
 *	      ADM
 * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
 * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
 * @dir - DMA transfer direction
 */
struct desc_info {};

/*
 * holds the current register values that we want to write. acts as a contiguous
 * chunk of memory which we use to write the controller registers through DMA.
 */
struct nandc_regs {};

/*
 * NAND controller data struct
 *
 * @dev:			parent device
 *
 * @base:			MMIO base
 *
 * @core_clk:			controller clock
 * @aon_clk:			another controller clock
 *
 * @regs:			a contiguous chunk of memory for DMA register
 *				writes. contains the register values to be
 *				written to controller
 *
 * @props:			properties of current NAND controller,
 *				initialized via DT match data
 *
 * @controller:			base controller structure
 * @host_list:			list containing all the chips attached to the
 *				controller
 *
 * @chan:			dma channel
 * @cmd_crci:			ADM DMA CRCI for command flow control
 * @data_crci:			ADM DMA CRCI for data flow control
 *
 * @desc_list:			DMA descriptor list (list of desc_infos)
 *
 * @data_buffer:		our local DMA buffer for page read/writes,
 *				used when we can't use the buffer provided
 *				by upper layers directly
 * @reg_read_buf:		local buffer for reading back registers via DMA
 *
 * @base_phys:			physical base address of controller registers
 * @base_dma:			dma base address of controller registers
 * @reg_read_dma:		contains dma address for register read buffer
 *
 * @buf_size/count/start:	markers for chip->legacy.read_buf/write_buf
 *				functions
 * @max_cwperpage:		maximum QPIC codewords required. calculated
 *				from all connected NAND devices pagesize
 *
 * @reg_read_pos:		marker for data read in reg_read_buf
 *
 * @cmd1/vld:			some fixed controller register values
 *
 * @exec_opwrite:		flag to select correct number of code word
 *				while reading status
 */
struct qcom_nand_controller {};

/*
 * NAND special boot partitions
 *
 * @page_offset:		offset of the partition where spare data is not protected
 *				by ECC (value in pages)
 * @page_offset:		size of the partition where spare data is not protected
 *				by ECC (value in pages)
 */
struct qcom_nand_boot_partition {};

/*
 * Qcom op for each exec_op transfer
 *
 * @data_instr:			data instruction pointer
 * @data_instr_idx:		data instruction index
 * @rdy_timeout_ms:		wait ready timeout in ms
 * @rdy_delay_ns:		Additional delay in ns
 * @addr1_reg:			Address1 register value
 * @addr2_reg:			Address2 register value
 * @cmd_reg:			CMD register value
 * @flag:			flag for misc instruction
 */
struct qcom_op {};

/*
 * NAND chip structure
 *
 * @boot_partitions:		array of boot partitions where offset and size of the
 *				boot partitions are stored
 *
 * @chip:			base NAND chip structure
 * @node:			list node to add itself to host_list in
 *				qcom_nand_controller
 *
 * @nr_boot_partitions:		count of the boot partitions where spare data is not
 *				protected by ECC
 *
 * @cs:				chip select value for this chip
 * @cw_size:			the number of bytes in a single step/codeword
 *				of a page, consisting of all data, ecc, spare
 *				and reserved bytes
 * @cw_data:			the number of bytes within a codeword protected
 *				by ECC
 * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
 *				chip
 *
 * @last_command:		keeps track of last command on this chip. used
 *				for reading correct status
 *
 * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
 *				ecc/non-ecc mode for the current nand flash
 *				device
 *
 * @status:			value to be returned if NAND_CMD_STATUS command
 *				is executed
 * @codeword_fixup:		keep track of the current layout used by
 *				the driver for read/write operation.
 * @use_ecc:			request the controller to use ECC for the
 *				upcoming read/write
 * @bch_enabled:		flag to tell whether BCH ECC mode is used
 */
struct qcom_nand_host {};

/*
 * This data type corresponds to the NAND controller properties which varies
 * among different NAND controllers.
 * @ecc_modes - ecc mode for NAND
 * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
 * @is_bam - whether NAND controller is using BAM
 * @is_qpic - whether NAND CTRL is part of qpic IP
 * @qpic_v2 - flag to indicate QPIC IP version 2
 * @use_codeword_fixup - whether NAND has different layout for boot partitions
 */
struct qcom_nandc_props {};

/* Frees the BAM transaction memory */
static void free_bam_transaction(struct qcom_nand_controller *nandc)
{}

/* Allocates and Initializes the BAM transaction */
static struct bam_transaction *
alloc_bam_transaction(struct qcom_nand_controller *nandc)
{}

/* Clears the BAM transaction indexes */
static void clear_bam_transaction(struct qcom_nand_controller *nandc)
{}

/* Callback for DMA descriptor completion */
static void qpic_bam_dma_done(void *data)
{}

static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
{}

static inline struct qcom_nand_controller *
get_qcom_nand_controller(struct nand_chip *chip)
{}

static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
{}

static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
			       u32 val)
{}

static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
					  bool is_cpu)
{}

static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
{}

static void nandc_set_reg(struct nand_chip *chip, int offset,
			  u32 val)
{}

/* Helper to check the code word, whether it is last cw or not */
static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
{}

/* helper to configure location register values */
static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
			       int cw_offset, int read_size, int is_last_read_loc)
{}

/* helper to configure address register values */
static void set_address(struct qcom_nand_host *host, u16 column, int page)
{}

/*
 * update_rw_regs:	set up read/write register values, these will be
 *			written to the NAND controller registers via DMA
 *
 * @num_cw:		number of steps for the read/write operation
 * @read:		read or write operation
 * @cw	:		which code word
 */
static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
{}

/*
 * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
 * for BAM. This descriptor will be added in the NAND DMA descriptor queue
 * which will be submitted to DMA engine.
 */
static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
				  struct dma_chan *chan,
				  unsigned long flags)
{}

/*
 * Prepares the command descriptor for BAM DMA which will be used for NAND
 * register reads and writes. The command descriptor requires the command
 * to be formed in command element type so this function uses the command
 * element from bam transaction ce array and fills the same with required
 * data. A single SGL can contain multiple command elements so
 * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
 * after the current command element.
 */
static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
				 int reg_off, const void *vaddr,
				 int size, unsigned int flags)
{}

/*
 * Prepares the data descriptor for BAM DMA which will be used for NAND
 * data reads and writes.
 */
static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
				  const void *vaddr,
				  int size, unsigned int flags)
{}

static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
			     int reg_off, const void *vaddr, int size,
			     bool flow_control)
{}

/*
 * read_reg_dma:	prepares a descriptor to read a given number of
 *			contiguous registers to the reg_read_buf pointer
 *
 * @first:		offset of the first register in the contiguous block
 * @num_regs:		number of registers to read
 * @flags:		flags to control DMA descriptor preparation
 */
static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
			int num_regs, unsigned int flags)
{}

/*
 * write_reg_dma:	prepares a descriptor to write a given number of
 *			contiguous registers
 *
 * @first:		offset of the first register in the contiguous block
 * @num_regs:		number of registers to write
 * @flags:		flags to control DMA descriptor preparation
 */
static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
			 int num_regs, unsigned int flags)
{}

/*
 * read_data_dma:	prepares a DMA descriptor to transfer data from the
 *			controller's internal buffer to the buffer 'vaddr'
 *
 * @reg_off:		offset within the controller's data buffer
 * @vaddr:		virtual address of the buffer we want to write to
 * @size:		DMA transaction size in bytes
 * @flags:		flags to control DMA descriptor preparation
 */
static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
			 const u8 *vaddr, int size, unsigned int flags)
{}

/*
 * write_data_dma:	prepares a DMA descriptor to transfer data from
 *			'vaddr' to the controller's internal buffer
 *
 * @reg_off:		offset within the controller's data buffer
 * @vaddr:		virtual address of the buffer we want to read from
 * @size:		DMA transaction size in bytes
 * @flags:		flags to control DMA descriptor preparation
 */
static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
			  const u8 *vaddr, int size, unsigned int flags)
{}

/*
 * Helper to prepare DMA descriptors for configuring registers
 * before reading a NAND page.
 */
static void config_nand_page_read(struct nand_chip *chip)
{}

/*
 * Helper to prepare DMA descriptors for configuring registers
 * before reading each codeword in NAND page.
 */
static void
config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw)
{}

/*
 * Helper to prepare dma descriptors to configure registers needed for reading a
 * single codeword in page
 */
static void
config_nand_single_cw_page_read(struct nand_chip *chip,
				bool use_ecc, int cw)
{}

/*
 * Helper to prepare DMA descriptors used to configure registers needed for
 * before writing a NAND page.
 */
static void config_nand_page_write(struct nand_chip *chip)
{}

/*
 * Helper to prepare DMA descriptors for configuring registers
 * before writing each codeword in NAND page.
 */
static void config_nand_cw_write(struct nand_chip *chip)
{}

/* helpers to submit/free our list of dma descriptors */
static int submit_descs(struct qcom_nand_controller *nandc)
{}

/* reset the register read buffer for next NAND operation */
static void clear_read_regs(struct qcom_nand_controller *nandc)
{}

/*
 * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
 * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
 *
 * when using RS ECC, the HW reports the same erros when reading an erased CW,
 * but it notifies that it is an erased CW by placing special characters at
 * certain offsets in the buffer.
 *
 * verify if the page is erased or not, and fix up the page for RS ECC by
 * replacing the special characters with 0xff.
 */
static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
{}

struct read_stats {};

/* reads back FLASH_STATUS register set by the controller */
static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
{}

/* performs raw read for one codeword */
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)
{}

/*
 * Bitflips can happen in erased codewords also so this function counts the
 * number of 0 in each CW for which ECC engine returns the uncorrectable
 * error. The page will be assumed as erased if this count is less than or
 * equal to the ecc->strength for each CW.
 *
 * 1. Both DATA and OOB need to be checked for number of 0. The
 *    top-level API can be called with only data buf or OOB buf so use
 *    chip->data_buf if data buf is null and chip->oob_poi if oob buf
 *    is null for copying the raw bytes.
 * 2. Perform raw read for all the CW which has uncorrectable errors.
 * 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
 *    The BBM and spare bytes bit flip won’t affect the ECC so don’t check
 *    the number of bitflips in this area.
 */
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)
{}

/*
 * reads back status registers set by the controller to notify page read
 * errors. this is equivalent to what 'ecc->correct()' would do.
 */
static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
			     u8 *oob_buf, int page)
{}

/*
 * helper to perform the actual page read operation, used by ecc->read_page(),
 * ecc->read_oob()
 */
static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
			 u8 *oob_buf, int page)
{}

/*
 * a helper that copies the last step/codeword of a page (containing free oob)
 * into our local buffer
 */
static int copy_last_cw(struct qcom_nand_host *host, int page)
{}

static bool qcom_nandc_is_boot_partition(struct qcom_nand_host *host, int page)
{}

static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page)
{}

/* implements ecc->read_page() */
static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf,
				int oob_required, int page)
{}

/* implements ecc->read_page_raw() */
static int qcom_nandc_read_page_raw(struct nand_chip *chip, u8 *buf,
				    int oob_required, int page)
{}

/* implements ecc->read_oob() */
static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
{}

/* implements ecc->write_page() */
static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf,
				 int oob_required, int page)
{}

/* implements ecc->write_page_raw() */
static int qcom_nandc_write_page_raw(struct nand_chip *chip,
				     const u8 *buf, int oob_required,
				     int page)
{}

/*
 * implements ecc->write_oob()
 *
 * the NAND controller cannot write only data or only OOB within a codeword
 * since ECC is calculated for the combined codeword. So update the OOB from
 * chip->oob_poi, and pad the data area with OxFF before writing.
 */
static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
{}

static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
{}

static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
{}

/*
 * NAND controller page layout info
 *
 * Layout with ECC enabled:
 *
 * |----------------------|  |---------------------------------|
 * |           xx.......yy|  |             *********xx.......yy|
 * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
 * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
 * |           xx.......yy|  |             *********xx.......yy|
 * |----------------------|  |---------------------------------|
 *     codeword 1,2..n-1                  codeword n
 *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
 *
 * n = Number of codewords in the page
 * . = ECC bytes
 * * = Spare/free bytes
 * x = Unused byte(s)
 * y = Reserved byte(s)
 *
 * 2K page: n = 4, spare = 16 bytes
 * 4K page: n = 8, spare = 32 bytes
 * 8K page: n = 16, spare = 64 bytes
 *
 * the qcom nand controller operates at a sub page/codeword level. each
 * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
 * the number of ECC bytes vary based on the ECC strength and the bus width.
 *
 * the first n - 1 codewords contains 516 bytes of user data, the remaining
 * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
 * both user data and spare(oobavail) bytes that sum up to 516 bytes.
 *
 * When we access a page with ECC enabled, the reserved bytes(s) are not
 * accessible at all. When reading, we fill up these unreadable positions
 * with 0xffs. When writing, the controller skips writing the inaccessible
 * bytes.
 *
 * Layout with ECC disabled:
 *
 * |------------------------------|  |---------------------------------------|
 * |         yy          xx.......|  |         bb          *********xx.......|
 * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
 * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
 * |         yy          xx.......|  |         bb          *********xx.......|
 * |------------------------------|  |---------------------------------------|
 *         codeword 1,2..n-1                        codeword n
 *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
 *
 * n = Number of codewords in the page
 * . = ECC bytes
 * * = Spare/free bytes
 * x = Unused byte(s)
 * y = Dummy Bad Bock byte(s)
 * b = Real Bad Block byte(s)
 * size1/size2 = function of codeword size and 'n'
 *
 * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
 * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
 * Block Markers. In the last codeword, this position contains the real BBM
 *
 * In order to have a consistent layout between RAW and ECC modes, we assume
 * the following OOB layout arrangement:
 *
 * |-----------|  |--------------------|
 * |yyxx.......|  |bb*********xx.......|
 * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
 * |yyxx.......|  |bb*********xx.......|
 * |yyxx.......|  |bb*********xx.......|
 * |-----------|  |--------------------|
 *  first n - 1       nth OOB region
 *  OOB regions
 *
 * n = Number of codewords in the page
 * . = ECC bytes
 * * = FREE OOB bytes
 * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
 * x = Unused byte(s)
 * b = Real bad block byte(s) (inaccessible when ECC enabled)
 *
 * This layout is read as is when ECC is disabled. When ECC is enabled, the
 * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
 * and assumed as 0xffs when we read a page/oob. The ECC, unused and
 * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
 * the sum of the three).
 */
static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
				   struct mtd_oob_region *oobregion)
{}

static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
				    struct mtd_oob_region *oobregion)
{}

static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops =;

static int
qcom_nandc_calc_ecc_bytes(int step_size, int strength)
{}

NAND_ECC_CAPS_SINGLE();

static int qcom_nand_attach_chip(struct nand_chip *chip)
{}

static int qcom_op_cmd_mapping(struct nand_chip *chip, u8 opcode,
			       struct qcom_op *q_op)
{}

/* NAND framework ->exec_op() hooks and related helpers */
static int qcom_parse_instructions(struct nand_chip *chip,
				    const struct nand_subop *subop,
				    struct qcom_op *q_op)
{}

static void qcom_delay_ns(unsigned int ns)
{}

static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms)
{}

static int qcom_read_status_exec(struct nand_chip *chip,
				 const struct nand_subop *subop)
{}

static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop)
{}

static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop)
{}

static int qcom_param_page_type_exec(struct nand_chip *chip,  const struct nand_subop *subop)
{}

static const struct nand_op_parser qcom_op_parser =;

static int qcom_check_op(struct nand_chip *chip,
			 const struct nand_operation *op)
{}

static int qcom_nand_exec_op(struct nand_chip *chip,
			     const struct nand_operation *op, bool check_only)
{}

static const struct nand_controller_ops qcom_nandc_ops =;

static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
{}

static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
{}

/* one time setup of a few nand controller registers */
static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
{}

static const char * const probes[] =;

static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nandc,
						struct qcom_nand_host *host,
						struct device_node *dn)
{}

static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
					    struct qcom_nand_host *host,
					    struct device_node *dn)
{}

static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
{}

/* parse custom DT properties here */
static int qcom_nandc_parse_dt(struct platform_device *pdev)
{}

static int qcom_nandc_probe(struct platform_device *pdev)
{}

static void qcom_nandc_remove(struct platform_device *pdev)
{}

static const struct qcom_nandc_props ipq806x_nandc_props =;

static const struct qcom_nandc_props ipq4019_nandc_props =;

static const struct qcom_nandc_props ipq8074_nandc_props =;

static const struct qcom_nandc_props sdx55_nandc_props =;

/*
 * data will hold a struct pointer containing more differences once we support
 * more controller variants
 */
static const struct of_device_id qcom_nandc_of_match[] =;
MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);

static struct platform_driver qcom_nandc_driver =;
module_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();