[U-Boot] [PATCH v2 1/2] mtd: nand : zynq_nand: Add nand driver support for zynq

Siva Durga Prasad Paladugu siva.durga.paladugu at xilinx.com
Mon Sep 26 08:59:42 CEST 2016


Hi Michal,

> -----Original Message-----
> From: Michal Simek [mailto:michal.simek at xilinx.com]
> Sent: Monday, September 26, 2016 12:12 PM
> To: Siva Durga Prasad Paladugu <sivadur at xilinx.com>; u-boot at lists.denx.de
> Cc: oss at buserror.net; Siva Durga Prasad Paladugu <sivadur at xilinx.com>
> Subject: Re: [PATCH v2 1/2] mtd: nand : zynq_nand: Add nand driver support
> for zynq
> 
> On 23.9.2016 14:50, Siva Durga Prasad Paladugu wrote:
> > Add nand flash controller driver support for zynq SoC.
> >
> > Signed-off-by: Siva Durga Prasad Paladugu <sivadur at xilinx.com>
> > ---
> > Changes for v2:
> > - corrected the from address
> > ---
> >  drivers/mtd/nand/Kconfig     |    7 +
> >  drivers/mtd/nand/Makefile    |    1 +
> >  drivers/mtd/nand/zynq_nand.c | 1186
> > ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 1194 insertions(+)
> >  create mode 100644 drivers/mtd/nand/zynq_nand.c
> >
> > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index
> > 5ce7d6d..7e5c436 100644
> > --- a/drivers/mtd/nand/Kconfig
> > +++ b/drivers/mtd/nand/Kconfig
> > @@ -80,6 +80,13 @@ config NAND_ARASAN
> >  	  controller. This uses the hardware ECC for read and
> >  	  write operations.
> >
> > +config NAND_ZYNQ
> > +	bool "Support for Zynq Nand controller"
> > +	select SYS_NAND_SELF_INIT
> > +	help
> > +	  This enables Nand driver support for Nand flash controller
> > +	  found on Zynq SoC.
> > +
> >  comment "Generic NAND options"
> >
> >  # Enhance depends when converting drivers to Kconfig which use this
> > config diff --git a/drivers/mtd/nand/Makefile
> > b/drivers/mtd/nand/Makefile index 1df9273..fd4bb66 100644
> > --- a/drivers/mtd/nand/Makefile
> > +++ b/drivers/mtd/nand/Makefile
> > @@ -67,6 +67,7 @@ obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
> >  obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
> >  obj-$(CONFIG_NAND_PLAT) += nand_plat.o
> >  obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
> > +obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
> >
> >  else  # minimal SPL drivers
> >
> > diff --git a/drivers/mtd/nand/zynq_nand.c
> > b/drivers/mtd/nand/zynq_nand.c new file mode 100644 index
> > 0000000..a0003a4
> > --- /dev/null
> > +++ b/drivers/mtd/nand/zynq_nand.c
> > @@ -0,0 +1,1186 @@
> > +/*
> > + * (C) Copyright 2013 Xilinx, Inc.
> > + *
> > + * Xilinx Zynq NAND Flash Controller Driver
> > + * This driver is based on plat_nand.c and mxc_nand.c drivers
> > + *
> > + * SPDX-License-Identifier:	GPL-2.0+
> > + */
> > +
> > +#include <common.h>
> > +#include <malloc.h>
> > +#include <asm/io.h>
> > +#include <asm/errno.h>
> 
> drivers/mtd/nand/zynq_nand.c:13:23: fatal error: asm/errno.h: No such file
> or directory  #include <asm/errno.h>
>                        ^
> compilation terminated.
> 
> Remove this header.

It might be due to latest changes on errno by Masahiro. 
I made this series on top of commit on friday
"201c9d884dcadb4e76981c30e9915f73de2d09b5"
Will anyway rebase it on top of latest master and send v3.

