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

// SPDX-License-Identifier: GPL-2.0
/*
 * Marvell NAND flash controller driver
 *
 * Copyright (C) 2017 Marvell
 * Author: Miquel RAYNAL <[email protected]>
 *
 *
 * This NAND controller driver handles two versions of the hardware,
 * one is called NFCv1 and is available on PXA SoCs and the other is
 * called NFCv2 and is available on Armada SoCs.
 *
 * The main visible difference is that NFCv1 only has Hamming ECC
 * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
 * is not used with NFCv2.
 *
 * The ECC layouts are depicted in details in Marvell AN-379, but here
 * is a brief description.
 *
 * When using Hamming, the data is split in 512B chunks (either 1, 2
 * or 4) and each chunk will have its own ECC "digest" of 6B at the
 * beginning of the OOB area and eventually the remaining free OOB
 * bytes (also called "spare" bytes in the driver). This engine
 * corrects up to 1 bit per chunk and detects reliably an error if
 * there are at most 2 bitflips. Here is the page layout used by the
 * controller when Hamming is chosen:
 *
 * +-------------------------------------------------------------+
 * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
 * +-------------------------------------------------------------+
 *
 * When using the BCH engine, there are N identical (data + free OOB +
 * ECC) sections and potentially an extra one to deal with
 * configurations where the chosen (data + free OOB + ECC) sizes do
 * not align with the page (data + OOB) size. ECC bytes are always
 * 30B per ECC chunk. Here is the page layout used by the controller
 * when BCH is chosen:
 *
 * +-----------------------------------------
 * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
 * +-----------------------------------------
 *
 *      -------------------------------------------
 *       ... | Data N | Free OOB bytes N | ECC N |
 *      -------------------------------------------
 *
 *           --------------------------------------------+
 *            Last Data | Last Free OOB bytes | Last ECC |
 *           --------------------------------------------+
 *
 * In both cases, the layout seen by the user is always: all data
 * first, then all free OOB bytes and finally all ECC bytes. With BCH,
 * ECC bytes are 30B long and are padded with 0xFF to align on 32
 * bytes.
 *
 * The controller has certain limitations that are handled by the
 * driver:
 *   - It can only read 2k at a time. To overcome this limitation, the
 *     driver issues data cycles on the bus, without issuing new
 *     CMD + ADDR cycles. The Marvell term is "naked" operations.
 *   - The ECC strength in BCH mode cannot be tuned. It is fixed 16
 *     bits. What can be tuned is the ECC block size as long as it
 *     stays between 512B and 2kiB. It's usually chosen based on the
 *     chip ECC requirements. For instance, using 2kiB ECC chunks
 *     provides 4b/512B correctability.
 *   - The controller will always treat data bytes, free OOB bytes
 *     and ECC bytes in that order, no matter what the real layout is
 *     (which is usually all data then all OOB bytes). The
 *     marvell_nfc_layouts array below contains the currently
 *     supported layouts.
 *   - Because of these weird layouts, the Bad Block Markers can be
 *     located in data section. In this case, the NAND_BBT_NO_OOB_BBM
 *     option must be set to prevent scanning/writing bad block
 *     markers.
 */

#include <linux/module.h>
#include <linux/clk.h>
#include <linux/mtd/rawnand.h>
#include <linux/of.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/unaligned.h>

#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/dma/pxa-dma.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>

/* Data FIFO granularity, FIFO reads/writes must be a multiple of this length */
#define FIFO_DEPTH
#define FIFO_REP(x)
#define BCH_SEQ_READS
/* NFC does not support transfers of larger chunks at a time */
#define MAX_CHUNK_SIZE
/* NFCv1 cannot read more that 7 bytes of ID */
#define NFCV1_READID_LEN
/* Polling is done at a pace of POLL_PERIOD us until POLL_TIMEOUT is reached */
#define POLL_PERIOD
#define POLL_TIMEOUT
/* Interrupt maximum wait period in ms */
#define IRQ_TIMEOUT
/* Latency in clock cycles between SoC pins and NFC logic */
#define MIN_RD_DEL_CNT
/* Maximum number of contiguous address cycles */
#define MAX_ADDRESS_CYC_NFCV1
#define MAX_ADDRESS_CYC_NFCV2
/* System control registers/bits to enable the NAND controller on some SoCs */
#define GENCONF_SOC_DEVICE_MUX
#define GENCONF_SOC_DEVICE_MUX_NFC_EN
#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST
#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST
#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN
#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN
#define GENCONF_CLK_GATING_CTRL
#define GENCONF_CLK_GATING_CTRL_ND_GATE
#define GENCONF_ND_CLK_CTRL
#define GENCONF_ND_CLK_CTRL_EN

