Commit 4bbaac41 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev
Browse files

nand spl support - tmp working with nand_base.c

parent e47e7650
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -257,8 +257,6 @@ void zynq_slcr_devcfg_enable(void)
u32 zynq_slcr_get_boot_mode(void)
u32 zynq_slcr_get_boot_mode(void)
{
{
	/* Get the bootmode register value */
	/* Get the bootmode register value */
	printf("\nBOOTMODE CODE is %d\n",(u32)readl(&slcr_base->boot_mode));
	udelay(5000);
	return readl(&slcr_base->boot_mode);
	return readl(&slcr_base->boot_mode);
}
}


+3 −0
Original line number Original line Diff line number Diff line
@@ -17,9 +17,12 @@ obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_ELPHEL393) += elphel393_nand_spl.o
obj-$(CONFIG_SPL_NAND_ELPHEL393) += elphel393_nand_spl.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
obj-$(CONFIG_SPL_NAND_BBT) += nand_bbt.o
obj-$(CONFIG_SPL_NAND_IDS) += nand_ids.o
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
obj-$(CONFIG_SPL_NAND_INIT) += nand.o
obj-$(CONFIG_SPL_NAND_INIT) += nand.o
obj-$(CONFIG_SPL_NAND_INIT) += ../mtdcore.o ../mtd_uboot.o
ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o
obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o
endif
endif
+105 −70
Original line number Original line Diff line number Diff line
/*
/*
 * Xilinx Zynq NAND Flash Controller Driver
 * Elphel393 NAND driver for SPL, not based on denali_spl.c
 * This driver is based on plat_nand.c and mxc_nand.c drivers
 *
 *
 * Copyright (C) 2009 - 2013 Xilinx, Inc.
 * Copyright (C) 2016 Elphel, Inc.
 *
 *
 * SPDX-License-Identifier:	GPL-2.0+
 * SPDX-License-Identifier:	GPL-2.0+
 */
 */
@@ -19,82 +18,118 @@
#include <asm/arch/hardware.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/sys_proto.h>


/* The NAND flash driver defines */
extern nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
#define ZYNQ_NAND_CMD_PHASE	1	/* End command valid in command phase */

#define ZYNQ_NAND_DATA_PHASE	2	/* End command valid in data phase */
static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt)
#define ZYNQ_NAND_ECC_SIZE	512	/* Size of data for ECC operation */
{

	register struct nand_chip *chip = mtd->priv;
/* Flash memory controller operating parameters */
	unsigned int block = offs >> chip->phys_erase_shift;
#define ZYNQ_NAND_CLR_CONFIG	((0x1 << 1)  |	/* Disable interrupt */ \
	unsigned int page = offs >> chip->page_shift;
				(0x1 << 4)   |	/* Clear interrupt */ \

				(0x1 << 6))	/* Disable ECC interrupt */
	printf("    is_badblock(): offs=0x%08x block=%d page=%d\n",(int)offs, block,

	      page);
/* Assuming 50MHz clock (20ns cycle time) and 3V operation */
	//chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
#define ZYNQ_NAND_SET_CYCLES	((0x2 << 20) |	/* t_rr from nand_cycles */ \
	//memset(chip->oob_poi, 0, mtd->oobsize);
				(0x2 << 17)  |	/* t_ar from nand_cycles */ \
	//chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
				(0x1 << 14)  |	/* t_clr from nand_cycles */ \

				(0x3 << 11)  |	/* t_wp from nand_cycles */ \
	//return chip->oob_poi[0] != 0xff;
				(0x2 << 8)   |	/* t_rea from nand_cycles */ \
	return 0;
				(0x5 << 4)   |	/* t_wc from nand_cycles */ \
}
				(0x5 << 0))	/* t_rc from nand_cycles */


//dst or buf - destination in RAM
#define ZYNQ_NAND_SET_OPMODE	0x0
//offs - u-boot-dtb.img offset in NAND