Thanks,
Siva
> 
> 
> > +#include <nand.h>
> > +#include <linux/mtd/mtd.h>
> > +#include <linux/mtd/nand.h>
> > +#include <linux/mtd/partitions.h>
> > +#include <linux/mtd/nand_ecc.h>
> > +#include <asm/arch/hardware.h>
> > +
> > +/* The NAND flash driver defines */
> > +#define ZYNQ_NAND_CMD_PHASE		1
> > +#define ZYNQ_NAND_DATA_PHASE		2
> > +#define ZYNQ_NAND_ECC_SIZE		512
> > +#define ZYNQ_NAND_SET_OPMODE_8BIT	(0 << 0)
> > +#define ZYNQ_NAND_SET_OPMODE_16BIT	(1 << 0)
> > +#define ZYNQ_NAND_ECC_STATUS		(1 << 6)
> > +#define ZYNQ_MEMC_CLRCR_INT_CLR1	(1 << 4)
> > +#define ZYNQ_MEMC_SR_RAW_INT_ST1	(1 << 6)
> > +#define ZYNQ_MEMC_SR_INT_ST1		(1 << 4)
> > +#define ZYNQ_MEMC_NAND_ECC_MODE_MASK	0xC
> > +
> > +/* Flash memory controller operating parameters */
> > +#define ZYNQ_NAND_CLR_CONFIG	((0x1 << 1)  |	/* Disable interrupt
> */ \
> > +				(0x1 << 4)   |	/* Clear interrupt */ \
> > +				(0x1 << 6))	/* Disable ECC interrupt */
> > +
> > +/* Assuming 50MHz clock (20ns cycle time) and 3V operation */
> > +#define ZYNQ_NAND_SET_CYCLES	((0x2 << 20) |	/* t_rr from
> nand_cycles */ \
> > +				(0x2 << 17)  |	/* t_ar from nand_cycles */ \
> > +				(0x1 << 14)  |	/* t_clr from nand_cycles */ \
> > +				(0x3 << 11)  |	/* t_wp from nand_cycles */
> \
> > +				(0x2 << 8)   |	/* t_rea from nand_cycles */
> \
> > +				(0x5 << 4)   |	/* t_wc from nand_cycles */ \
> > +				(0x5 << 0))	/* t_rc from nand_cycles */
> > +
> > +
> > +#define ZYNQ_NAND_DIRECT_CMD	((0x4 << 23) |	/* Chip 0 from
> interface 1 */ \
> > +				(0x2 << 21))	/* UpdateRegs operation */
> > +
> > +#define ZYNQ_NAND_ECC_CONFIG	((0x1 << 2)  |	/* ECC available on
> APB */ \
> > +				(0x1 << 4)   |	/* ECC read at end of page */
> \
> > +				(0x0 << 5))	/* No Jumping */
> > +
> > +#define ZYNQ_NAND_ECC_CMD1	((0x80)      |	/* Write command */
> \
> > +				(0x00 << 8)  |	/* Read command */ \
> > +				(0x30 << 16) |	/* Read End command */ \
> > +				(0x1 << 24))	/* Read End command calid
> */
> > +
> > +#define ZYNQ_NAND_ECC_CMD2	((0x85)      |	/* Write col change
> cmd */ \
> > +				(0x05 << 8)  |	/* Read col change cmd */ \
> > +				(0xE0 << 16) |	/* Read col change end cmd
> */ \
> > +				(0x1 << 24))	/* Read col change
> > +							end cmd valid */
> > +/* AXI Address definitions */
> > +#define START_CMD_SHIFT			3
> > +#define END_CMD_SHIFT			11
> > +#define END_CMD_VALID_SHIFT		20
> > +#define ADDR_CYCLES_SHIFT		21
> > +#define CLEAR_CS_SHIFT			21
> > +#define ECC_LAST_SHIFT			10
> > +#define COMMAND_PHASE			(0 << 19)
> > +#define DATA_PHASE			(1 << 19)
> > +#define ONDIE_ECC_FEATURE_ADDR		0x90
> > +#define ONDIE_ECC_FEATURE_ENABLE	0x08
> > +
> > +#define ZYNQ_NAND_ECC_LAST	(1 << ECC_LAST_SHIFT)	/* Set
> ECC_Last */
> > +#define ZYNQ_NAND_CLEAR_CS	(1 << CLEAR_CS_SHIFT)	/* Clear chip
> select */
> > +
> > +/* ECC block registers bit position and bit mask */
> > +#define ZYNQ_NAND_ECC_BUSY	(1 << 6)	/* ECC block is busy */
> > +#define ZYNQ_NAND_ECC_MASK	0x00FFFFFF	/* ECC value mask */
> > +
> > +
> > +/* SMC register set */
> > +struct zynq_nand_smc_regs {
> > +	u32 csr;		/* 0x00 */
> > +	u32 reserved0[2];
> > +	u32 cfr;		/* 0x0C */
> > +	u32 dcr;		/* 0x10 */
> > +	u32 scr;		/* 0x14 */
> > +	u32 sor;		/* 0x18 */
> > +	u32 reserved1[249];
> > +	u32 esr;		/* 0x400 */
> > +	u32 emcr;		/* 0x404 */
> > +	u32 emcmd1r;		/* 0x408 */
> > +	u32 emcmd2r;		/* 0x40C */
> > +	u32 reserved2[2];
> > +	u32 eval0r;		/* 0x418 */
> > +};
> > +#define zynq_nand_smc_base	((struct zynq_nand_smc_regs
> __iomem *)\
> > +				ZYNQ_SMC_BASEADDR)
> > +
> > +/*
> > + * struct zynq_nand_info - Defines the NAND flash driver instance
> > + * @parts:		Pointer to the mtd_partition structure
> > + * @nand_base:		Virtual address of the NAND flash device
> > + * @end_cmd_pending:	End command is pending
> > + * @end_cmd:		End command
> > + */
> > +struct zynq_nand_info {
> > +	void __iomem	*nand_base;
> > +	u8		end_cmd_pending;
> > +	u8		end_cmd;
> > +};
> > +
> > +/*
> > + * struct zynq_nand_command_format - Defines NAND flash command
> format
> > + * @start_cmd:		First cycle command (Start command)
> > + * @end_cmd:		Second cycle command (Last command)
> > + * @addr_cycles:	Number of address cycles required to send the
> address
> > + * @end_cmd_valid:	The second cycle command is valid for cmd or data
> phase
> > + */
> > +struct zynq_nand_command_format {
> > +	u8 start_cmd;
> > +	u8 end_cmd;
> > +	u8 addr_cycles;
> > +	u8 end_cmd_valid;
> > +};
> > +
> > +/*  The NAND flash operations command format */ static const struct
> > +zynq_nand_command_format zynq_nand_commands[] = {
> > +	{NAND_CMD_READ0, NAND_CMD_READSTART, 5,
> ZYNQ_NAND_CMD_PHASE},
> > +	{NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2,
> ZYNQ_NAND_CMD_PHASE},
> > +	{NAND_CMD_READID, NAND_CMD_NONE, 1, 0},
> > +	{NAND_CMD_STATUS, NAND_CMD_NONE, 0, 0},
> > +	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5,
> ZYNQ_NAND_DATA_PHASE},
> > +	{NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0},
> > +	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3,
> ZYNQ_NAND_CMD_PHASE},
> > +	{NAND_CMD_RESET, NAND_CMD_NONE, 0, 0},
> > +	{NAND_CMD_PARAM, NAND_CMD_NONE, 1, 0},
> > +	{NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 0},
> > +	{NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0},
> > +	{NAND_CMD_NONE, NAND_CMD_NONE, 0, 0},
> > +	/* Add all the flash commands supported by the flash device */ };
> > +
> > +/* Define default oob placement schemes for large and small page
> > +devices */ static struct nand_ecclayout nand_oob_16 = {
> > +	.eccbytes = 3,
> > +	.eccpos = {0, 1, 2},
> > +	.oobfree = {
> > +		{ .offset = 8, .length = 8 }
> > +	}
> > +};
> > +
> > +static struct nand_ecclayout nand_oob_64 = {
> > +	.eccbytes = 12,
> > +	.eccpos = {
> > +		   52, 53, 54, 55, 56, 57,
> > +		   58, 59, 60, 61, 62, 63},
> > +	.oobfree = {
> > +		{ .offset = 2, .length = 50 }
> > +	}
> > +};
> > +
> > +static struct nand_ecclayout ondie_nand_oob_64 = {
> > +	.eccbytes = 32,
> > +
> > +	.eccpos = {
> > +		8, 9, 10, 11, 12, 13, 14, 15,
> > +		24, 25, 26, 27, 28, 29, 30, 31,
> > +		40, 41, 42, 43, 44, 45, 46, 47,
> > +		56, 57, 58, 59, 60, 61, 62, 63
> > +	},
> > +
> > +	.oobfree = {
> > +		{ .offset = 4, .length = 4 },
> > +		{ .offset = 20, .length = 4 },
> > +		{ .offset = 36, .length = 4 },
> > +		{ .offset = 52, .length = 4 }
> > +	}
> > +};
> > +
> > +/* bbt decriptors for chips with on-die ECC and
> > +   chips with 64-byte OOB */
> > +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; static u8
> > +mirror_pattern[] = {'1', 't', 'b', 'B' };
> > +
> > +static struct nand_bbt_descr bbt_main_descr = {
> > +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE |
> NAND_BBT_WRITE |
> > +		NAND_BBT_2BIT | NAND_BBT_VERSION |
> NAND_BBT_PERCHIP,
> > +	.offs = 4,
> > +	.len = 4,
> > +	.veroffs = 20,
> > +	.maxblocks = 4,
> > +	.pattern = bbt_pattern
> > +};
> > +
> > +static struct nand_bbt_descr bbt_mirror_descr = {
> > +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE |
> NAND_BBT_WRITE |
> > +		NAND_BBT_2BIT | NAND_BBT_VERSION |
> NAND_BBT_PERCHIP,
> > +	.offs = 4,
> > +	.len = 4,
> > +	.veroffs = 20,
> > +	.maxblocks = 4,
> > +	.pattern = mirror_pattern
> > +};
> > +
> > +/*
> > + * zynq_nand_waitfor_ecc_completion - Wait for ECC completion
> > + *
> > + * returns: status for command completion, -1 for Timeout  */ static
> > +int zynq_nand_waitfor_ecc_completion(void)
> > +{
> > +	unsigned long timeout;
> > +	u32 status;
> > +
> > +	/* Wait max 10us */
> > +	timeout = 10;
> > +	status = readl(&zynq_nand_smc_base->esr);
> > +	while (status & ZYNQ_NAND_ECC_BUSY) {
> > +		status = readl(&zynq_nand_smc_base->esr);
> > +		if (timeout == 0)
> > +			return -1;
> > +		timeout--;
> > +		udelay(1);
> > +	}
> > +
> > +	return status;
> > +}
> > +
> > +/*
> > + * zynq_nand_init_nand_flash - Initialize NAND controller
> > + * @option:	Device property flags
> > + *
> > + * This function initializes the NAND flash interface on the NAND
> controller.
> > + *
> > + * returns:	0 on success or error value on failure
> > + */
> > +static int zynq_nand_init_nand_flash(int option) {
> > +	u32 status;
> > +
> > +	/* disable interrupts */
> > +	writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr);
> > +	/* Initialize the NAND interface by setting cycles and operation mode
> */
> > +	writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr);
> > +	if (option & NAND_BUSWIDTH_16)
> > +		writel(ZYNQ_NAND_SET_OPMODE_16BIT,
> &zynq_nand_smc_base->sor);
> > +	else
> > +		writel(ZYNQ_NAND_SET_OPMODE_8BIT,
> &zynq_nand_smc_base->sor);
> > +
> > +	writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr);
> > +
> > +	/* Wait till the ECC operation is complete */
> > +	status = zynq_nand_waitfor_ecc_completion();
> > +	if (status < 0) {
> > +		printf("%s: Timeout\n", __func__);
> > +		return status;
> > +	}
> > +
> > +	/* Set the command1 and command2 register */
> > +	writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r);
> > +	writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r);
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * zynq_nand_calculate_hwecc - Calculate Hardware ECC
> > + * @mtd:	Pointer to the mtd_info structure
> > + * @data:	Pointer to the page data
> > + * @ecc_code:	Pointer to the ECC buffer where ECC data needs to
> be stored
> > + *
> > + * This function retrieves the Hardware ECC data from the controller
> > +and returns
> > + * ECC data back to the MTD subsystem.
> > + *
> > + * returns:	0 on success or error value on failure
> > + */
> > +static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8
> *data,
> > +		u8 *ecc_code)
> > +{
> > +	u32 ecc_value = 0;
> > +	u8 ecc_reg, ecc_byte;
> > +	u32 ecc_status;
> > +
> > +	/* Wait till the ECC operation is complete */
> > +	ecc_status = zynq_nand_waitfor_ecc_completion();
> > +	if (ecc_status < 0) {
> > +		printf("%s: Timeout\n", __func__);
> > +		return ecc_status;
> > +	}
> > +
> > +	for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
> > +		/* Read ECC value for each block */
> > +		ecc_value = readl(&zynq_nand_smc_base->eval0r + ecc_reg);
> > +
> > +		/* Get the ecc status from ecc read value */
> > +		ecc_status = (ecc_value >> 24) & 0xFF;
> > +
> > +		/* ECC value valid */
> > +		if (ecc_status & ZYNQ_NAND_ECC_STATUS) {
> > +			for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) {
> > +				/* Copy ECC bytes to MTD buffer */
> > +				*ecc_code = ecc_value & 0xFF;
> > +				ecc_value = ecc_value >> 8;
> > +				ecc_code++;
> > +			}
> > +		} else {
> > +			debug("%s: ecc status failed\n", __func__);
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * onehot - onehot function
> > + * @value:	value to check for onehot
> > + *
> > + * This function checks whether a value is onehot or not.
> > + * onehot is if and only if one bit is set.
> > + *
> > + * FIXME: Try to move this in common.h  */ static bool
> > +onehot(unsigned short value) {
> > +	bool onehot;
> > +
> > +	onehot = value && !(value & (value - 1));
> > +	return onehot;
> > +}
> > +
> > +/*
> > + * zynq_nand_correct_data - ECC correction function
> > + * @mtd:	Pointer to the mtd_info structure
> > + * @buf:	Pointer to the page data
> > + * @read_ecc:	Pointer to the ECC value read from spare data area
> > + * @calc_ecc:	Pointer to the calculated ECC value
> > + *
> > + * This function corrects the ECC single bit errors & detects 2-bit errors.
> > + *
> > + * returns:	0 if no ECC errors found
> > + *		1 if single bit error found and corrected.
> > + *		-1 if multiple ECC errors found.
> > + */
> > +static int zynq_nand_correct_data(struct mtd_info *mtd, unsigned char
> *buf,
> > +			unsigned char *read_ecc, unsigned char *calc_ecc) {
> > +	unsigned char bit_addr;
> > +	unsigned int byte_addr;
> > +	unsigned short ecc_odd, ecc_even;
> > +	unsigned short read_ecc_lower, read_ecc_upper;
> > +	unsigned short calc_ecc_lower, calc_ecc_upper;
> > +
> > +	read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff;
> > +	read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff;
> > +
> > +	calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff;
> > +	calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff;
> > +
> > +	ecc_odd = read_ecc_lower ^ calc_ecc_lower;
> > +	ecc_even = read_ecc_upper ^ calc_ecc_upper;
> > +
> > +	if ((ecc_odd == 0) && (ecc_even == 0))
> > +		return 0;       /* no error */
> > +
> > +	if (ecc_odd == (~ecc_even & 0xfff)) {
> > +		/* bits [11:3] of error code is byte offset */
> > +		byte_addr = (ecc_odd >> 3) & 0x1ff;
> > +		/* bits [2:0] of error code is bit offset */
> > +		bit_addr = ecc_odd & 0x7;
> > +		/* Toggling error bit */
> > +		buf[byte_addr] ^= (1 << bit_addr);
> > +		return 1;
> > +	}
> > +
> > +	if (onehot(ecc_odd | ecc_even))
> > +		return 1; /* one error in parity */
> > +
> > +	return -1; /* Uncorrectable error */ }
> > +
> > +/*
> > + * zynq_nand_read_oob - [REPLACABLE] the most common OOB data read
> function
> > + * @mtd:	mtd info structure
> > + * @chip:	nand chip info structure
> > + * @page:	page number to read
> > + * @sndcmd:	flag whether to issue read command or not
> > + */
> > +static int zynq_nand_read_oob(struct mtd_info *mtd, struct nand_chip
> *chip,
> > +			int page)
> > +{
> > +	unsigned long data_phase_addr = 0;
> > +	int data_width = 4;
> > +	u8 *p;
> > +
> > +	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
> > +
> > +	p = chip->oob_poi;
> > +	chip->read_buf(mtd, p, (mtd->oobsize - data_width));
> > +	p += mtd->oobsize - data_width;
> > +
> > +	data_phase_addr = (unsigned long)chip->IO_ADDR_R;
> > +	data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
> > +	chip->IO_ADDR_R = (void __iomem *)data_phase_addr;
> > +	chip->read_buf(mtd, p, data_width);
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * zynq_nand_write_oob - [REPLACABLE] the most common OOB data
> write function
> > + * @mtd:	mtd info structure
> > + * @chip:	nand chip info structure
> > + * @page:	page number to write
> > + */
> > +static int zynq_nand_write_oob(struct mtd_info *mtd, struct nand_chip
> *chip,
> > +			     int page)
> > +{
> > +	int status = 0, data_width = 4;
> > +	const u8 *buf = chip->oob_poi;
> > +	unsigned long data_phase_addr = 0;
> > +
> > +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
> > +
> > +	chip->write_buf(mtd, buf, (mtd->oobsize - data_width));
> > +	buf += mtd->oobsize - data_width;
> > +
> > +	data_phase_addr = (unsigned long)chip->IO_ADDR_W;
> > +	data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
> > +	data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
> > +	chip->IO_ADDR_W = (void __iomem *)data_phase_addr;
> > +	chip->write_buf(mtd, buf, data_width);
> > +
> > +	/* Send command to program the OOB data */
> > +	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
> > +	status = chip->waitfunc(mtd, chip);
> > +
> > +	return status & NAND_STATUS_FAIL ? -EIO : 0; }
> > +
> > +/*
> > + * zynq_nand_read_page_raw - [Intern] read raw page data without ecc
> > + * @mtd:        mtd info structure
> > + * @chip:       nand chip info structure
> > + * @buf:        buffer to store read data
> > + * @oob_required: must write chip->oob_poi to OOB
> > + * @page:       page number to read
> > + */
> > +static int zynq_nand_read_page_raw(struct mtd_info *mtd, struct
> nand_chip *chip,
> > +				   u8 *buf,  int oob_required, int page) {
> > +	unsigned long data_width = 4;
> > +	unsigned long data_phase_addr = 0;
> > +	u8 *p;
> > +
> > +	chip->read_buf(mtd, buf, mtd->writesize);
> > +
> > +	p = chip->oob_poi;
> > +	chip->read_buf(mtd, p, (mtd->oobsize - data_width));
> > +	p += (mtd->oobsize - data_width);
> > +
> > +	data_phase_addr = (unsigned long)chip->IO_ADDR_R;
> > +	data_phase_addr |= ZYNQ_NAND_CLEAR_CS;
> > +	chip->IO_ADDR_R = (void __iomem *)data_phase_addr;
> > +
> > +	chip->read_buf(mtd, p, data_width);
> > +	return 0;
> > +}
> > +
> > +static int zynq_nand_read_page_raw_nooob(struct mtd_info *mtd,
> > +		struct nand_chip *chip, u8 *buf, int oob_required, int page) {
> > +	chip->read_buf(mtd, buf, mtd->writesize);
> > +	return 0;
> > +}
> > +
> > +static int zynq_nand_read_subpage_raw(struct mtd_info *mtd,
> > +				    struct nand_chip *chip, u32 data_offs,
> > +				    u32 readlen, u8 *buf)
> > +{
> 
> drivers/mtd/nand/zynq_nand.c: In function 'zynq_nand_init':
> drivers/mtd/nand/zynq_nand.c:1092:31: warning: assignment from
> incompatible pointer type
>    nand_chip->ecc.read_subpage = zynq_nand_read_subpage_raw;
>                                ^
> 
> 
> Thanks,
> Michal


More information about the U-Boot mailing list