X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fvf610_nfc.c;h=5c11ac94aada2e1c3c78224f76cb1ce1e1d86fdc;hb=8d1809a966996fdbcddb441c0ff8080d78a89c59;hp=5d72b4a0209f12e9a3985273c0162f223a641d36;hpb=5dec286b8233f658764497b10d455ba447167816;p=u-boot diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 5d72b4a020..5c11ac94aa 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -62,6 +62,7 @@ * Briefly these are bitmasks of controller cycles. */ #define READ_PAGE_CMD_CODE 0x7EE0 +#define READ_ONFI_PARAM_CMD_CODE 0x4860 #define PROGRAM_PAGE_CMD_CODE 0x7FC0 #define ERASE_CMD_CODE 0x4EC0 #define READ_ID_CMD_CODE 0x4804 @@ -71,6 +72,7 @@ /* NFC ECC mode define */ #define ECC_BYPASS 0 #define ECC_45_BYTE 6 +#define ECC_60_BYTE 7 /*** Register Mask and bit definitions */ @@ -149,36 +151,17 @@ struct vf610_nfc { int alt_buf; #define ALT_BUF_ID 1 #define ALT_BUF_STAT 2 +#define ALT_BUF_ONFI 3 struct clk *clk; }; #define mtd_to_nfc(_mtd) \ (struct vf610_nfc *)((struct nand_chip *)_mtd->priv)->priv -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, - .offs = 11, - .len = 4, - .veroffs = 15, - .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, - .offs = 11, - .len = 4, - .veroffs = 15, - .maxblocks = 4, - .pattern = mirror_pattern, -}; +#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) +#define ECC_HW_MODE ECC_45_BYTE -static struct nand_ecclayout vf610_nfc_ecc45 = { +static struct nand_ecclayout vf610_nfc_ecc = { .eccbytes = 45, .eccpos = {19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -190,6 +173,24 @@ static struct nand_ecclayout vf610_nfc_ecc45 = { {.offset = 8, .length = 11} } }; +#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) +#define ECC_HW_MODE ECC_60_BYTE + +static struct nand_ecclayout vf610_nfc_ecc = { + .eccbytes = 60, + .eccpos = { 4, 5, 6, 7, 8, 9, 10, 11, + 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 }, + .oobfree = { + {.offset = 2, + .length = 2} } +}; +#endif static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg) { @@ -363,7 +364,7 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, vf610_nfc_transfer_size(nfc->regs, page_sz); vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN, command, PROGRAM_PAGE_CMD_CODE); - vf610_nfc_ecc_mode(mtd, ECC_45_BYTE); + vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); break; case NAND_CMD_RESET: @@ -388,7 +389,17 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, NAND_CMD_READSTART, READ_PAGE_CMD_CODE); vf610_nfc_addr_cycle(mtd, column, page); - vf610_nfc_ecc_mode(mtd, ECC_45_BYTE); + vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); + break; + + case NAND_CMD_PARAM: + nfc->alt_buf = ALT_BUF_ONFI; + vf610_nfc_transfer_size(nfc->regs, 768); + vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM, + READ_ONFI_PARAM_CMD_CODE); + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, column); + vf610_nfc_ecc_mode(mtd, ECC_BYPASS); break; case NAND_CMD_ERASE1: @@ -400,8 +411,11 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_READID: nfc->alt_buf = ALT_BUF_ID; + nfc->column = 0; vf610_nfc_transfer_size(nfc->regs, 0); vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE); + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, column); break; case NAND_CMD_STATUS: @@ -423,17 +437,11 @@ static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) struct vf610_nfc *nfc = mtd_to_nfc(mtd); uint c = nfc->column; - switch (nfc->alt_buf) { - case ALT_BUF_ID: - *buf = vf610_nfc_get_id(mtd, c); - break; - case ALT_BUF_STAT: - *buf = vf610_nfc_get_status(mtd); - break; - default: - vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); - break; - } + /* Alternate buffers are only supported through read_byte */ + if (nfc->alt_buf) + return; + + vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); nfc->column += len; } @@ -454,8 +462,29 @@ static void vf610_nfc_write_buf(struct mtd_info *mtd, const u_char *buf, /* Read byte from NFC buffers */ static u8 vf610_nfc_read_byte(struct mtd_info *mtd) { + struct vf610_nfc *nfc = mtd_to_nfc(mtd); u8 tmp; - vf610_nfc_read_buf(mtd, &tmp, sizeof(tmp)); + uint c = nfc->column; + + switch (nfc->alt_buf) { + case ALT_BUF_ID: + tmp = vf610_nfc_get_id(mtd, c); + break; + case ALT_BUF_STAT: + tmp = vf610_nfc_get_status(mtd); + break; + case ALT_BUF_ONFI: +#ifdef __LITTLE_ENDIAN + /* Reverse byte since the controller uses big endianness */ + c = nfc->column ^ 0x3; + tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); + break; +#endif + default: + tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); + break; + } + nfc->column++; return tmp; } @@ -603,13 +632,11 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) mtd->priv = chip; chip->priv = nfc; - if (cfg.width == 16) { + if (cfg.width == 16) chip->options |= NAND_BUSWIDTH_16; - vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); - } else { - chip->options &= ~NAND_BUSWIDTH_16; - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); - } + + /* Use 8-bit mode during initialization */ + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); /* Disable subpage writes as we do not provide ecc->hwctl */ chip->options |= NAND_NO_SUBPAGE_WRITE; @@ -624,10 +651,8 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) /* Bad block options. */ if (cfg.flash_bbt) - chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_CREATE; - - chip->bbt_td = &bbt_main_descr; - chip->bbt_md = &bbt_mirror_descr; + chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB | + NAND_BBT_CREATE; /* Set configuration register. */ vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); @@ -654,6 +679,9 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) goto error; } + if (cfg.width == 16) + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); + chip->ecc.mode = NAND_ECC_SOFT; /* default */ /* Single buffer only, max 256 OOB minus ECC status */ @@ -670,7 +698,9 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) goto error; } - chip->ecc.layout = &vf610_nfc_ecc45; + /* Current HW ECC layouts only use 64 bytes of OOB */ + if (mtd->oobsize > 64) + mtd->oobsize = 64; /* propagate ecc.layout to mtd_info */ mtd->ecclayout = chip->ecc.layout; @@ -678,9 +708,15 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) chip->ecc.write_page = vf610_nfc_write_page; chip->ecc.mode = NAND_ECC_HW; - chip->ecc.bytes = 45; chip->ecc.size = PAGE_2K; + chip->ecc.layout = &vf610_nfc_ecc; +#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) chip->ecc.strength = 24; + chip->ecc.bytes = 45; +#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) + chip->ecc.strength = 32; + chip->ecc.bytes = 60; +#endif /* Enable ECC_STATUS */ vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);