Message ID | 1298876234-28115-5-git-send-email-xiangfu@openmobilefree.net |
---|---|
State | Changes Requested |
Headers | show |
On Mon, 28 Feb 2011 14:57:11 +0800 Xiangfu Liu <xiangfu@openmobilefree.net> wrote: > +static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, > + u_char *read_ecc, u_char *calc_ecc) > +{ > + int k; > + uint32_t errcnt, index, mask, status; > + volatile u8 *paraddr = (volatile u8 *) &emc->nfpar[0]; > + > + /* Set PAR values */ > + static uint8_t all_ff_ecc[] = > + {0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f}; const? > + > + if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && > + read_ecc[2] == 0xff && read_ecc[3] == 0xff && > + read_ecc[4] == 0xff && read_ecc[5] == 0xff && > + read_ecc[6] == 0xff && read_ecc[7] == 0xff && > + read_ecc[8] == 0xff) { > + for (k = 0; k < 9; k++) > + writeb(all_ff_ecc[k], (paraddr + k)); > + } else { > + for (k = 0; k < 9; k++) > + writeb(read_ecc[k], (paraddr + k)); > + } Wouldn't it be simpler to do: writeb(..., &emc->nfpar[k]); And don't use volatile. > + /* Set PRDY */ > + writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr); > + > + /* Wait for completion */ > + do { > + status = readl(&emc->nfints); > + } while (!(status & EMC_NFINTS_DECF)); > + > + /* disable ecc */ > + writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); > + > + /* Check decoding */ > + if (!(status & EMC_NFINTS_ERR)) > + return 0; > + > + if (status & EMC_NFINTS_UNCOR) { > + printf("uncorrectable ecc\n"); > + return -1; > + } > + > + errcnt = (status & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; > + > +#ifdef CONFIG_NAND_SPL > + return 0; > +#endif Spaces should be a tab. > + switch (errcnt) { > + case 4: > + index = (readl(&emc->nferr[3]) & EMC_NFERR_INDEX_MASK) >> > + EMC_NFERR_INDEX_BIT; > + mask = (readl(&emc->nferr[3]) & EMC_NFERR_MASK_MASK) >> > + EMC_NFERR_MASK_BIT; > + jz_rs_correct(dat, index, mask); > + case 3: > + index = (readl(&emc->nferr[2]) & EMC_NFERR_INDEX_MASK) >> > + EMC_NFERR_INDEX_BIT; > + mask = (readl(&emc->nferr[2]) & EMC_NFERR_MASK_MASK) >> > + EMC_NFERR_MASK_BIT; > + jz_rs_correct(dat, index, mask); > + case 2: > + index = (readl(&emc->nferr[1]) & EMC_NFERR_INDEX_MASK) >> > + EMC_NFERR_INDEX_BIT; > + mask = (readl(&emc->nferr[1]) & EMC_NFERR_MASK_MASK) >> > + EMC_NFERR_MASK_BIT; > + jz_rs_correct(dat, index, mask); > + case 1: > + index = (readl(&emc->nferr[0]) & EMC_NFERR_INDEX_MASK) >> > + EMC_NFERR_INDEX_BIT; > + mask = (readl(&emc->nferr[0]) & EMC_NFERR_MASK_MASK) >> > + EMC_NFERR_MASK_BIT; > + jz_rs_correct(dat, index, mask); > + default: > + break; > + } > + > + return errcnt; You don't do ECC correction in SPL? Can it not fit? > +/* > + * Main initialization routine > + */ > +int board_nand_init(struct nand_chip *nand) > +{ > +#ifdef CONFIG_NAND_SPL > +extern void pll_init(void); > +extern void sdram_init(void); > +extern int serial_init(void); Externs should go in header files. > + __gpio_as_sdram_16bit_4720(); > + __gpio_as_uart0(); > + > + pll_init(); > + serial_init(); > + sdram_init(); > +#if defined(CONFIG_QI_LB60) > +#define KEY_U_OUT (32 * 2 + 16) > +#define KEY_U_IN (32 * 3 + 19) > + __gpio_as_input(KEY_U_IN); > + __gpio_enable_pull(KEY_U_IN); > + __gpio_as_output(KEY_U_OUT); > + __gpio_clear_pin(KEY_U_OUT); > + > + if (__gpio_get_pin(KEY_U_IN) == 0) > + usb_boot(); > +#endif > +#endif This stuff does not belong in the NAND driver; it belongs under your board or cpu directory. > + uint32_t reg; > + > + reg = readl(&emc->nfcsr); > + reg |= EMC_NFCSR_NFE1; /* EMC setup, Set NFE bit */ > + writel(reg, &emc->nfcsr); > + > + writel(EMC_SMCR1_OPT_NAND, &emc->smcr[1]); > + > + nand->IO_ADDR_R = JZ_NAND_DATA_ADDR; > + nand->IO_ADDR_W = JZ_NAND_DATA_ADDR; > + nand->cmd_ctrl = jz_nand_cmd_ctrl; > + nand->dev_ready = jz_nand_device_ready; > +#ifdef CONFIG_NAND_SPL > + nand->read_byte = nand_read_byte; > + nand->read_buf = nand_read_buf; > +#endif > + nand->ecc.hwctl = jz_nand_hwctl; > + nand->ecc.correct = jz_nand_rs_correct_data; > + nand->ecc.calculate = jz_nand_rs_calculate_ecc; > + nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; > + nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; > + nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; > + nand->ecc.layout = &qi_lb60_ecclayout_2gb; > + nand->chip_delay = 50; You don't set nand->options... Don't you want a bad block table? -Scott
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/08/2011 07:44 AM, Scott Wood wrote: >> +#if defined(CONFIG_QI_LB60) >> > +#define KEY_U_OUT (32 * 2 + 16) >> > +#define KEY_U_IN (32 * 3 + 19) >> > + __gpio_as_input(KEY_U_IN); >> > + __gpio_enable_pull(KEY_U_IN); >> > + __gpio_as_output(KEY_U_OUT); >> > + __gpio_clear_pin(KEY_U_OUT); >> > + >> > + if (__gpio_get_pin(KEY_U_IN) == 0) >> > + usb_boot(); >> > +#endif >> > +#endif > This stuff does not belong in the NAND driver; it belongs under your board > or cpu directory. > I have tried to move those 'usb_boot' to board files. the only problem is I have to run this 'usb_boot' very early. after CPU load the real u-boot to memory the usb_boot will not working. I will try to found more info about this. then explain more in next email. thanks Scott Wood for your feedback. I will keeping working. until the code is good enough :) - -- Best Regards Xiangfu Liu http://www.openmobilefree.net -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk2IWZcACgkQRRAEFRxkgLTVvwCfaw7jKe7ZVzycMS+gN2lFdV2t mEYAoIFahfXxtoiXs565cuN4vAuDdlIR =tdrU -----END PGP SIGNATURE-----
On Tue, 22 Mar 2011 16:11:03 +0800 Xiangfu Liu <xiangfu@openmobilefree.net> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On 03/08/2011 07:44 AM, Scott Wood wrote: > >> +#if defined(CONFIG_QI_LB60) > >> > +#define KEY_U_OUT (32 * 2 + 16) > >> > +#define KEY_U_IN (32 * 3 + 19) > >> > + __gpio_as_input(KEY_U_IN); > >> > + __gpio_enable_pull(KEY_U_IN); > >> > + __gpio_as_output(KEY_U_OUT); > >> > + __gpio_clear_pin(KEY_U_OUT); > >> > + > >> > + if (__gpio_get_pin(KEY_U_IN) == 0) > >> > + usb_boot(); > >> > +#endif > >> > +#endif > > This stuff does not belong in the NAND driver; it belongs under your board > > or cpu directory. > > > > I have tried to move those 'usb_boot' to board files. the only problem is > I have to run this 'usb_boot' very early. after CPU load the real u-boot to memory > the usb_boot will not working. I will try to found more info about this. > then explain more in next email. OK, so you need to run it during the SPL phase -- but there should be some board/cpu-specific file for the SPL (if not, create one). Current examples of this include nand_spl/board/freescale/p1_p2_rdb/nand_boot.c and arch/powerpc/cpu/mpc83xx/nand_init.c. -Scott
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/08/2011 07:44 AM, Scott Wood wrote: > You don't set nand->options... > > Don't you want a bad block table? > hmm... some question. a little confuse. 1. I using all rest of nand as rootfs partition. do I have keep some space in nand for BBT? 2. do I have to tell u-boot where is the BBT? 3. do I need some configure in linux kernel for BBT? - -- Best Regards Xiangfu Liu http://www.openmobilefree.net -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk2MXZ0ACgkQRRAEFRxkgLTxoACePzD7G02iYng9GEHkbEWw4Ndk 6tgAn26gxUBbZK+hVJQSqnpL15GafZcA =bIOO -----END PGP SIGNATURE-----
On Fri, 25 Mar 2011 17:17:17 +0800 Xiangfu Liu <xiangfu@openmobilefree.net> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On 03/08/2011 07:44 AM, Scott Wood wrote: > > You don't set nand->options... > > > > Don't you want a bad block table? > > > > hmm... some question. a little confuse. > > 1. I using all rest of nand as rootfs partition. > do I have keep some space in nand for BBT? The last block or so is marked reserved for the BBT. > 2. do I have to tell u-boot where is the BBT? No, it's marked with a special OOB marker. If it isn't present, it will create it at the end of the chip. > 3. do I need some configure in linux kernel for BBT? Set the nand->options flag, same as in U-Boot. -Scott
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/23/2011 12:10 AM, Scott Wood wrote: >> I have tried to move those 'usb_boot' to board files. the only problem is >> > I have to run this 'usb_boot' very early. after CPU load the real u-boot to memory >> > the usb_boot will not working. I will try to found more info about this. >> > then explain more in next email. > OK, so you need to run it during the SPL phase -- but there should be > some board/cpu-specific file for the SPL (if not, create one). > > Current examples of this > include nand_spl/board/freescale/p1_p2_rdb/nand_boot.c and > arch/powerpc/cpu/mpc83xx/nand_init.c. > Hi Scott Wood thanks for the info. for speed up I think I will remove the usbboot and nandboot SPL in those patches series. I am NOT SOTP working on that. I will try to implement them in next series patches and will include the mmc/lcd/nandSPL source code in next serial patches. thanks again. - -- Best Regards Xiangfu Liu http://www.openmobilefree.net -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk222lMACgkQRRAEFRxkgLSMaACgrOofX/zJNpNp1e1WvhTVyAl3 64kAoIvIx38HasmCmqer2FXzoKPKlagH =Qmft -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/26/2011 12:04 AM, Scott Wood wrote: >> hmm... some question. a little confuse. >> > >> > 1. I using all rest of nand as rootfs partition. >> > do I have keep some space in nand for BBT? > The last block or so is marked reserved for the BBT. > >> > 2. do I have to tell u-boot where is the BBT? > No, it's marked with a special OOB marker. If it isn't present, it will > create it at the end of the chip. > >> > 3. do I need some configure in linux kernel for BBT? > Set the nand->options flag, same as in U-Boot. > thanks for the info. will enable the BBT in next series patches - -- Best Regards Xiangfu Liu http://www.openmobilefree.net -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk222o4ACgkQRRAEFRxkgLQOmgCfSfL0iN6BY0TlDcg9jbUiSnen VukAnA1pE4d3YnZwA5nLRQbPUv2tecXR =d/2S -----END PGP SIGNATURE-----
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 8b598f6..bf2a8f9 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -50,6 +50,7 @@ COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o +COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o endif COBJS := $(COBJS-y) diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c new file mode 100644 index 0000000..a7d16e3 --- /dev/null +++ b/drivers/mtd/nand/jz4740_nand.c @@ -0,0 +1,329 @@ +/* + * Platform independend driver for JZ4740. + * + * Copyright (c) 2007 Ingenic Semiconductor Inc. + * Author: <jlwei@ingenic.cn> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ +#include <common.h> + +#include <nand.h> +#include <asm/io.h> +#include <asm/jz4740.h> + +#ifdef CONFIG_NAND_SPL +#define printf(arg...) do {} while (0) +#endif + +#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000) +#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000) +#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000) + +#define BIT(x) (1 << (x)) +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) +#define JZ_NAND_ECC_CTRL_RS BIT(2) +#define JZ_NAND_ECC_CTRL_RESET BIT(1) +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) + +#define EMC_SMCR1_OPT_NAND 0x094c4400 +/* Optimize the timing of nand */ + +static struct jz4740_emc * emc = (struct jz4740_emc *) JZ4740_EMC_BASE; + +static struct nand_ecclayout qi_lb60_ecclayout_2gb = { + .eccbytes = 72, + .eccpos = { + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83}, + .oobfree = { + {.offset = 2, + .length = 10}, + {.offset = 84, + .length = 44}} +}; + +#ifdef CONFIG_NAND_SPL +#if (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R3) + #define NAND_BUS_WIDTH 8 + #define NAND_ROW_CYCLE 3 +#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R2) + #define NAND_BUS_WIDTH 8 + #define NAND_ROW_CYCLE 2 +#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R3) + #define NAND_BUS_WIDTH 16 + #define NAND_ROW_CYCLE 3 +#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R2) + #define NAND_BUS_WIDTH 16 + #define NAND_ROW_CYCLE 2 +#endif + +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; +#if NAND_BUS_WIDTH == 16 + for (i = 0; i < len; i += 2) + buf[i] = readw(this->IO_ADDR_R); +#elif NAND_BUS_WIDTH == 8 + for (i = 0; i < len; i++) + buf[i] = readb(this->IO_ADDR_R); +#endif +} + +static u_char nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + return readb(this->IO_ADDR_R); +} +#endif + +static int is_reading; + +static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_ALE) + this->IO_ADDR_W = JZ_NAND_ADDR_ADDR; + else if (ctrl & NAND_CLE) + this->IO_ADDR_W = JZ_NAND_CMD_ADDR; + else + this->IO_ADDR_W = JZ_NAND_DATA_ADDR; + + if (ctrl & NAND_NCE) + writel(readl(&emc->nfcsr) | EMC_NFCSR_NFCE1, &emc->nfcsr); + else + writel(readl(&emc->nfcsr) & ~EMC_NFCSR_NFCE1, &emc->nfcsr); + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +static int jz_nand_device_ready(struct mtd_info *mtd) +{ + return (readl(GPIO_PXPIN(2)) & 0x40000000) ? 1 : 0; +} + +void board_nand_select_device(struct nand_chip *nand, int chip) +{ + /* + * Don't use "chip" to address the NAND device, + * generate the cs from the address where it is encoded. + */ +} + +static int jz_nand_rs_calculate_ecc(struct mtd_info* mtd, const u_char* dat, + u_char* ecc_code) +{ + uint32_t status; + int i; + volatile u8 *paraddr = (volatile u8 *) &emc->nfpar[0]; + + if (is_reading) + return 0; + + do { + status = readl(&emc->nfints); + } while(!(status & EMC_NFINTS_ENCF)); + + /* disable ecc */ + writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); + + for (i = 0; i < 9; i++) + ecc_code[i] = readb(paraddr + i); + + return 0; +} + +static void jz_nand_hwctl(struct mtd_info* mtd, int mode) +{ + uint32_t reg; + + writel(0, &emc->nfints); + reg = readl(&emc->nfecr); + reg |= JZ_NAND_ECC_CTRL_RESET; + reg |= JZ_NAND_ECC_CTRL_ENABLE; + reg |= JZ_NAND_ECC_CTRL_RS; + + switch (mode) { + case NAND_ECC_READ: + reg &= ~JZ_NAND_ECC_CTRL_ENCODING; + is_reading = 1; + break; + case NAND_ECC_WRITE: + reg |= JZ_NAND_ECC_CTRL_ENCODING; + is_reading = 0; + break; + default: + break; + } + + writel(reg, &emc->nfecr); +} + +/* Correct 1~9-bit errors in 512-bytes data */ +static void jz_rs_correct(unsigned char *dat, int idx, int mask) +{ + int i; + + idx--; + + i = idx + (idx >> 3); + if (i >= 512) + return; + + mask <<= (idx & 0x7); + + dat[i] ^= mask & 0xff; + if (i < 511) + dat[i+1] ^= (mask >> 8) & 0xff; +} + +static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + int k; + uint32_t errcnt, index, mask, status; + volatile u8 *paraddr = (volatile u8 *) &emc->nfpar[0]; + + /* Set PAR values */ + static uint8_t all_ff_ecc[] = + {0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f}; + + if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && + read_ecc[2] == 0xff && read_ecc[3] == 0xff && + read_ecc[4] == 0xff && read_ecc[5] == 0xff && + read_ecc[6] == 0xff && read_ecc[7] == 0xff && + read_ecc[8] == 0xff) { + for (k = 0; k < 9; k++) + writeb(all_ff_ecc[k], (paraddr + k)); + } else { + for (k = 0; k < 9; k++) + writeb(read_ecc[k], (paraddr + k)); + } + /* Set PRDY */ + writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr); + + /* Wait for completion */ + do { + status = readl(&emc->nfints); + } while (!(status & EMC_NFINTS_DECF)); + + /* disable ecc */ + writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); + + /* Check decoding */ + if (!(status & EMC_NFINTS_ERR)) + return 0; + + if (status & EMC_NFINTS_UNCOR) { + printf("uncorrectable ecc\n"); + return -1; + } + + errcnt = (status & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; + +#ifdef CONFIG_NAND_SPL + return 0; +#endif + + switch (errcnt) { + case 4: + index = (readl(&emc->nferr[3]) & EMC_NFERR_INDEX_MASK) >> + EMC_NFERR_INDEX_BIT; + mask = (readl(&emc->nferr[3]) & EMC_NFERR_MASK_MASK) >> + EMC_NFERR_MASK_BIT; + jz_rs_correct(dat, index, mask); + case 3: + index = (readl(&emc->nferr[2]) & EMC_NFERR_INDEX_MASK) >> + EMC_NFERR_INDEX_BIT; + mask = (readl(&emc->nferr[2]) & EMC_NFERR_MASK_MASK) >> + EMC_NFERR_MASK_BIT; + jz_rs_correct(dat, index, mask); + case 2: + index = (readl(&emc->nferr[1]) & EMC_NFERR_INDEX_MASK) >> + EMC_NFERR_INDEX_BIT; + mask = (readl(&emc->nferr[1]) & EMC_NFERR_MASK_MASK) >> + EMC_NFERR_MASK_BIT; + jz_rs_correct(dat, index, mask); + case 1: + index = (readl(&emc->nferr[0]) & EMC_NFERR_INDEX_MASK) >> + EMC_NFERR_INDEX_BIT; + mask = (readl(&emc->nferr[0]) & EMC_NFERR_MASK_MASK) >> + EMC_NFERR_MASK_BIT; + jz_rs_correct(dat, index, mask); + default: + break; + } + + return errcnt; +} + +/* + * Main initialization routine + */ +int board_nand_init(struct nand_chip *nand) +{ +#ifdef CONFIG_NAND_SPL +extern void pll_init(void); +extern void sdram_init(void); +extern int serial_init(void); + __gpio_as_sdram_16bit_4720(); + __gpio_as_uart0(); + + pll_init(); + serial_init(); + sdram_init(); + +#if defined(CONFIG_QI_LB60) +#define KEY_U_OUT (32 * 2 + 16) +#define KEY_U_IN (32 * 3 + 19) + __gpio_as_input(KEY_U_IN); + __gpio_enable_pull(KEY_U_IN); + __gpio_as_output(KEY_U_OUT); + __gpio_clear_pin(KEY_U_OUT); + + if (__gpio_get_pin(KEY_U_IN) == 0) + usb_boot(); +#endif +#endif + uint32_t reg; + + reg = readl(&emc->nfcsr); + reg |= EMC_NFCSR_NFE1; /* EMC setup, Set NFE bit */ + writel(reg, &emc->nfcsr); + + writel(EMC_SMCR1_OPT_NAND, &emc->smcr[1]); + + nand->IO_ADDR_R = JZ_NAND_DATA_ADDR; + nand->IO_ADDR_W = JZ_NAND_DATA_ADDR; + nand->cmd_ctrl = jz_nand_cmd_ctrl; + nand->dev_ready = jz_nand_device_ready; +#ifdef CONFIG_NAND_SPL + nand->read_byte = nand_read_byte; + nand->read_buf = nand_read_buf; +#endif + nand->ecc.hwctl = jz_nand_hwctl; + nand->ecc.correct = jz_nand_rs_correct_data; + nand->ecc.calculate = jz_nand_rs_calculate_ecc; + nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; + nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; + nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + nand->ecc.layout = &qi_lb60_ecclayout_2gb; + nand->chip_delay = 50; + + return 0; +}