/* NAND controller data flash control register */
#define NDCR
#define NDCR_ALL_INT
#define NDCR_CS1_CMDDM
#define NDCR_CS0_CMDDM
#define NDCR_RDYM
#define NDCR_ND_ARB_EN
#define NDCR_RA_START
#define NDCR_RD_ID_CNT(x)
#define NDCR_PAGE_SZ(x)
#define NDCR_DWIDTH_M
#define NDCR_DWIDTH_C
#define NDCR_ND_RUN
#define NDCR_DMA_EN
#define NDCR_ECC_EN
#define NDCR_SPARE_EN
#define NDCR_GENERIC_FIELDS_MASK

/* NAND interface timing parameter 0 register */
#define NDTR0
#define NDTR0_TRP(x)
#define NDTR0_TRH(x)
#define NDTR0_ETRP(x)
#define NDTR0_SEL_NRE_EDGE
#define NDTR0_TWP(x)
#define NDTR0_TWH(x)
#define NDTR0_TCS(x)
#define NDTR0_TCH(x)
#define NDTR0_RD_CNT_DEL(x)
#define NDTR0_SELCNTR
#define NDTR0_TADL(x)

/* NAND interface timing parameter 1 register */
#define NDTR1
#define NDTR1_TAR(x)
#define NDTR1_TWHR(x)
#define NDTR1_TRHW(x)
#define NDTR1_PRESCALE
#define NDTR1_WAIT_MODE
#define NDTR1_TR(x)

/* NAND controller status register */
#define NDSR
#define NDSR_WRCMDREQ
#define NDSR_RDDREQ
#define NDSR_WRDREQ
#define NDSR_CORERR
#define NDSR_UNCERR
#define NDSR_CMDD(cs)
#define NDSR_RDY(rb)
#define NDSR_ERRCNT(x)

/* NAND ECC control register */
#define NDECCCTRL
#define NDECCCTRL_BCH_EN

/* NAND controller data buffer register */
#define NDDB

/* NAND controller command buffer 0 register */
#define NDCB0
#define NDCB0_CMD1(x)
#define NDCB0_CMD2(x)
#define NDCB0_ADDR_CYC(x)
#define NDCB0_ADDR_GET_NUM_CYC(x)
#define NDCB0_DBC
#define NDCB0_CMD_TYPE(x)
#define NDCB0_CSEL
#define NDCB0_RDY_BYP
#define NDCB0_LEN_OVRD
#define NDCB0_CMD_XTYPE(x)

/* NAND controller command buffer 1 register */
#define NDCB1
#define NDCB1_COLS(x)
#define NDCB1_ADDRS_PAGE(x)

/* NAND controller command buffer 2 register */
#define NDCB2
#define NDCB2_ADDR5_PAGE(x)
#define NDCB2_ADDR5_CYC(x)

/* NAND controller command buffer 3 register */
#define NDCB3
#define NDCB3_ADDR6_CYC(x)
#define NDCB3_ADDR7_CYC(x)

/* NAND controller command buffer 0 register 'type' and 'xtype' fields */
#define TYPE_READ
#define TYPE_WRITE
#define TYPE_ERASE
#define TYPE_READ_ID
#define TYPE_STATUS
#define TYPE_RESET
#define TYPE_NAKED_CMD
#define TYPE_NAKED_ADDR
#define TYPE_MASK
#define XTYPE_MONOLITHIC_RW
#define XTYPE_LAST_NAKED_RW
#define XTYPE_FINAL_COMMAND
#define XTYPE_READ
#define XTYPE_WRITE_DISPATCH
#define XTYPE_NAKED_RW
#define XTYPE_COMMAND_DISPATCH
#define XTYPE_MASK

/**
 * struct marvell_hw_ecc_layout - layout of Marvell ECC
 *
 * Marvell ECC engine works differently than the others, in order to limit the
 * size of the IP, hardware engineers chose to set a fixed strength at 16 bits
 * per subpage, and depending on a the desired strength needed by the NAND chip,
 * a particular layout mixing data/spare/ecc is defined, with a possible last
 * chunk smaller that the others.
 *
 * @writesize:		Full page size on which the layout applies
 * @chunk:		Desired ECC chunk size on which the layout applies
 * @strength:		Desired ECC strength (per chunk size bytes) on which the
 *			layout applies
 * @nchunks:		Total number of chunks
 * @full_chunk_cnt:	Number of full-sized chunks, which is the number of
 *			repetitions of the pattern:
 *			(data_bytes + spare_bytes + ecc_bytes).
 * @data_bytes:		Number of data bytes per chunk
 * @spare_bytes:	Number of spare bytes per chunk
 * @ecc_bytes:		Number of ecc bytes per chunk
 * @last_data_bytes:	Number of data bytes in the last chunk
 * @last_spare_bytes:	Number of spare bytes in the last chunk
 * @last_ecc_bytes:	Number of ecc bytes in the last chunk
 */