//size - size of u-boot-dtb.img
#define ZYNQ_NAND_DIRECT_CMD	((0x4 << 23) |	/* Chip 0 from interface 1 */ \
int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
				(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 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 */

#define ZYNQ_NAND_ROW_ADDR_CYCL_MASK	0x0F
#define ZYNQ_NAND_COL_ADDR_CYCL_MASK	0xF0

/* NAND MIO buswidth count*/
#define ZYNQ_NAND_MIO_NUM_NAND_8BIT	13
#define ZYNQ_NAND_MIO_NUM_NAND_16BIT	8

/* Based on Fabian Gottlieb von Bellingshausen's work in Antarctica */
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
{
{
	struct nand_chip *chip;
	struct mtd_info *mtd;
	unsigned int page;
	unsigned int nand_page_per_block;
	unsigned int sz = 0;

	printf("\nnand_spl_load_image(): offs=0x%08x size=%d (0x%08x) buf_addr=0x%08x\n",offs,size,size,buf);
	udelay(10000);

	//if (mxs_nand_init()) return -ENODEV;
	mtd = &nand_info[0];
	//mtd.priv = &nand_chip;
	chip = mtd->priv;
	page = offs >> chip->page_shift;
	nand_page_per_block = mtd->erasesize / mtd->writesize;

	debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page);

	printf("  nand_page_per_block= %d\n",nand_page_per_block);
	printf("  mtd->writesize= %d\n",mtd->writesize);
	printf("  u-boot-dtb.img size is: %d (0x%08x)\n",size,size);
	
	size = roundup(size, mtd->writesize);

	printf("  u-boot-dtb.img size after roundup is:%d\n",size);
	
	//u32 testbuf[16];

	while (sz < size) {
		//if (mxs_read_page_ecc(&mtd, buf, page) < 0)
		//	return -1;
		//printf("  Reading from NAND, offset:0x%08x page_index:%d to MEM address:0x%08x\n",offs, page, buf);

		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
		udelay(500);
		//read min
		chip->read_buf(mtd,buf,min(size-sz, mtd->writesize));

		//chip->ecc.read_page(mtd, chip, buf, 0, page);
		sz += mtd->writesize;
		offs += mtd->writesize;
		page++;
		buf += mtd->writesize;

		/*
		 * Check if we have crossed a block boundary, and if so
		 * check for bad block.
		 */
		//if (!(page % nand_page_per_block)) {
		//	/*
		//	 * Yes, new block. See if this block is good. If not,
		//	 * loop until we find a good block.
		//	 */
		//	while (is_badblock(&mtd, offs, 1)) {
		//		page = page + nand_page_per_block;
		//		/* Check we've reached the end of flash. */
		//		if (page >= mtd->size >> chip->page_shift)
		//			return -ENOMEM;
		//	}
		//}
	}
	return 0;
	return 0;
}
}


/* nand_init() - initialize data to make nand usable by SPL */
/* already defined in nand.c
// nand_init() - initialize data to make nand usable by SPL
void nand_init(void)
void nand_init(void)
{
{
	puts("nand_init()\n");
	udelay(5000);
	board_nand_init();
}
*/


void nand_init_custom(void)
{
	puts("nand_init_custom()\n");
	udelay(5000);
	//board_nand_init();
}
}


/* secret */
/* secret */
void nand_deselect(void) {
void nand_deselect(void) {
	
	puts("nand_deselect(): empty function\n");
	udelay(10000);
}
}


void nand_deselect2(void) {
	printf("nand_deselect2(): &nand_info[0]=0x%08x\n",(u32)&nand_info[0]);
	puts("nand_deselect2(): empty function\n");
	udelay(10000);
}
+4047 −0

File added.

Preview size limit exceeded, changes collapsed.

