/** * Copyright (C) 2010-2014 Ikanos Communications. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * Info : Fusiv VX185 on-chip NAND flash controller driver * * Derived from drivers/mtd/nand/bf5xx_nand.c * Copyright 2006-2008 Analog Devices Inc. * Bryan Wu * * Changelog: * Version 1.0 => NAND driver without ECC * Version 1.1 => Added Hardware ECC support * Added bad block detection and marking support */ //CRS-Porting //Header file additions #include #include #include #include #include #include #include #include #include #include #include #include "../mtdcore.h" #include #include #define DRV_NAME "fusiv-nand" #define DRV_VERSION "1.2" #define DRV_AUTHOR "Kiran Kumar C.S.K " #if defined(CONFIG_FUSIV_VX585) #define DRV_DESC "VX5xx On-Chip NAND FLash Controller Driver" #endif #if defined(CONFIG_FUSIV_VX185) #define DRV_DESC "VX185 On-Chip NAND FLash Controller Driver" #endif #define CONFIG_MTD_NAND_FUSIV_HWECC #ifndef CONFIG_MTD_NAND_FUSIV_HWECC static int hardware_ecc; #else #if defined(CONFIG_FUSIV_VX185) #include "fusiv_bch_decode.c" #endif #if defined(CONFIG_FUSIV_VX585) #include "fusiv_8bit_bch_decode.c" #endif static int hardware_ecc = 1; #endif #ifdef FUSIV_NAND_ECC_DEBUG int nand_scan_done = 0; #endif unsigned int page_size_shift; #if defined(CONFIG_FUSIV_VX185) volatile unsigned int reset_reg_val; #endif #if defined(CONFIG_FUSIV_VX585) static unsigned page_size; #endif /* * Data structure access helper functions */ static struct fusiv_nand_info *to_nand_info(struct platform_device *pdev) { return platform_get_drvdata(pdev); } static struct fusiv_nand_platform *to_nand_plat(struct platform_device *pdev) { return pdev->dev.platform_data; } void print_buf (uint8_t *buf, int len) { for (; len; len--) { if ((len % 16) == 0) printk("\n"); printk("0x%x ", *buf++); } printk("\n"); } /* * struct nand_chip interface function pointers */ void print_NFC_registers (void) { printk("\t***NFC Registers***\n"); printk("scu_regs->nand_status: 0x%x\n",scu_regs->nand_status); printk("scu_regs->rst_strap: 0x%x\n",scu_regs->rst_strap); printk("ID_0: 0x%x\n",fusiv_nfc_readl(NFC_ID_0)); printk("ID_1: 0x%x\n",fusiv_nfc_readl(NFC_ID_2)); printk("ID_2: 0x%x\n",fusiv_nfc_readl(NFC_ID_4)); printk("ID_3: 0x%x\n",fusiv_nfc_readl(NFC_ID_6)); printk("NFC_CONFIG: 0x%x\n",fusiv_nfc_readl(NFC_CONFIG)); printk("NFC_STATUS: 0x%x\n",fusiv_nfc_readl(NFC_STATUS_0)); printk("NFC_INT_ENABLE: 0x%x\n",fusiv_nfc_readl(NFC_INT_ENABLE)); printk("NFC_INT_STATUS: 0x%x\n",fusiv_nfc_readl(NFC_INT_STATUS)); printk("NFC_INT: 0x%x\n",fusiv_nfc_readl(NFC_INT)); printk("BCH Status: 0x%x\n", fusiv_nfc_readl(NFC_BCH_STATUS)); printk("\n"); } /* * Fusiv NFC hardware initialization * - Reset the flash, clear NFC registers, enable/disable ECC */ static int fusiv_nand_hw_init(struct fusiv_nand_info *info) { int err = 0; unsigned short val; volatile unsigned int output; unsigned short page_size; unsigned short chip_size; #if defined(CONFIG_FUSIV_VX585) #endif /* clear the status */ fusiv_nfc_writel(NFC_INT_STATUS, 0); #if defined(CONFIG_FUSIV_VX585) /* Default (slow) timing that should work on all NAND */ //fusiv_nfc_writel(NFC_TIMING_0, 0x03090707); //fusiv_nfc_writel(NFC_TIMING_1, 0x13050404); fusiv_nfc_writel(NFC_TIMING_0, 0x07100a25); fusiv_nfc_writel(NFC_TIMING_1, 0x3d0D100a); /* Read SCU registers: RESET_STRAP SCU Control Register NANDC STATUS */ if (((fusiv_nfc_readl(NFC_CONFIG) >> 8) & 3) == 1) { page_size = 0x1; chip_size = 0x6; } else { page_size = 0x2; chip_size = 0x7; } #endif #if defined(CONFIG_FUSIV_VX185) if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) { /* * Size: 8Gbit, 4KB page size. 512KB block size, Bank 0 enable, * write protect off, 3 row address cycles */ page_size = 0x2; chip_size = 0x7; } else { /* * Size: 4Gbit, 2KB page size. 256KB block size, Bank 0 enable, * write protect off, 3 row address cycles */ page_size = 0x1; chip_size = 0x6; } #endif //VX185 fusiv_nfc_writel(NFC_CONFIG, (C_CSZ(chip_size) | C_BNK(0) | C_PSZ(page_size) | C_WPR(1) | C_RAC(1))); /* Reset nand flash device on bank 0*/ fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_RESET); /* wait for reset to complete */ do{ output = fusiv_nfc_readl(NFC_INT_STATUS); } while ((output & INTS_RSEW) == 0); /* clear the status */ fusiv_nfc_writel(NFC_INT_STATUS, 0); #if 0 /* AP 1000 build timing values */ fusiv_nfc_writel(NFC_TIMING_0, 0x0F1E1E1E); fusiv_nfc_writel(NFC_TIMING_1, 0x37190A14); #endif #if defined(CONFIG_FUSIV_VX185) /* Set timing parameters for standard flash device signals, as per flash device datasheet. The following values are derived from ST-Micro datasheet for 4Gbit flashes. The values are expected to be applicable for 2k page size MLC flash with V-DDQ 2.7V to 3.6V */ if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) != NAND_RESET_1GB_4KB) { /* Modified NAND timing parameters; Please Refer bug 25257*/ fusiv_nfc_writel(NFC_TIMING_0, 0x04050505); fusiv_nfc_writel(NFC_TIMING_1, 0x19050505); } #endif //VX185 /* clear the EXT_INDEX */ fusiv_nfc_writel(NFC_EXT_INDEX, 0); /* Enable/Disable Hardware ECC */ val = fusiv_nfc_readl(NFC_INT_ENABLE); if (hardware_ecc) { if (val & INTE_ECCD) val &= (INTE_ECCE | INTE_RD | INTE_RSEW); } else { if (!(val & INTE_ECCD)) val |= INTE_ECCD; } fusiv_nfc_writel(NFC_INT_ENABLE, val); return err; } /* * fusiv_nand_hwcontrol * * Issue command and address cycles to the chip */ static void fusiv_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { if ((cmd == NAND_CMD_NONE) || (cmd == NAND_CMD_READSTART) || (cmd == NAND_CMD_READID) || (cmd == NAND_CMD_PAGEPROG) || (cmd == NAND_CMD_RNDOUTSTART)) return; if (ctrl & NAND_CLE) { //Write command to flash controller fusiv_nfc_writel(NFC_COMMAND, cmd); } else { //Write the address for read/write/erase fusiv_nfc_writel(NFC_INDEX, cmd); } } /* * fusiv_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready */ static int fusiv_nand_devready(struct mtd_info *mtd) { #if defined(CONFIG_FUSIV_VX585) if (*(volatile unsigned int *)0xb90003a4 == 1) #elif defined(CONFIG_FUSIV_VX185) if (scu_regs->nand_status) #endif return 0; else return 1; } /* * Generic read from NAND flash. * Assumption: INDEX register is already programmed with the address to read from, by the user prior to calling this routine. */ static void fusiv_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { volatile int i,r_val = 0; unsigned short words; if (len <= 0) { pr_err("%s: Read request for invald length of %d bytes\n", \ __FUNCTION__, len); dump_stack(); return; } words = (len/4); if (len % 4) words++; //Issue the large-page/write-triggered-read command 0xE0 fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_RNDOUTSTART); /* CHIP_BUSY takes a few cycles to go high, we should not access the NANDC before this */ for (i = 0; i < 20; i++); /* Wait for page open to complete and CHIP_BUSY to go low. This may take many clock cycles, so ensure we wait enough */ i = 1000; #if defined(CONFIG_FUSIV_VX585) while (((*(volatile unsigned int *)0xb90003a4) & NAND_CHIP_BUSY) && i--); #elif defined(CONFIG_FUSIV_VX185) while ((scu_regs->nand_status & NAND_CHIP_BUSY) && i--); #endif if (!i) { pr_err("%s: page open TIMEOUT\n", __FUNCTION__); return; } /* Do the page read */ for (; words > 0;) { r_val = fusiv_nfc_readl(NFC_DATA); if (--words) { *(unsigned int *)buf = r_val; buf+=4; } } if ((len % 4) == 0) { //last word *(unsigned int *)buf = r_val; } else { for (i =0; i < (len%4); i++, buf++) { *buf = (r_val >> (i*8)) & 0xFF; } } /* Commands to calculate ECC. Make sure we dont issue them for OOB area reads to avoid false ECC error flags */ if (hardware_ecc && !(fusiv_nfc_readl(NFC_INDEX) & mtd->writesize)) { i = 100; /* Tell the controller to calculate-ECC */ fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_CALC_ECC); /* PECC_BUSY takes a few clocks to assert */ #if defined(CONFIG_FUSIV_VX585) while (!((*(volatile unsigned int *)0xb90003a4) & NAND_PECC_BUSY) && i--); #elif defined(CONFIG_FUSIV_VX185) while (!(scu_regs->nand_status & NAND_PECC_BUSY) && i--); #endif /* Wait for PECC_BUSY to go low */ #if defined(CONFIG_FUSIV_VX585) while ((*(volatile unsigned int *)0xb90003a4) & NAND_PECC_BUSY); #elif defined(CONFIG_FUSIV_VX185) while (scu_regs->nand_status & NAND_PECC_BUSY); #endif } #if defined(CONFIG_FUSIV_VX585) // udelay_nand(400); #endif //Turn off chip enable fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_CE_OFF); #if defined(CONFIG_FUSIV_VX585) // udelay_nand(100); #endif } /* Read a single byte from NAND flash * Assumption: INDEX register is already programmed with the address to * read from, by the user prior to calling this routine. */ static uint8_t fusiv_nand_read_byte(struct mtd_info *mtd) { uint8_t val; fusiv_nand_read_buf(mtd, &val, 1); return val; } /* Generic write to NAND flash * Assumption: INDEX register is already programmed with the address to * write to, by the user prior to calling this routine. */ static void fusiv_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { volatile int i,w_val = 0; unsigned short words; if (len <= 0) { pr_err("%s: Write request for invald length of %d bytes\n", \ __FUNCTION__, len); dump_stack(); return; } words = (len/4); if (len % 4) words++; /* Do the page write */ for (i = 0; words > 0; i++) { if (--words) { w_val = *(unsigned int *)buf; fusiv_nfc_writel(NFC_DATA, w_val); buf+=4; } } if ((len % 4) == 0) { //last word w_val = *(unsigned int *)buf; fusiv_nfc_writel(NFC_DATA, w_val); } else { w_val = 0; for (i =0; i < (len%4); i++, buf++) { w_val |= ((unsigned int)*buf << (i*8)); } fusiv_nfc_writel(NFC_DATA, w_val); } //Issue the page-program command 0x10 fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_PAGEPROG); #if defined(CONFIG_FUSIV_VX185) /* Additional Command Completion Delay for Program Page command*/ if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) udelay(1); #endif #if defined(CONFIG_FUSIV_VX585) udelay(1); #endif /* Commands to write ECC bytes to flash. Make sure we dont issue them for OOB area writes, since ECC does not cover OOB area */ if (hardware_ecc && \ !(fusiv_nfc_readl(NFC_INDEX) & mtd->writesize)) { i = 20; /* PECC_BUSY takes a few clocks to assert */ #if defined(CONFIG_FUSIV_VX585) while (!((*(volatile unsigned int *)0xb90003a4) & NAND_PECC_BUSY) && i--); #elif defined(CONFIG_FUSIV_VX185) while (!(scu_regs->nand_status & NAND_PECC_BUSY) && i--); #endif /* Wait for PECC_BUSY to go low */ #if defined(CONFIG_FUSIV_VX585) while ((*(volatile unsigned int *)0xb90003a4) & NAND_PECC_BUSY); #elif defined(CONFIG_FUSIV_VX185) while (scu_regs->nand_status & NAND_PECC_BUSY); #endif } //Turn off chip enable fusiv_nfc_writel(NFC_COMMAND, NAND_CMD_CE_OFF); } /* Get the status byte from the NAND flash */ int fusiv_nand_status(struct mtd_info *mtd, struct nand_chip *this) { return fusiv_nfc_readl(NFC_STATUS_0); } /* ECC Specific routines */ #ifdef CONFIG_MTD_NAND_FUSIV_HWECC /* Good blocks match the following pattern at chip->badblockpos * in OOB area */ static uint8_t scan_ff_pattern[] = { 0xff }; /* Good/bad block check location and pattern in OOB area */ static struct nand_bbt_descr fusiv_bb_pattern = { .options = 0, .offs = 0, .len = 1, .pattern = scan_ff_pattern }; /* OOB area layout for 2k Page size flash. Offset 0: Bad block marker Offset 32 to 63: ECC bytes written by controller Offset 1 to 31 : Free for use (by filesystem). */ static struct nand_ecclayout fusiv_oobinfo_2048 = { .eccbytes = 32, .eccpos = { 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 = {{1, 31}} }; /* OOB area layout for 4k Page size flash. Offset 0: Bad block marker Offset 64 to 127: ECC bytes written by controller Offset 1 to 33 : Free for use (by filesystem). */ static struct nand_ecclayout fusiv_oobinfo_4096 = { .eccbytes = 64, .eccpos = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}, .oobfree = {{1, 63}} }; #if defined (CONFIG_FUSIV_VX585) static struct nand_ecclayout fusiv58x_oobinfo_4096 = { .eccbytes = 128, .eccpos = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191}, .oobfree = {{1, 63}} }; static struct nand_ecclayout fusiv58x_oobinfo_2048 = { .eccbytes = 64, .eccpos = { 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, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}, .oobfree = {{1, 31}} }; #endif static void fusiv_nand_bug(struct mtd_info *mtd) { BUG(); } /* Low-level page-write routine for ECC-ON mode */ static void fusiv_nand_write_page_lowlevel(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { int status = 0; chip->write_buf(mtd, buf, mtd->writesize); status = chip->waitfunc(mtd, chip); #if defined(CONFIG_FUSIV_VX585) if (status & NAND_STATUS_FAIL) { chip->write_buf(mtd, buf, mtd->writesize); status = chip->waitfunc(mtd, chip); } /* Read the Status of the 8Gb NAND Flash Chip */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); while (!(fusiv_nfc_readl(NFC_STATUS_0) & NAND_STATUS_READY)); #endif #if defined(CONFIG_FUSIV_VX185) if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) { if (status & NAND_STATUS_FAIL) { chip->write_buf(mtd, buf, mtd->writesize); status = chip->waitfunc(mtd, chip); } /* Read the Status of the 8Gb NAND Flash Chip */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); while (!(fusiv_nfc_readl(NFC_STATUS_0) & NAND_STATUS_READY)); } #endif //VX185 } /* Page-write routine for ECC-ON mode */ static int fusiv_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, int oob_required, int page, int cached, int raw) { int status = 0; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); chip->ecc.write_page(mtd, chip, buf, 1); status = chip->waitfunc(mtd, chip); #if defined(CONFIG_FUSIV_VX585) if (status & NAND_STATUS_FAIL) { chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); chip->ecc.write_page(mtd, chip, buf, 1); status = chip->waitfunc(mtd, chip); } /* Read the Status of the 8Gb NAND Flash Chip */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); while (!(fusiv_nfc_readl(NFC_STATUS_0) & NAND_STATUS_READY)); #endif #if defined(CONFIG_FUSIV_VX185) if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) { if (status & NAND_STATUS_FAIL) { chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); chip->ecc.write_page(mtd, chip, buf, 1); status = chip->waitfunc(mtd, chip); } /* Read the Status of the 8Gb NAND Flash Chip */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); while (!(fusiv_nfc_readl(NFC_STATUS_0) & NAND_STATUS_READY)); } #endif //VX185 return status & NAND_STATUS_FAIL ? -EIO : 0; } /************************************************************************** * Fn : Check if the page is erased. * * * * 1. If 32 bytes of oob area are 0xFF, consider the page as erased. * * However bit-flips during oob area area can cause this logic to fail * * 2. Check for byte 4 & 5 of the ecc for each section. When a page is * * programmed 12 bits of those 2 bytes are expected to be '0'. * * Considering 4 possible bit flips, atleast 8 bits have to be '0' to * * flag a page as 'programmed' * * * **************************************************************************/ static int fusiv_check_erased_page (unsigned int page_number, struct nand_chip *chip, struct mtd_info *mtd) { unsigned char erased_page_ecc_bytes[32]; unsigned char *sectionEcc; unsigned int i, clean, section, numSections,zeroBits=0; unsigned short ecc45=0; numSections = mtd->writesize/BCH_SECTION_SIZE; memset(erased_page_ecc_bytes, 0xff, 32); chip->ecc.read_oob(mtd, chip, page_number); if (memcmp((unsigned char *)(&chip->oob_poi[32]), \ erased_page_ecc_bytes, 32) == 0) return 1; else { clean = 1; // maybee a bit (or a few bits) have flipped for (section = 0; section < numSections; section++) { sectionEcc = ((u8*)(chip->oob_poi)) + 32 + 8 * section; zeroBits = 0; ecc45 = (sectionEcc[NAND_ECC_BYTE4] << 4) | (sectionEcc[NAND_ECC_BYTE5] >> 4); for (i = 0; i < NAND_MAX_COUNT_ZERO; i++) if((ecc45 & (1 << i)) == 0) zeroBits++; if (zeroBits >= NAND_MIN_COUNT_ZERO) { clean = 0; break; } } if (clean) return 1; } return 0; } /* Try to find out if the page is an erased page. An erased page will have for ECC correction. An erased page will have */ static int fusiv_check_erased_page_4096 (unsigned int page_number, struct nand_chip *chip, struct mtd_info *mtd) { #if defined(CONFIG_FUSIV_VX185) #define ECC_SIZE 64 #else #define ECC_SIZE 128 #endif unsigned char erased_page_ecc_bytes[ECC_SIZE]; memset(erased_page_ecc_bytes, 0xff, ECC_SIZE); chip->ecc.read_oob(mtd, chip, page_number); if (memcmp((unsigned char *)(&chip->oob_poi[ECC_SIZE]), \ erased_page_ecc_bytes, ECC_SIZE) == 0) return 1; else return 0; } #if defined(CONFIG_FUSIV_VX185) /** * fusiv_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * * The hw generator calculates the error syndrome automatically. */ static int fusiv_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf) { int bch_error_status, errs = 0; uint8_t sections, i, j, fixable = 1, k; unsigned short syn_val[10]; unsigned short errlocations[MAX_FIXABLE_ERRS]; sections = mtd->writesize/BCH_SECTION_SIZE; chip->read_buf(mtd, buf, mtd->writesize); /* Check for error on read */ if ((bch_error_status = bch_get_error_flags()) != 0) { if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) { if (fusiv_check_erased_page_4096(fusiv_nfc_readl(NFC_INDEX) >> page_size_shift,chip,mtd)) { return 0; } } else { if (fusiv_check_erased_page(fusiv_nfc_readl(NFC_INDEX) >> page_size_shift,chip,mtd)) { return 0; } } #ifdef FUSIV_NAND_ECC_DEBUG pr_debug("NAND ECC Error for page no: 0x%x\n", fusiv_nfc_readl(NFC_INDEX) >> page_size_shift); pr_debug("BCH Error flags: 0x%x\n",bch_error_status); dump_stack(); chip->ecc.read_oob(mtd, chip, fusiv_nfc_readl(NFC_INDEX) >> page_size_shift); pr_debug("Spare area dump for the page: \n"); print_buf(chip->oob_poi, mtd->oobsize); #endif for (i = 0; i < sections; i++) { if (bch_error_status & (1 << i)) { read_syndrome_vals(&syn_val[1], i); syn_val[0] = 0; syn_val[9] = 0; for (k = 0; k < 4; k++) errlocations[k] = 0; errs = bch_locate_errors(&syn_val[0], &errlocations[0]); #ifdef FUSIV_NAND_ECC_DEBUG pr_debug("**Section No: %d**\n",i); for (k = 0; k < 10; k++) pr_debug("syn_val[%d] = 0x%x\n", k, syn_val[k]); printk("No of errs located = %d\n",errs); for (k = 0; k < errs; k++) printk("errlocations[%d] = 0x%x\n",k, errlocations[k]); #endif if (errs >= 0) { for (j = 0; j < errs; j++) { fix_errors(i, errlocations[j], (char *)buf); } } else { #ifdef FUSIV_NAND_ECC_DEBUG printk("Page No 0x%x has unfixable \ ECC errors! Index: 0x%x\n", \ (fusiv_nfc_readl(NFC_INDEX) & \ 0x3FFFF000) >> page_size_shift, \ fusiv_nfc_readl(NFC_INDEX)); #endif /* Too many errors, page unfixable */ fixable = 0; break; } } } } /* Update ECC correction stats for the device */ if (fixable) mtd->ecc_stats.corrected += errs; else mtd->ecc_stats.failed++; return 0; } #endif //VX185 #if defined(CONFIG_FUSIV_VX585) static void fix_single_error(int bit, int offset, unsigned long *dest) { // Fix a single NAND bit error in the target buffer // @offset is guaranteed to be long aligned unsigned long *d; d = dest + (offset >> 2); *d ^= (1 << bit); } static short find_sector_errors(int sector, unsigned short page_size, short *errlocations) { // Return which bits, if any, in a 512 byte sector of a page need correcting unsigned long bch_errflags; short syn_val[NR_SYNDROMES + 2]; short page_errs; bch_errflags = bch_get_error_flags(); page_errs = 0; if ((bch_errflags & (1 << sector)) != 0) { /* Note - bch_locate_errors() is derived from code that expects * the syndromes in syn_val[1]..syn_val[N] and requires one extra * syn_val element at the end of the array. Hardware syndromes * are, therefore, read into elements 1 upwards. */ read_syndrome_vals(&syn_val[1], sector); syn_val[0] = 0; syn_val[NR_SYNDROMES + 1] = 0; page_errs = bch_locate_errors(&syn_val[0], errlocations, MAX_FIXABLE_ERRS); } return page_errs; } /** * fusiv_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * * The hw generator calculates the error syndrome automatically. */ static int fusiv_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf) { int bch_error_status, errs = 0; uint8_t sections, i, j, fixable = 1, k; short errlocations[MAX_FIXABLE_ERRS]; int page_err_loc; sections = mtd->writesize/BCH_SECTION_SIZE; chip->read_buf(mtd, buf, mtd->writesize); if ((bch_error_status = bch_get_error_flags()) != 0) { if (((fusiv_nfc_readl(NFC_CONFIG) >> 8) & 3) == 1) { if (fusiv_check_erased_page(fusiv_nfc_readl(NFC_INDEX) >> NAND_PAGE_SHIFT_2KB, chip, mtd)) return 0; } else { if (fusiv_check_erased_page_4096(fusiv_nfc_readl(NFC_INDEX) >> NAND_PAGE_SHIFT_4KB, chip, mtd)) return 0; } for (i = 0; i < sections; i++) { errs = find_sector_errors(i, mtd->writesize, &errlocations[0]); if (errs < 0) { // Page cannot be corrected, so fail this image download fixable = 0; break; } for (j = 0; j < errs; j++) { #if 1 if (errlocations[i] >= 0) { page_err_loc = i << 9 + ((errlocations[i] >> 3) & ~3); if (page_err_loc >= 0 && page_err_loc < mtd->writesize) fix_single_error(errlocations[j] & 0x1f, page_err_loc, (char *)buf); } #else fix_errors(i, errlocations[j],(char *)buf); #endif } } } /* Update ECC correction stats for the device */ if (fixable) mtd->ecc_stats.corrected += errs; else mtd->ecc_stats.failed++; return 0; } #endif /*VX585*/ static int fusiv_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { int status = 0; chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); status = chip->waitfunc(mtd, chip); return status & NAND_STATUS_FAIL ? -EIO : 0; } static int fusiv_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) { chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); return 1; } #endif //CRS- Porting //From 3.4.1 MTD_PARTITION is removed so removing the MACRO // and the subsequent check /* * Device management interface */ static int fusiv_nand_add_partition(struct fusiv_nand_info *info) { struct mtd_info *mtd = &info->mtd; struct mtd_partition *parts = info->platform->partitions; int nr = info->platform->nr_partitions; return add_mtd_partitions(mtd, parts, nr); } /* * fusiv_nand_probe * * called by device layer when it finds a device matching * one our driver can handled. This code checks to see if * it can allocate all necessary resources then calls the * nand layer to look for devices */ static int fusiv_nand_probe(struct platform_device *pdev) { struct fusiv_nand_platform *plat = to_nand_plat(pdev); struct fusiv_nand_info *info = NULL; struct nand_chip *chip = NULL; struct mtd_info *mtd = NULL; int err = 0; dev_dbg(&pdev->dev, "(%p)\n", pdev); #if defined(CONFIG_FUSIV_VX185) // Read the Reset Register strap reset_reg_val = scu_regs->rst_strap; #endif if (!plat) { dev_err(&pdev->dev, "No platform specific information \ for NFC driver\n"); return -EINVAL; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&pdev->dev, "Mem allocation failed for flash \ info in NFC driver\n"); err = -ENOMEM; goto out_err_kzalloc; } platform_set_drvdata(pdev, info); spin_lock_init(&info->controller.lock); init_waitqueue_head(&info->controller.wq); info->device = &pdev->dev; info->platform = plat; /* initialise chip data struct */ chip = &info->chip; chip->read_buf = fusiv_nand_read_buf; chip->write_buf = fusiv_nand_write_buf; chip->read_byte = fusiv_nand_read_byte; chip->cmd_ctrl = fusiv_nand_hwcontrol; chip->dev_ready = fusiv_nand_devready; //chip->waitfunc = fusiv_nand_status; chip->priv = &info->mtd; chip->controller = &info->controller; chip->IO_ADDR_R = (void __iomem *) NFC_BASEADDR+NFC_DATA; chip->IO_ADDR_W = (void __iomem *) NFC_BASEADDR+NFC_DATA; chip->chip_delay = 0; /* initialise mtd info data struct */ mtd = &info->mtd; mtd->priv = chip; mtd->owner = THIS_MODULE; /* initialise the hardware */ err = fusiv_nand_hw_init(info); if (err) goto out_err_hw_init; if (hardware_ecc) { chip->ecc.mode = NAND_ECC_HW_SYNDROME; #if defined(CONFIG_FUSIV_VX585) if (((fusiv_nfc_readl(NFC_CONFIG) >> 8) & 3) == 1) { chip->ecc.layout = &fusiv58x_oobinfo_2048; chip->ecc.size = NAND_PAGE_SIZE_2KB; chip->ecc.bytes = NAND_ECC_64; page_size_shift = NAND_PAGE_SHIFT_2KB; } else { chip->ecc.layout = &fusiv58x_oobinfo_4096; chip->ecc.size = NAND_PAGE_SIZE_4KB; chip->ecc.bytes = NAND_ECC_128; page_size_shift = NAND_PAGE_SHIFT_4KB; } #endif #if defined(CONFIG_FUSIV_VX185) if ((reset_reg_val & NAND_RESET_1GB_4KB_MASK) == NAND_RESET_1GB_4KB) { chip->ecc.layout = &fusiv_oobinfo_4096; chip->ecc.size = NAND_PAGE_SIZE_4KB; chip->ecc.bytes = NAND_ECC_64; page_size_shift = NAND_PAGE_SHIFT_4KB; } else { chip->ecc.layout = &fusiv_oobinfo_2048; chip->ecc.size = NAND_PAGE_SIZE_2KB; chip->ecc.bytes = NAND_ECC_32; page_size_shift = NAND_PAGE_SHIFT_2KB; } #endif //VX185 chip->ecc.hwctl = (void *)fusiv_nand_bug; chip->ecc.calculate = (void *)fusiv_nand_bug; chip->ecc.correct = (void *)fusiv_nand_bug; chip->write_page = fusiv_nand_write_page; chip->ecc.write_page = fusiv_nand_write_page_lowlevel; chip->ecc.read_page = fusiv_nand_read_page; chip->ecc.write_oob = fusiv_nand_write_oob; chip->ecc.read_oob = fusiv_nand_read_oob; chip->badblock_pattern = &fusiv_bb_pattern; chip->ecc.strength = 0; } else { chip->ecc.mode = NAND_ECC_NONE; } /* scan hardware nand chip and setup mtd info data struct */ if (nand_scan(mtd, 1)) { err = -ENXIO; goto out_err_nand_scan; } #ifdef FUSIV_NAND_ECC_DEBUG nand_scan_done = 1; #endif /* add NAND partition */ fusiv_nand_add_partition(info); dev_dbg(&pdev->dev, "NFC driver initialised ok\n"); return 0; out_err_nand_scan: out_err_hw_init: platform_set_drvdata(pdev, NULL); kfree(info); out_err_kzalloc: return err; } static int fusiv_nand_remove(struct platform_device *pdev) { struct fusiv_nand_info *info = to_nand_info(pdev); struct mtd_info *mtd = NULL; platform_set_drvdata(pdev, NULL); /* first thing we need to do is release all our mtds * and their partitions, then go through freeing the * resources used */ mtd = &info->mtd; if (mtd) { nand_release(mtd); kfree(mtd); } /* free the common resources */ kfree(info); return 0; } /* PM Support */ #ifdef CONFIG_PM static int fusiv_nand_suspend(struct platform_device *dev, pm_message_t pm) { // struct fusiv_nand_info *info = platform_get_drvdata(dev); return 0; } static int fusiv_nand_resume(struct platform_device *dev) { // struct fusiv_nand_info *info = platform_get_drvdata(dev); return 0; } #else #define fusiv_nand_suspend NULL #define fusiv_nand_resume NULL #endif /* driver device registration */ static struct platform_driver fusiv_nand_driver = { .probe = fusiv_nand_probe, .remove = fusiv_nand_remove, .suspend = fusiv_nand_suspend, .resume = fusiv_nand_resume, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, }; static int __init fusiv_nand_init(void) { pr_info("%s, Version %s (c) 2010 Ikanos, Inc.\n", \ DRV_DESC, DRV_VERSION); return platform_driver_register(&fusiv_nand_driver); } static void __exit fusiv_nand_exit(void) { platform_driver_unregister(&fusiv_nand_driver); } MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESC); MODULE_ALIAS("platform:" DRV_NAME); module_init(fusiv_nand_init); module_exit(fusiv_nand_exit);