struct marvell_hw_ecc_layout {};

#define MARVELL_LAYOUT(ws, dc, ds, nc, fcc, db, sb, eb, ldb, lsb, leb)

/* Layouts explained in AN-379_Marvell_SoC_NFC_ECC */
static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] =;

/**
 * struct marvell_nand_chip_sel - CS line description
 *
 * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
 * is made by a field in NDCB0 register, and in another field in NDCB2 register.
 * The datasheet describes the logic with an error: ADDR5 field is once
 * declared at the beginning of NDCB2, and another time at its end. Because the
 * ADDR5 field of NDCB2 may be used by other bytes, it would be more logical
 * to use the last bit of this field instead of the first ones.
 *
 * @cs:			Wanted CE lane.
 * @ndcb0_csel:		Value of the NDCB0 register with or without the flag
 *			selecting the wanted CE lane. This is set once when
 *			the Device Tree is probed.
 * @rb:			Ready/Busy pin for the flash chip
 */
struct marvell_nand_chip_sel {};

/**
 * struct marvell_nand_chip - stores NAND chip device related information
 *
 * @chip:		Base NAND chip structure
 * @node:		Used to store NAND chips into a list
 * @layout:		NAND layout when using hardware ECC
 * @ndcr:		Controller register value for this NAND chip
 * @ndtr0:		Timing registers 0 value for this NAND chip
 * @ndtr1:		Timing registers 1 value for this NAND chip
 * @addr_cyc:		Amount of cycles needed to pass column address
 * @selected_die:	Current active CS
 * @nsels:		Number of CS lines required by the NAND chip
 * @sels:		Array of CS lines descriptions
 */
struct marvell_nand_chip {};

static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip)
{}

static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
							*nand)
{}

/**
 * struct marvell_nfc_caps - NAND controller capabilities for distinction
 *                           between compatible strings
 *
 * @max_cs_nb:		Number of Chip Select lines available
 * @max_rb_nb:		Number of Ready/Busy lines available
 * @need_system_controller: Indicates if the SoC needs to have access to the
 *                      system controller (ie. to enable the NAND controller)
 * @legacy_of_bindings:	Indicates if DT parsing must be done using the old
 *			fashion way
 * @is_nfcv2:		NFCv2 has numerous enhancements compared to NFCv1, ie.
 *			BCH error detection and correction algorithm,
 *			NDCB3 register has been added
 * @use_dma:		Use dma for data transfers
 * @max_mode_number:	Maximum timing mode supported by the controller
 */
struct marvell_nfc_caps {};

/**
 * struct marvell_nfc - stores Marvell NAND controller information
 *
 * @controller:		Base controller structure
 * @dev:		Parent device (used to print error messages)
 * @regs:		NAND controller registers
 * @core_clk:		Core clock
 * @reg_clk:		Registers clock
 * @complete:		Completion object to wait for NAND controller events
 * @assigned_cs:	Bitmask describing already assigned CS lines
 * @chips:		List containing all the NAND chips attached to
 *			this NAND controller
 * @selected_chip:	Currently selected target chip
 * @caps:		NAND controller capabilities for each compatible string
 * @use_dma:		Whetner DMA is used
 * @dma_chan:		DMA channel (NFCv1 only)
 * @dma_buf:		32-bit aligned buffer for DMA transfers (NFCv1 only)
 */
struct marvell_nfc {};

static inline struct marvell_nfc *to_marvell_nfc(struct nand_controller *ctrl)
{}

/**
 * struct marvell_nfc_timings - NAND controller timings expressed in NAND
 *                              Controller clock cycles
 *
 * @tRP:		ND_nRE pulse width
 * @tRH:		ND_nRE high duration
 * @tWP:		ND_nWE pulse time
 * @tWH:		ND_nWE high duration
 * @tCS:		Enable signal setup time
 * @tCH:		Enable signal hold time
 * @tADL:		Address to write data delay
 * @tAR:		ND_ALE low to ND_nRE low delay
 * @tWHR:		ND_nWE high to ND_nRE low for status read
 * @tRHW:		ND_nRE high duration, read to write delay
 * @tR:			ND_nWE high to ND_nRE low for read
 */
struct marvell_nfc_timings {};