+42 −3
Original line number Original line Diff line number Diff line
@@ -55,8 +55,8 @@
#define ZYNQ_NAND_ECC_CMD2	((0x85)      |	/* Write col change cmd */ \
#define ZYNQ_NAND_ECC_CMD2	((0x85)      |	/* Write col change cmd */ \
				(0x05 << 8)  |	/* Read col change cmd */ \
				(0x05 << 8)  |	/* Read col change cmd */ \
				(0xE0 << 16) |	/* Read col change end cmd */ \
				(0xE0 << 16) |	/* Read col change end cmd */ \
				(0x1 << 24))	/* Read col change
				(0x1 << 24))	/* Read col change end cmd valid */
							end cmd valid */

/* AXI Address definitions */
/* AXI Address definitions */
#define START_CMD_SHIFT		3
#define START_CMD_SHIFT		3
#define END_CMD_SHIFT		11
#define END_CMD_SHIFT		11
@@ -773,6 +773,8 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
	unsigned long end_cmd_valid = 0;
	unsigned long end_cmd_valid = 0;
	unsigned long i;
	unsigned long i;


	//printf(" zynq_nand(): Command=0x%02x Column=0x%02x PageAddr=0x%08x\n",command,column,page_addr);

	xnand = (struct zynq_nand_info *)chip->priv;
	xnand = (struct zynq_nand_info *)chip->priv;
	if (xnand->end_cmd_pending) {
	if (xnand->end_cmd_pending) {
		/* Check for end command if this command request is same as the
		/* Check for end command if this command request is same as the
@@ -905,6 +907,9 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
 */
 */
static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
{

	//printf("zynq_nand_read_buf():start len=0x%08x buf=0x%08x\n",len,buf);

	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd->priv;
	const u32 *nand = chip->IO_ADDR_R;
	const u32 *nand = chip->IO_ADDR_R;


@@ -955,6 +960,9 @@ static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 */
 */
static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
{

	printf("zynq_nand_write_buf(): len=%d buf=%d\n",len,buf);

	struct nand_chip *chip = mtd->priv;
	struct nand_chip *chip = mtd->priv;
	const u32 *nand = chip->IO_ADDR_W;
	const u32 *nand = chip->IO_ADDR_W;


@@ -1040,7 +1048,9 @@ static int zynq_nand_check_is_16bit_bw_flash(void)
	    (mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT))
	    (mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT))
		is_16bit_bw = NAND_BW_16BIT;
		is_16bit_bw = NAND_BW_16BIT;


	return is_16bit_bw;
	//return is_16bit_bw;
	//elphel force 8 bits width
	return NAND_BW_8BIT;
}
}