/**
 * TO_CYCLES() - Derives a duration in numbers of clock cycles.
 *
 * @ps: Duration in pico-seconds
 * @period_ns:  Clock period in nano-seconds
 *
 * Convert the duration in nano-seconds, then divide by the period and
 * return the number of clock periods.
 */
#define TO_CYCLES(ps, period_ns)
#define TO_CYCLES64(ps, period_ns)

/**
 * struct marvell_nfc_op - filled during the parsing of the ->exec_op()
 *                         subop subset of instructions.
 *
 * @ndcb:		Array of values written to NDCBx registers
 * @cle_ale_delay_ns:	Optional delay after the last CMD or ADDR cycle
 * @rdy_timeout_ms:	Timeout for waits on Ready/Busy pin
 * @rdy_delay_ns:	Optional delay after waiting for the RB pin
 * @data_delay_ns:	Optional delay after the data xfer
 * @data_instr_idx:	Index of the data instruction in the subop
 * @data_instr:		Pointer to the data instruction in the subop
 */
struct marvell_nfc_op {};

/*
 * Internal helper to conditionnally apply a delay (from the above structure,
 * most of the time).
 */
static void cond_delay(unsigned int ns)
{}

/*
 * The controller has many flags that could generate interrupts, most of them
 * are disabled and polling is used. For the very slow signals, using interrupts
 * may relax the CPU charge.
 */
static void marvell_nfc_disable_int(struct marvell_nfc *nfc, u32 int_mask)
{}

static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
{}

static u32 marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
{}

static void marvell_nfc_force_byte_access(struct nand_chip *chip,
					  bool force_8bit)
{}

static int marvell_nfc_wait_ndrun(struct nand_chip *chip)
{}

/*
 * Any time a command has to be sent to the controller, the following sequence
 * has to be followed:
 * - call marvell_nfc_prepare_cmd()
 *      -> activate the ND_RUN bit that will kind of 'start a job'
 *      -> wait the signal indicating the NFC is waiting for a command
 * - send the command (cmd and address cycles)
 * - enventually send or receive the data
 * - call marvell_nfc_end_cmd() with the corresponding flag
 *      -> wait the flag to be triggered or cancel the job with a timeout
 *
 * The following helpers are here to factorize the code a bit so that
 * specialized functions responsible for executing the actual NAND
 * operations do not have to replicate the same code blocks.
 */
static int marvell_nfc_prepare_cmd(struct nand_chip *chip)
{}

static void marvell_nfc_send_cmd(struct nand_chip *chip,
				 struct marvell_nfc_op *nfc_op)
{}

static int marvell_nfc_end_cmd(struct nand_chip *chip, int flag,
			       const char *label)
{}

static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
{}

static int marvell_nfc_poll_status(struct marvell_nfc *nfc, u32 mask,
				   u32 expected_val, unsigned long timeout_ms)
{}

static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
{}

static void marvell_nfc_select_target(struct nand_chip *chip,
				      unsigned int die_nr)
{}

static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
{}

/* HW ECC related functions */
static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
{}

static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
{}

/* DMA related helpers */
static void marvell_nfc_enable_dma(struct marvell_nfc *nfc)
{}

static void marvell_nfc_disable_dma(struct marvell_nfc *nfc)
{}

/* Read/write PIO/DMA accessors */
static int marvell_nfc_xfer_data_dma(struct marvell_nfc *nfc,
				     enum dma_data_direction direction,
				     unsigned int len)
{}

static int marvell_nfc_xfer_data_in_pio(struct marvell_nfc *nfc, u8 *in,
					unsigned int len)
{}

static int marvell_nfc_xfer_data_out_pio(struct marvell_nfc *nfc, const u8 *out,
					 unsigned int len)
{}

static void marvell_nfc_check_empty_chunk(struct nand_chip *chip,
					  u8 *data, int data_len,
					  u8 *spare, int spare_len,
					  u8 *ecc, int ecc_len,
					  unsigned int *max_bitflips)
{}

/*
 * Check if a chunk is correct or not according to the hardware ECC engine.
 * mtd->ecc_stats.corrected is updated, as well as max_bitflips, however
 * mtd->ecc_stats.failure is not, the function will instead return a non-zero
 * value indicating that a check on the emptyness of the subpage must be
 * performed before actually declaring the subpage as "corrupted".
 */
static int marvell_nfc_hw_ecc_check_bitflips(struct nand_chip *chip,
					     unsigned int *max_bitflips)
{}

/* Hamming read helpers */
static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
					       u8 *data_buf, u8 *oob_buf,
					       bool raw, int page)
{}

static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
						int oob_required, int page)
{}

static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
					    int oob_required, int page)
{}

/*
 * Spare area in Hamming layouts is not protected by the ECC engine (even if
 * it appears before the ECC bytes when reading), the ->read_oob_raw() function
 * also stands for ->read_oob().
 */
static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
{}

/* Hamming write helpers */
static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
						const u8 *data_buf,
						const u8 *oob_buf, bool raw,
						int page)
{}

static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
						 const u8 *buf,
						 int oob_required, int page)
{}

static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
					     const u8 *buf,
					     int oob_required, int page)
{}

/*
 * Spare area in Hamming layouts is not protected by the ECC engine (even if
 * it appears before the ECC bytes when reading), the ->write_oob_raw() function
 * also stands for ->write_oob().
 */
static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
						int page)
{}

/* BCH read helpers */
static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
						int oob_required, int page)
{}

static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
					      u8 *data, unsigned int data_len,
					      u8 *spare, unsigned int spare_len,
					      int page)
{}

static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
					    u8 *buf, int oob_required,
					    int page)
{}

static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
{}

static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
{}

/* BCH write helpers */
static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
						 const u8 *buf,
						 int oob_required, int page)
{}

static int
marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
				   const u8 *data, unsigned int data_len,
				   const u8 *spare, unsigned int spare_len,
				   int page)
{}

static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
					     const u8 *buf,
					     int oob_required, int page)
{}

static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
						int page)
{}

static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
{}

/* NAND framework ->exec_op() hooks and related helpers */
static void marvell_nfc_parse_instructions(struct nand_chip *chip,
					   const struct nand_subop *subop,
					   struct marvell_nfc_op *nfc_op)
{}

static int marvell_nfc_xfer_data_pio(struct nand_chip *chip,
				     const struct nand_subop *subop,
				     struct marvell_nfc_op *nfc_op)
{}

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

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

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

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

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

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

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

static const struct nand_op_parser marvell_nfcv2_op_parser =;

static const struct nand_op_parser marvell_nfcv1_op_parser =;

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

/*
 * Layouts were broken in old pxa3xx_nand driver, these are supposed to be
 * usable.
 */
static int marvell_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
				      struct mtd_oob_region *oobregion)
{}

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

static const struct mtd_ooblayout_ops marvell_nand_ooblayout_ops =;

static int marvell_nand_hw_ecc_controller_init(struct mtd_info *mtd,
					       struct nand_ecc_ctrl *ecc)
{}

static int marvell_nand_ecc_init(struct mtd_info *mtd,
				 struct nand_ecc_ctrl *ecc)
{}

static u8 bbt_pattern[] =;
static u8 bbt_mirror_pattern[] =;

static struct nand_bbt_descr bbt_main_descr =;

static struct nand_bbt_descr bbt_mirror_descr =;

static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr,
				       const struct nand_interface_config *conf)
{}

static int marvell_nand_attach_chip(struct nand_chip *chip)
{}

static const struct nand_controller_ops marvell_nand_controller_ops =;

static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
				  struct device_node *np)
{}

static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
{}

static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
{}

static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
{}

static void marvell_nfc_reset(struct marvell_nfc *nfc)
{}

static int marvell_nfc_init(struct marvell_nfc *nfc)
{}

static int marvell_nfc_probe(struct platform_device *pdev)
{}

static void marvell_nfc_remove(struct platform_device *pdev)
{}

static int __maybe_unused marvell_nfc_suspend(struct device *dev)
{}

static int __maybe_unused marvell_nfc_resume(struct device *dev)
{}

static const struct dev_pm_ops marvell_nfc_pm_ops =;

static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps =;

static const struct marvell_nfc_caps marvell_ac5_caps =;

static const struct marvell_nfc_caps marvell_armada370_nfc_caps =;

static const struct marvell_nfc_caps marvell_pxa3xx_nfc_caps =;

static const struct marvell_nfc_caps marvell_armada_8k_nfc_legacy_caps =;

static const struct marvell_nfc_caps marvell_armada370_nfc_legacy_caps =;

static const struct marvell_nfc_caps marvell_pxa3xx_nfc_legacy_caps =;

static const struct platform_device_id marvell_nfc_platform_ids[] =;
MODULE_DEVICE_TABLE(platform, marvell_nfc_platform_ids);

static const struct of_device_id marvell_nfc_of_ids[] =;
MODULE_DEVICE_TABLE(of, marvell_nfc_of_ids);

static struct platform_driver marvell_nfc_driver =;
module_platform_driver();

MODULE_LICENSE();
MODULE_DESCRIPTION();