static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
@@ -1056,7 +1066,12 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	int ondie_ecc_enabled = 0;
	int ondie_ecc_enabled = 0;
	int is_16bit_bw;
	int is_16bit_bw;


	//printf("\n  zynq_nand_init():start\n");

	xnand = calloc(1, sizeof(struct zynq_nand_info));
	xnand = calloc(1, sizeof(struct zynq_nand_info));

	//printf("ZYNQ_NAND_INIT: CALLOC @0x%08x size=%d\n",(u32)&xnand,sizeof(xnand));

	if (!xnand) {
	if (!xnand) {
		printf("%s: failed to allocate\n", __func__);
		printf("%s: failed to allocate\n", __func__);
		goto free;
		goto free;
@@ -1072,6 +1087,11 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	nand_chip->IO_ADDR_R = xnand->nand_base;
	nand_chip->IO_ADDR_R = xnand->nand_base;
	nand_chip->IO_ADDR_W = xnand->nand_base;
	nand_chip->IO_ADDR_W = xnand->nand_base;


	//printf("    ZYNQ_NAND_BASEADDR:0x%08x\n",(unsigned int)ZYNQ_NAND_BASEADDR);
	//printf("    xnand->nand_base:0x%08x\n",(unsigned int)xnand->nand_base);
	//printf("    nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
	//printf("    nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);

	/* Set the driver entry points for MTD */
	/* Set the driver entry points for MTD */
	nand_chip->cmdfunc = zynq_nand_cmd_function;
	nand_chip->cmdfunc = zynq_nand_cmd_function;
	nand_chip->dev_ready = zynq_nand_device_ready;
	nand_chip->dev_ready = zynq_nand_device_ready;
@@ -1087,6 +1107,9 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	/* Check the NAND buswidth */
	/* Check the NAND buswidth */
	/* FIXME this will be changed by using NAND_BUSWIDTH_AUTO */
	/* FIXME this will be changed by using NAND_BUSWIDTH_AUTO */
	is_16bit_bw = zynq_nand_check_is_16bit_bw_flash();
	is_16bit_bw = zynq_nand_check_is_16bit_bw_flash();

	//printf("    is_16bit_bw: %d\n",is_16bit_bw);

	if (is_16bit_bw == NAND_BW_UNKNOWN) {
	if (is_16bit_bw == NAND_BW_UNKNOWN) {
		printf("%s: Unable detect NAND based on MIO settings\n",
		printf("%s: Unable detect NAND based on MIO settings\n",
		       __func__);
		       __func__);
@@ -1116,6 +1139,10 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	maf_id = nand_chip->read_byte(mtd);
	maf_id = nand_chip->read_byte(mtd);
	dev_id = nand_chip->read_byte(mtd);
	dev_id = nand_chip->read_byte(mtd);


	//printf("    maf_id=0x%02x dev_id=0x%02x\n",maf_id,dev_id);
	//printf("    nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
	//printf("    nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);

	if ((maf_id == 0x2c) && ((dev_id == 0xf1) ||
	if ((maf_id == 0x2c) && ((dev_id == 0xf1) ||
				 (dev_id == 0xa1) || (dev_id == 0xb1) ||
				 (dev_id == 0xa1) || (dev_id == 0xb1) ||
				 (dev_id == 0xaa) || (dev_id == 0xba) ||
				 (dev_id == 0xaa) || (dev_id == 0xba) ||
@@ -1146,6 +1173,13 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	}
	}


	if (ondie_ecc_enabled) {
	if (ondie_ecc_enabled) {
		//puts("  Welcome to OnDie ECC flash\n");
		
		//printf("    ZYNQ_NAND_BASEADDR:0x%08x\n",(unsigned int)ZYNQ_NAND_BASEADDR);
		//printf("    xnand->nand_base:0x%08x\n",(unsigned int)xnand->nand_base);
		//printf("    nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
		//printf("    nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);
		
		/* bypass the controller ECC block */
		/* bypass the controller ECC block */
		ecc_cfg = readl(&zynq_nand_smc_base->emcr);
		ecc_cfg = readl(&zynq_nand_smc_base->emcr);
		ecc_cfg &= ~0xc;
		ecc_cfg &= ~0xc;
@@ -1206,6 +1240,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
			       &zynq_nand_smc_base->emcr);
			       &zynq_nand_smc_base->emcr);
			break;
			break;
		case 2048:
		case 2048:
			printf("    necc_page_size = 0x3\n");
			ecc_page_size = 0x3;
			ecc_page_size = 0x3;
			/* Set the ECC memory config register */
			/* Set the ECC memory config register */
			writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
			writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
@@ -1248,6 +1283,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
	if (nand_register(devnum))
	if (nand_register(devnum))
		goto fail;
		goto fail;


	//printf("  zynq_nand_init(): end\n");
	return 0;
	return 0;
fail:
fail:
free:
free:
@@ -1261,6 +1297,9 @@ void board_nand_init(void)
{
{
	struct nand_chip *nand = &nand_chip[0];
	struct nand_chip *nand = &nand_chip[0];


	printf("board_nand_init(): &nand_chip[0]=0x%08x\n",(u32)&nand_chip[0]);

	if (zynq_nand_init(nand, 0))
	if (zynq_nand_init(nand, 0))
		puts("ZYNQ NAND init failed\n");
		puts("ZYNQ NAND init failed\n");

}
}
Loading