/* * ------------------------------------------------------------------------ * stm_afm_nand.c STMicroelectronics Advanced Flex Mode NAND Flash driver * for SoC's with the Hamming NAND Controller. * ------------------------------------------------------------------------ * * Copyright (c) 2010 STMicroelectronics Limited * Author: Angus Clark * * ------------------------------------------------------------------------ * May be copied or modified under the terms of the GNU General Public * License Version 2.0 only. See linux/COPYING for more information. * ------------------------------------------------------------------------ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stm_nand_ecc.h" #include "stm_nandc_regs.h" #define NAME "stm-nand-afm" #ifdef CONFIG_MTD_PARTITIONS #include static const char *part_probes[] = { "cmdlinepart", NULL }; #endif #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* * Support for STM boot-mode ECC: The STM NAND Boot Controller uses a different * ECC scheme to the AFM controller. In order to support boot-mode ECC data, we * maintian two sets of ECC parameters and switch depending on which partition * we are about to read from. */ struct ecc_params { /* nand_chip params */ struct nand_ecc_ctrl ecc_ctrl; int subpagesize; /* mtd_info params */ u_int32_t subpage_sft; }; static void afm_select_eccparams(struct mtd_info *mtd, loff_t offs); static void afm_write_page_boot(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf); static int afm_read_page_boot(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page); /* Module parameter for specifying name of boot partition */ static char *nbootpart; module_param(nbootpart, charp, 0000); MODULE_PARM_DESC(nbootpart, "MTD name of NAND boot-mode ECC partition"); #else #define afm_select_eccparams(x, y) do {} while (0); #endif /* CONFIG_STM_NAND_AFM_BOOTMODESUPPORT */ /* External functions */ /* AFM 32-byte program block */ struct afm_prog { uint8_t instr[16]; uint32_t addr_reg; uint32_t extra_reg; uint8_t cmds[4]; uint32_t seq_cfg; } __attribute__((__packed__)); /* NAND device connected to STM NAND Controller */ struct stm_nand_afm_device { struct nand_chip chip; struct mtd_info mtd; int csn; struct stm_nand_timing_data *timing_data; struct device *dev; #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT unsigned long boot_start; unsigned long boot_end; struct ecc_params ecc_boot; struct ecc_params ecc_afm; #endif #ifdef CONFIG_MTD_PARTITIONS int nr_parts; struct mtd_partition *parts; #endif }; /* STM NAND AFM Controller */ struct stm_nand_afm_controller { void __iomem *base; void __iomem *fifo_cached; unsigned long fifo_phys; /* resources */ struct device *dev; unsigned int map_base; unsigned int map_size; unsigned int irq; spinlock_t lock; /* save/restore IRQ flags */ int current_csn; /* access control */ struct nand_hw_control hwcontrol; /* irq completions */ struct completion rbn_completed; struct completion seq_completed; /* emulate MTD nand_base.c implementation */ uint32_t status; uint32_t col; uint32_t page; /* devices connected to controller */ struct stm_nand_afm_device *devices[0]; }; #define afm_writereg(val, reg) iowrite32(val, afm->base + (reg)) #define afm_readreg(reg) ioread32(afm->base + (reg)) static struct stm_nand_afm_controller *mtd_to_afm(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct nand_hw_control *controller = chip->controller; struct stm_nand_afm_controller *afm; afm = container_of(controller, struct stm_nand_afm_controller, hwcontrol); return afm; } /* * Define some template AFM programs */ #define AFM_INSTR(cmd, op) ((cmd) | ((op) << 4)) /* AFM Prog: Block Erase */ struct afm_prog afm_prog_erase = { .cmds = { NAND_CMD_ERASE1, NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_CMD_STATUS }, .instr = { AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_ADDR, 0), AFM_INSTR(AFM_ADDR, 1), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CMD, 3), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Block Erase, extra address cycle */ struct afm_prog afm_prog_erase_ext = { .cmds = { NAND_CMD_ERASE1, NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_CMD_STATUS }, .instr = { AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_ADDR, 0), AFM_INSTR(AFM_ADDR, 1), AFM_INSTR(AFM_ADDR, 2), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CMD, 3), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Read OOB [SmallPage] */ struct afm_prog afm_prog_read_oob_sp = { .cmds = { NAND_CMD_READOOB }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Read OOB [LargePage] */ struct afm_prog afm_prog_read_oob_lp = { .cmds = { NAND_CMD_READ0, NAND_CMD_READSTART }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Read Raw Page and OOB Data [SmallPage] * * Note, "SPARE3" would normally be used to read the OOB data. However, SPARE3 * has been observed to cause problems with EMI Arbitration resulting in system * deadlock. To avoid such problems, we use the DATA0 command here. This will * have the effect of over-reading 48 bytes from the end of OOB area but should * be benign on current NAND devices. */ struct afm_prog afm_prog_read_raw_sp = { .cmds = { NAND_CMD_READ0 }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Read Raw Page and OOB Data [LargePage] */ struct afm_prog afm_prog_read_raw_lp = { .cmds = { NAND_CMD_READ0, NAND_CMD_READSTART }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO, }; /* AFM Prog: Write Raw Page [SmallPage] * OOB written with FLEX mode. */ struct afm_prog afm_prog_write_raw_sp_a = { .cmds = { NAND_CMD_SEQIN, NAND_CMD_READ0, NAND_CMD_PAGEPROG, NAND_CMD_STATUS, }, .instr = { AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CMD, 3), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO | AFM_SEQ_CFG_DIR_WRITE, }; /* AFM Prog: Write Raw Page and OOB Data [LargePage] */ struct afm_prog afm_prog_write_raw_lp = { .cmds = { NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_CMD_STATUS, }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO | AFM_SEQ_CFG_DIR_WRITE, }; /* AFM Prog: Write Page and OOB Data, with ECC support [SmallPage] * * Note, the AFM command, "SPARE3", would normally be used to write the OOB * data, with ECC inserted on the fly by the NAND controller. However, the * SPARE3 command has been observed to cause EMI Arbitration issues resulting in * a bus stall and system deadlock. To avoid this problem, we switch to FLEX * mode to write the OOB data, extracting and inserting the ECC bytes from the * NAND ECC checkcode regiter (see afm_write_page_ecc_sp()) */ struct afm_prog afm_prog_write_ecc_sp_a = { .cmds = { NAND_CMD_SEQIN, NAND_CMD_READ0, NAND_CMD_PAGEPROG, NAND_CMD_STATUS, }, .instr = { AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 1), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO | AFM_SEQ_CFG_DIR_WRITE, }; /* AFM Prog: Write Page and OOB Data, with ECC support [LargePage] */ struct afm_prog afm_prog_write_ecc_lp = { .cmds = { NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_CMD_STATUS, }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 2), AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO | AFM_SEQ_CFG_DIR_WRITE, }; /* AFM Prog: Write OOB Data [LargePage] */ struct afm_prog afm_prog_write_oob_lp = { .cmds = { NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_CMD_STATUS }, .instr = { AFM_INSTR(AFM_CMD, 0), AFM_INSTR(AFM_DATA, 0), AFM_INSTR(AFM_CMD, 1), AFM_INSTR(AFM_CMD, 2), AFM_INSTR(AFM_CHECK, 0), AFM_INSTR(AFM_STOP, 0) }, .seq_cfg = AFM_SEQ_CFG_GO | AFM_SEQ_CFG_DIR_WRITE, }; /* * STMicroeclectronics H/W ECC layouts * * AFM4 ECC: 512-byte data records, 3 bytes H/W ECC, 1 byte S/W ECC, 3 * bytes marker ({'A', 'F', 'M'}) * Boot-mode ECC: 128-byte data records, 3 bytes ECC + 1 byte marker ('B') * */ static struct nand_ecclayout afm_oob_16 = { .eccbytes = 7, .eccpos = { /* { HW_ECC0, HW_ECC1, HW_ECC2, 'A', 'F', 'M', SW_ECC } */ 0, 1, 2, 3, 4, 5, 6}, .oobfree = { {.offset = 7, . length = 9}, } }; static struct nand_ecclayout afm_oob_64 = { .eccbytes = 28, .eccpos = { /* { HW_ECC0, HW_ECC1, HW_ECC2, 'A', 'F', 'M', SW_ECC } */ 0, 1, 2, 3, 4, 5, 6, /* Record 0 */ 16, 17, 18, 19, 20, 21, 22, /* Record 1 */ 32, 33, 34, 35, 36, 37, 38, /* Record 2 */ 48, 49, 50, 51, 52, 53, 54, /* Record 3 */ }, .oobfree = { {.offset = 7, .length = 9 }, {.offset = 23, .length = 9 }, {.offset = 39, .length = 9 }, {.offset = 55, .length = 9 }, } }; #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT static struct nand_ecclayout boot_oob_16 = { .eccbytes = 16, .eccpos = { 0, 1, 2, 3, /* Record 0: ECC0, ECC1, ECC2, 'B' */ 4, 5, 6, 7, /* Record 1: ECC0, ECC1, ECC2, 'B' */ 8, 9, 10, 11, /* ... */ 12, 13, 14, 15 }, .oobfree = {{0, 0} }, /* No free space in OOB */ }; static struct nand_ecclayout boot_oob_64 = { .eccbytes = 64, .eccpos = { 0, 1, 2, 3, /* Record 0: ECC0, ECC1, ECC2, B */ 4, 5, 6, 7, /* Record 1: ECC0, ECC1, ECC2, B */ 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 = {{0, 0} }, /* No free OOB bytes */ }; #endif /* Pattern descriptors for scanning bad-block scanning - add support for AFM ECC * scheme */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static struct nand_bbt_descr bbt_scan_sp = { .options = (NAND_BBT_SCAN2NDPAGE | NAND_BBT_SCANSTMAFMECC), .offs = 5, .len = 1, .pattern = scan_ff_pattern }; static struct nand_bbt_descr bbt_scan_lp = { .options = (NAND_BBT_SCAN2NDPAGE | NAND_BBT_SCANSTMAFMECC), .offs = 0, .len = 2, .pattern = scan_ff_pattern }; /* * AFM Interrupts */ #define AFM_IRQ (1 << 0) #define AFM_IRQ_RBN (1 << 2) #define AFM_IRQ_DATA_DREQ (1 << 3) #define AFM_IRQ_SEQ_DREQ (1 << 4) #define AFM_IRQ_CHECK (1 << 5) #define AFM_IRQ_ECC_FIX (1 << 6) static void afm_enable_interrupts(struct stm_nand_afm_controller *afm, uint32_t irqs) { uint32_t reg; reg = afm_readreg(EMINAND_INTERRUPT_ENABLE); reg |= irqs; afm_writereg(reg, EMINAND_INTERRUPT_ENABLE); } static void afm_disable_interrupts(struct stm_nand_afm_controller *afm, uint32_t irqs) { uint32_t reg; reg = afm_readreg(EMINAND_INTERRUPT_ENABLE); reg &= ~irqs; afm_writereg(reg, EMINAND_INTERRUPT_ENABLE); } static irqreturn_t afm_irq_handler(int irq, void *dev) { struct stm_nand_afm_controller *afm = (struct stm_nand_afm_controller *)dev; unsigned int irq_status; irq_status = afm_readreg(EMINAND_INTERRUPT_STATUS); /* RBn */ if (irq_status & 0x4) { afm_writereg(0x04, EMINAND_INTERRUPT_CLEAR); complete(&afm->rbn_completed); } /* ECC_fix */ if (irq_status & 0x40) afm_writereg(0x10, EMINAND_INTERRUPT_CLEAR); /* Seq_req */ if (irq_status & AFM_IRQ_SEQ_DREQ) { afm_writereg(0x40, EMINAND_INTERRUPT_CLEAR); complete(&afm->seq_completed); } return IRQ_HANDLED; } /* * AFM Initialisation */ /* AFM set generic config register */ static void afm_generic_config(struct stm_nand_afm_controller *afm, uint32_t busw, uint32_t page_size, uint32_t chip_size) { uint32_t reg; reg = 0x00; if ((busw & NAND_BUSWIDTH_16) == 0) reg |= 0x1 << 16; /* data_8_not_16 */ if (page_size > 512) { /* large page */ reg |= 0x1 << 17; /* page size */ if (chip_size > (128 << 20)) reg |= 0x1 << 18; /* extra addr cycle */ } else if (chip_size > (32 << 20)) { /* small page */ reg |= 0x1 << 18; /* extra addr cycle */ } dev_dbg(afm->dev, "setting AFM_GENERIC_CONFIG_REG = 0x%08x\n", reg); afm_writereg(reg, EMINAND_AFM_GENERIC_CONFIG_REG); } /* AFM configure timing parameters */ static void afm_set_timings(struct stm_nand_afm_controller *afm, struct stm_nand_timing_data *tm) { uint32_t n; uint32_t reg; struct clk *emi_clk; uint32_t emi_t_ns; /* Timings set in terms of EMI clock... */ emi_clk = clk_get(NULL, "emi_clk"); if (!emi_clk || IS_ERR(emi_clk)) { printk(KERN_WARNING NAME ": Failed to find EMI clock. " "Using default 100MHz.\n"); emi_t_ns = 10; } else { emi_t_ns = 1000000000UL / clk_get_rate(emi_clk); } /* CONTROL_TIMING */ n = (tm->sig_setup + emi_t_ns - 1)/emi_t_ns; reg = (n & 0xff) << 0; n = (tm->sig_hold + emi_t_ns - 1)/emi_t_ns; reg |= (n & 0xff) << 8; n = (tm->CE_deassert + emi_t_ns - 1)/emi_t_ns; reg |= (n & 0xff) << 16; n = (tm->WE_to_RBn + emi_t_ns - 1)/emi_t_ns; reg |= (n & 0xff) << 24; dev_dbg(afm->dev, "setting CONTROL_TIMING = 0x%08x\n", reg); afm_writereg(reg, EMINAND_CONTROL_TIMING); /* WEN_TIMING */ n = (tm->wr_on + emi_t_ns - 1)/emi_t_ns; reg = (n & 0xff) << 0; n = (tm->wr_off + emi_t_ns - 1)/emi_t_ns; reg |= (n & 0xff) << 8; dev_dbg(afm->dev, "setting WEN_TIMING = 0x%08x\n", reg); afm_writereg(reg, EMINAND_WEN_TIMING); /* REN_TIMING */ n = (tm->rd_on + emi_t_ns - 1)/emi_t_ns; reg = (n & 0xff) << 0; n = (tm->rd_off + emi_t_ns - 1)/emi_t_ns; reg |= (n & 0xff) << 8; dev_dbg(afm->dev, "setting REN_TIMING = 0x%08x\n", reg); afm_writereg(reg, EMINAND_REN_TIMING); } /* Initialise the AFM NAND controller */ static struct stm_nand_afm_controller * __init afm_init_controller(struct platform_device *pdev) { struct stm_plat_nand_flex_data *pdata = pdev->dev.platform_data; struct stm_nand_afm_controller *afm; struct resource *resource; int err = 0; afm = kzalloc(sizeof(struct stm_nand_afm_controller) + (sizeof(struct stm_nand_afm_device *) * pdata->nr_banks), GFP_KERNEL); if (!afm) { dev_err(&pdev->dev, "failed to allocate afm controller data\n"); err = -ENOMEM; goto err0; } afm->dev = &pdev->dev; /* Request IO Memory */ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!resource) { dev_err(&pdev->dev, "failed to find IOMEM resource\n"); err = -ENOENT; goto err1; } afm->map_base = resource->start; afm->map_size = resource->end - resource->start + 1; if (!request_mem_region(afm->map_base, afm->map_size, pdev->name)) { dev_err(&pdev->dev, "request memory region failed [0x%08x]\n", afm->map_base); err = -EBUSY; goto err1; } /* Map base address */ afm->base = ioremap_nocache(afm->map_base, afm->map_size); if (!afm->base) { dev_err(&pdev->dev, "base ioremap failed [0x%08x]\n", afm->map_base); err = -ENXIO; goto err2; } #ifdef CONFIG_STM_NAND_AFM_CACHED /* Setup cached mapping to the AFM data FIFO */ afm->fifo_phys = (afm->map_base + EMINAND_AFM_DATA_FIFO); #ifndef CONFIG_32BIT /* 29-bit uses 'Area 7' address. [Should this be done in ioremap?] */ afm->fifo_phys &= 0x1fffffff; #endif afm->fifo_cached = ioremap_cache(afm->fifo_phys, 512); if (!afm->fifo_cached) { dev_err(&pdev->dev, "fifo ioremap failed [0x%08x]\n", afm->map_base + EMINAND_AFM_DATA_FIFO); err = -ENXIO; goto err3; } spin_lock_init(&afm->lock); #endif /* Setup IRQ handler */ resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!resource) { dev_err(&pdev->dev, "failed to find IRQ resource\n"); err = -ENOENT; goto err4; } afm->irq = resource->start; if (request_irq(afm->irq, afm_irq_handler, IRQF_DISABLED, dev_name(&pdev->dev), afm)) { dev_err(&pdev->dev, "irq request failed\n"); err = -EBUSY; goto err4; } /* Initialise 'controller' structure */ spin_lock_init(&afm->hwcontrol.lock); init_waitqueue_head(&afm->hwcontrol.wq); init_completion(&afm->rbn_completed); init_completion(&afm->seq_completed); afm->current_csn = -1; /* Stop AFM Controller, in case it's still running! */ afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); memset(afm->base + EMINAND_AFM_SEQUENCE_REG_1, 0, 32); /* Reset AFM Controller */ afm_writereg((0x1 << 3), EMINAND_FLEXMODE_CONFIG); udelay(1); afm_writereg(0x00, EMINAND_FLEXMODE_CONFIG); /* Disable boot_not_flex */ afm_writereg(0x00000000, EMINAND_BOOTBANK_CONFIG); /* Set Controller to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); /* Enable Interrupts: individual interrupts enabled when needed! */ afm_writereg(0x0000007C, EMINAND_INTERRUPT_CLEAR); afm_writereg(0x00000001, EMINAND_INTERRUPT_EDGECONFIG); afm_writereg(AFM_IRQ, EMINAND_INTERRUPT_ENABLE); /* Success :-) */ return afm; /* Error path */ err4: #ifdef CONFIG_STM_NAND_AFM_CACHED iounmap(afm->fifo_cached); err3: #endif iounmap(afm->base); err2: release_mem_region(afm->map_base, afm->map_size); err1: kfree(afm); err0: return ERR_PTR(err); } static void __devexit afm_exit_controller(struct platform_device *pdev) { struct stm_nand_afm_controller *afm = platform_get_drvdata(pdev); free_irq(afm->irq, afm); #ifdef CONFIG_STM_NAND_AFM_CACHED iounmap(afm->fifo_cached); #endif iounmap(afm->base); release_mem_region(afm->map_base, afm->map_size); kfree(afm); } #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT static void afm_setup_eccparams(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; struct stm_nand_afm_device *data = chip->priv; /* Take a copy of ECC AFM params, as set up during nand_scan() */ data->ecc_afm.ecc_ctrl = chip->ecc; data->ecc_afm.subpagesize = chip->subpagesize; data->ecc_afm.subpage_sft = mtd->subpage_sft; /* Set ECC BOOT params */ data->ecc_boot.ecc_ctrl = data->ecc_afm.ecc_ctrl; data->ecc_boot.ecc_ctrl.write_page = afm_write_page_boot; data->ecc_boot.ecc_ctrl.read_page = afm_read_page_boot; data->ecc_boot.ecc_ctrl.size = 128; data->ecc_boot.ecc_ctrl.bytes = 4; if (mtd->oobsize == 16) data->ecc_boot.ecc_ctrl.layout = &boot_oob_16; else data->ecc_boot.ecc_ctrl.layout = &boot_oob_64; data->ecc_boot.ecc_ctrl.layout->oobavail = 0; data->ecc_boot.ecc_ctrl.steps = mtd->writesize / data->ecc_boot.ecc_ctrl.size; if (data->ecc_boot.ecc_ctrl.steps * data->ecc_boot.ecc_ctrl.size != mtd->writesize) { dev_err(data->dev, "invalid ECC parameters\n"); BUG(); } data->ecc_boot.ecc_ctrl.total = data->ecc_boot.ecc_ctrl.steps * data->ecc_boot.ecc_ctrl.bytes; /* Disable subpage writes */ data->ecc_boot.subpage_sft = 0; data->ecc_boot.subpagesize = mtd->writesize; } /* Switch ECC parameters */ static void afm_set_eccparams(struct mtd_info *mtd, struct ecc_params *params) { struct nand_chip *chip = mtd->priv; chip->ecc = params->ecc_ctrl; chip->subpagesize = params->subpagesize; mtd->oobavail = params->ecc_ctrl.layout->oobavail; mtd->subpage_sft = params->subpage_sft; } static void afm_select_eccparams(struct mtd_info *mtd, loff_t offs) { struct nand_chip *chip = mtd->priv; struct stm_nand_afm_device *data = chip->priv; if (offs >= data->boot_start && offs < data->boot_end) { if (chip->ecc.layout != data->ecc_boot.ecc_ctrl.layout) { dev_dbg(data->dev, "switching to boot-mode ECC\n"); afm_set_eccparams(mtd, &data->ecc_boot); } } else { if (chip->ecc.layout != data->ecc_afm.ecc_ctrl.layout) { dev_dbg(data->dev, "switching to AFM4 ECC\n"); afm_set_eccparams(mtd, &data->ecc_afm); } } } /* Replicated from ../mtdpart.c: required here to get slave MTD offsets and * determine which ECC mode to use. */ struct mtd_part { struct mtd_info mtd; struct mtd_info *master; u_int32_t offset; int index; struct list_head list; int registered; }; #define PART(x) ((struct mtd_part *)(x)) #endif /* * Internal helper-functions for MTD Interface callbacks */ static uint8_t *afm_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; case MTD_OOB_AUTO: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { /* Read request not from offset 0 ? */ if (unlikely(roffs)) { if (roffs >= free->length) { roffs -= free->length; continue; } boffs = free->offset + roffs; bytes = min_t(size_t, len, (free->length - roffs)); roffs = 0; } else { bytes = min_t(size_t, len, free->length); boffs = free->offset; } memcpy(oob, chip->oob_poi + boffs, bytes); oob += bytes; } return oob; } default: BUG(); } return NULL; } static int afm_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; DEBUG(MTD_DEBUG_LEVEL3, "afm_do_read_oob: from = 0x%08Lx, len = %i\n", (unsigned long long)from, readlen); if (ops->mode == MTD_OOB_AUTO) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; if (unlikely(ops->ooboffs >= len)) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt to start read outside oob\n"); return -EINVAL; } /* Do not allow reads past end of device */ if (unlikely(from >= mtd->size || ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - (from >> chip->page_shift)) * len)) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt read beyond end of device\n"); return -EINVAL; } chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); /* Shift to get page */ realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; while (1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); buf = afm_transfer_oob(chip, buf, ops, len); if (!(chip->options & NAND_NO_READRDY)) { /* * Apply delay or wait for ready/busy pin. Do this * before the AUTOINCR check, so no problems arise if a * chip which does auto increment is marked as * NOAUTOINCR by the board driver. */ if (!chip->dev_ready) udelay(chip->chip_delay); else nand_wait_ready(mtd); } readlen -= len; if (!readlen) break; /* Increment page address */ realpage++; page = realpage & chip->pagemask; /* Check, if we cross a chip boundary */ if (!page) { chipnr++; chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } /* Check, if the chip supports auto page increment * or if we have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; } ops->oobretlen = ops->ooblen; return 0; } static int afm_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int chipnr, page, realpage, col, bytes, aligned; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int sndcmd = 1; int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; uint8_t *bufpoi, *oob, *buf; DEBUG(MTD_DEBUG_LEVEL3, "afm_do_read_ops: from = 0x%08Lx, len = %i\n", (unsigned long long)from, readlen); stats = mtd->ecc_stats; chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); realpage = (int)(from >> chip->page_shift); /* actual page no. */ page = realpage & chip->pagemask; /* within-chip page */ col = (int)(from & (mtd->writesize - 1)); /* col within page */ buf = ops->datbuf; /* pointer to data buf */ oob = ops->oobbuf; /* pointer to oob buf */ while (1) { /* #bytes in next transfer */ bytes = min(mtd->writesize - col, readlen); /* tranfer aligned to page? */ aligned = (bytes == mtd->writesize); /* Add test for for alignment */ if ((uint32_t)buf & 0x3) aligned = 0; /* Is the current page in the buffer ? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; afm->page = page; afm->col = 0; /* Now read the page into the buffer, without ECC if * MTD_OOB_RAW */ if (unlikely(ops->mode == MTD_OOB_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); if (ret < 0) break; /* Transfer not aligned data */ if (!aligned) { chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); } buf += bytes; /* Done page data, now look at OOB... */ if (unlikely(oob)) { /* Raw mode does data:oob:data:oob */ if (ops->mode != MTD_OOB_RAW) { int toread = min(oobreadlen, chip->ecc.layout->oobavail); if (toread) { oob = afm_transfer_oob(chip, oob, ops, toread); oobreadlen -= toread; } } else buf = afm_transfer_oob(chip, buf, ops, mtd->oobsize); } } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; } readlen -= bytes; if (!readlen) break; /* For subsequent reads align to page boundary. */ col = 0; /* Increment page address */ realpage++; page = realpage & chip->pagemask; /* Check, if we cross a chip boundary */ if (!page) { chipnr++; chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } /* Check, if the chip supports auto page increment * or if we have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; } ops->retlen = ops->len - (size_t) readlen; if (oob) ops->oobretlen = ops->ooblen - oobreadlen; if (ret) return ret; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } static int afm_check_wp(struct mtd_info *mtd) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); uint32_t status; /* Switch to Flex Mode */ afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Read status register */ afm_writereg(FLX_CMD(NAND_CMD_STATUS), EMINAND_FLEX_COMMAND_REG); status = afm_readreg(EMINAND_FLEX_DATA); /* Switch back to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); return (status & NAND_STATUS_WP) ? 0 : 1; } static uint8_t *afm_fill_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops) { size_t len = ops->ooblen; switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_RAW: memcpy(chip->oob_poi + ops->ooboffs, oob, len); return oob + len; case MTD_OOB_AUTO: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { /* Write request not from offset 0 ? */ if (unlikely(woffs)) { if (woffs >= free->length) { woffs -= free->length; continue; } boffs = free->offset + woffs; bytes = min_t(size_t, len, (free->length - woffs)); woffs = 0; } else { bytes = min_t(size_t, len, free->length); boffs = free->offset; } memcpy(chip->oob_poi + boffs, oob, bytes); oob += bytes; } return oob; } default: BUG(); } return NULL; } static int afm_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { int chipnr, page, status, len; struct nand_chip *chip = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)ops->ooblen); if (ops->mode == MTD_OOB_AUTO) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; /* Do not allow write past end of page */ if ((ops->ooboffs + ops->ooblen) > len) { DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Attempt to write past end of page\n"); return -EINVAL; } if (unlikely(ops->ooboffs >= len)) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt to start write outside oob\n"); return -EINVAL; } /* Do not allow reads past end of device */ if (unlikely(to >= mtd->size || ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt write beyond end of device\n"); return -EINVAL; } chipnr = (int)(to >> chip->chip_shift); chip->select_chip(mtd, chipnr); /* Shift to get page */ page = (int)(to >> chip->page_shift); /* Check, if it is write protected */ if (afm_check_wp(mtd)) return -EROFS; /* Invalidate the page cache, if we write to the cached page */ if (page == chip->pagebuf) chip->pagebuf = -1; memset(chip->oob_poi, 0xff, mtd->oobsize); afm_fill_oob(chip, ops->oobbuf, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); memset(chip->oob_poi, 0xff, mtd->oobsize); if (status) return status; ops->oobretlen = ops->ooblen; return 0; } static int afm_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); afm->page = page; afm->col = 0; if (unlikely(raw)) chip->ecc.write_page_raw(mtd, chip, buf); else chip->ecc.write_page(mtd, chip, buf); /* Check status information */ if (afm->status & NAND_STATUS_FAIL) return -EIO; return 0; } #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) static int afm_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int chipnr, realpage, page, blockmask, column; struct nand_chip *chip = mtd->priv; uint32_t writelen = ops->len; uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; int ret, subpage; ops->retlen = 0; if (!writelen) return 0; /* reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { dev_err(afm->dev, "attempt to write not page aligned data\n"); return -EINVAL; } column = to & (mtd->writesize - 1); subpage = column || (writelen & (mtd->writesize - 1)); if (subpage && oob) return -EINVAL; chipnr = (int)(to >> chip->chip_shift); chip->select_chip(mtd, chipnr); /* Check, if it is write protected */ if (afm_check_wp(mtd)) return -EIO; realpage = (int)(to >> chip->page_shift); page = realpage & chip->pagemask; blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; /* Invalidate the page cache, when we write to the cached page */ if (to <= (chip->pagebuf << chip->page_shift) && (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; /* If we're not given explicit OOB data, let it be 0xFF */ if (likely(!oob)) memset(chip->oob_poi, 0xff, mtd->oobsize); while (1) { int bytes = mtd->writesize; int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; /* Partial page write ? */ /* TODO: change alignment constraints for DMA transfer! */ if (unlikely(column || writelen < (mtd->writesize - 1) || ((uint32_t)wbuf & 31))) { cached = 0; bytes = min_t(int, bytes - column, (int) writelen); chip->pagebuf = -1; memset(chip->buffers->databuf, 0xff, mtd->writesize); memcpy(&chip->buffers->databuf[column], buf, bytes); wbuf = chip->buffers->databuf; } if (unlikely(oob)) oob = afm_fill_oob(chip, oob, ops); ret = chip->write_page(mtd, chip, wbuf, page, cached, (ops->mode == MTD_OOB_RAW)); if (ret) break; writelen -= bytes; if (!writelen) break; column = 0; buf += bytes; realpage++; page = realpage & chip->pagemask; /* Check, if we cross a chip boundary */ if (!page) { chipnr++; chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } } ops->retlen = ops->len - writelen; if (unlikely(oob)) ops->oobretlen = ops->ooblen; return ret; } /* * MTD Interface callbacks (replacing equivalent functions in nand_base.c) */ /* MTD Interface - erase block(s) */ static int afm_erase(struct mtd_info *mtd, struct erase_info *instr) { return nand_erase_nand(mtd, instr, 0); } /* MTD Interface - Check if block at offset is bad */ static int afm_block_isbad(struct mtd_info *mtd, loff_t offs) { struct nand_chip *chip = mtd->priv; /* Check for invalid offset */ if (offs > mtd->size) return -EINVAL; /* We should always have a memory-resident BBT */ BUG_ON(!chip->bbt); return nand_isbad_bbt(mtd, offs, 0); } /* MTD Interface - Mark block at the given offset as bad */ static int afm_block_markbad(struct mtd_info *mtd, loff_t offs) { struct nand_chip *chip = mtd->priv; uint8_t buf[16]; int block, ret; /* Is is already marked bad? */ ret = afm_block_isbad(mtd, offs); if (ret) return (ret > 0) ? 0 : ret; /* Update memory-resident BBT */ BUG_ON(!chip->bbt); block = (int)(offs >> chip->bbt_erase_shift); chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Update non-volatile marker... */ if (chip->options & NAND_USE_FLASH_BBT) { /* Update flash-resident BBT */ ret = nand_update_bbt(mtd, offs); } else { /* * Write the bad-block marker to OOB. We also need to wipe the * first 'AFM' marker (just in case it survived the preceding * failed ERASE) to prevent subsequent on-boot scans from * recognising an AFM block, instead of a marked-bad block. */ memset(buf, 0, 16); nand_get_device(chip, mtd, FL_WRITING); offs += mtd->oobsize; chip->ops.mode = MTD_OOB_PLACE; chip->ops.len = 16; chip->ops.ooblen = 16; chip->ops.datbuf = NULL; chip->ops.oobbuf = buf; chip->ops.ooboffs = chip->badblockpos & ~0x01; ret = afm_do_write_oob(mtd, offs, &chip->ops); nand_release_device(mtd); } if (ret == 0) mtd->ecc_stats.badblocks++; return ret; } /* MTD Interface - Read chunk of page data */ static int afm_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { struct nand_chip *chip = mtd->priv; int ret; /* Do not allow reads past end of device */ if ((from + len) > mtd->size) return -EINVAL; if (!len) return 0; nand_get_device(chip, mtd, FL_READING); afm_select_eccparams(mtd, from); chip->ops.len = len; chip->ops.datbuf = buf; chip->ops.oobbuf = NULL; ret = afm_do_read_ops(mtd, from, &chip->ops); *retlen = chip->ops.retlen; nand_release_device(mtd); return ret; } /* MTD Interface - read page data and/or OOB */ static int afm_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; /* Do not allow reads past end of device */ if (ops->datbuf && (from + ops->len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt read beyond end of device\n"); return -EINVAL; } nand_get_device(chip, mtd, FL_READING); afm_select_eccparams(mtd, from); switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: break; default: goto out; } if (!ops->datbuf) ret = afm_do_read_oob(mtd, from, ops); else ret = afm_do_read_ops(mtd, from, ops); out: nand_release_device(mtd); return ret; } /* MTD Interface - write page data */ static int afm_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; int ret; /* Do not allow reads past end of device */ if ((to + len) > mtd->size) return -EINVAL; if (!len) return 0; nand_get_device(chip, mtd, FL_WRITING); afm_select_eccparams(mtd, to); chip->ops.len = len; chip->ops.datbuf = (uint8_t *)buf; chip->ops.oobbuf = NULL; ret = afm_do_write_ops(mtd, to, &chip->ops); *retlen = chip->ops.retlen; nand_release_device(mtd); return ret; } /* MTD Interface - write page data and/or OOB */ static int afm_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; /* Do not allow writes past end of device */ if (ops->datbuf && (to + ops->len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt read beyond end of device\n"); return -EINVAL; } nand_get_device(chip, mtd, FL_WRITING); afm_select_eccparams(mtd, to); switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: case MTD_OOB_RAW: break; default: goto out; } if (!ops->datbuf) ret = afm_do_write_oob(mtd, to, ops); else ret = afm_do_write_ops(mtd, to, ops); out: nand_release_device(mtd); return ret; } /* MTD Interface - Sync (just wait for chip ready, then release) */ static void afm_sync(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n"); /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_SYNCING); /* Release it and go back */ nand_release_device(mtd); } /* MTD Interface - Suspend (wait for chip ready, then suspend) */ static int afm_suspend(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; return nand_get_device(chip, mtd, FL_PM_SUSPENDED); } /* MTD Interface - Resume (release device) */ static void afm_resume(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else printk(KERN_ERR "afm_resume() called for a chip which is not " "in suspended state\n"); } /* * AFM data transfer routines */ #ifdef CONFIG_STM_NAND_AFM_CACHED static void afm_read_buf_cached(struct mtd_info *mtd, uint8_t *buf, int len) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); unsigned long irq_flags; int lenaligned = len & ~(L1_CACHE_BYTES-1); int lenleft = len & (L1_CACHE_BYTES-1); while (lenaligned > 0) { spin_lock_irqsave(&(afm->lock), irq_flags); invalidate_ioremap_region(afm->fifo_phys, afm->fifo_cached, 0, L1_CACHE_BYTES); memcpy_fromio(buf, afm->fifo_cached, L1_CACHE_BYTES); spin_unlock_irqrestore(&(afm->lock), irq_flags); buf += L1_CACHE_BYTES; lenaligned -= L1_CACHE_BYTES; } #ifdef CONFIG_STM_L2_CACHE /* If L2 cache is enabled, we must ensure the cacheline is evicted prior * to non-cached accesses.. */ invalidate_ioremap_region(afm->fifo_phys, afm->fifo_cached, 0, L1_CACHE_BYTES); #endif /* Mop up any remaining bytes */ while (lenleft > 0) { *buf++ = readb(afm->base + EMINAND_AFM_DATA_FIFO); lenleft--; } } #else /* Default read buffer command */ static void afm_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); readsl(afm->base + EMINAND_AFM_DATA_FIFO, buf, len/4); } #endif /* Default write buffer command */ static void afm_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); writesl(afm->base + EMINAND_AFM_DATA_FIFO, buf, len/4); } /* * AFM low-level chip operations */ /* AFM: Block Erase */ static void afm_erase_cmd(struct mtd_info *mtd, int page) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog; struct nand_chip *chip = mtd->priv; uint32_t reg; int ret; afm->status = 0; /* Initialise Seq interrupts */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* Select AFM program */ if ((mtd->writesize == 512 && chip->chipsize > (32 << 20)) || (mtd->writesize == 2048 && chip->chipsize > (128 << 20))) /* For 'large' chips, we need an extra address cycle */ prog = &afm_prog_erase_ext; else prog = &afm_prog_erase; /* Set page address */ prog->extra_reg = page; /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Wait for sequence to finish */ ret = wait_for_completion_timeout(&afm->seq_completed, 2*HZ); if (!ret) { dev_warn(afm->dev, "sequence timeout, force exit!\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return; } /* Get status */ reg = afm_readreg(EMINAND_AFM_SEQUENCE_STATUS_REG); afm->status = NAND_STATUS_READY | ((reg & 0x60) >> 5); /* Disable interrupts */ afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); } static int afm_correct_ecc(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { /* No error */ if ((read_ecc[0] ^ calc_ecc[0]) == 0 && (read_ecc[1] ^ calc_ecc[1]) == 0 && (read_ecc[2] ^ calc_ecc[2]) == 0) return 0; /* Special test for freshly erased page */ if (read_ecc[0] == 0xff && calc_ecc[0] == 0x00 && read_ecc[1] == 0xff && calc_ecc[1] == 0x00 && read_ecc[2] == 0xff && calc_ecc[2] == 0x00) return 0; /* Use nand_ecc.c:nand_correct_data() function */ return nand_correct_data(mtd, buf, read_ecc, calc_ecc); } /* AFM: Read Page and OOB Data with ECC */ static int afm_read_page_ecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int i, j; int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_calc = chip->buffers->ecccalc; uint32_t *eccpos = chip->ecc.layout->eccpos; uint8_t *e1, *e2, t; /* Read raw page+oob data */ chip->ecc.read_page_raw(mtd, chip, buf, page); /* Recover ECC from OOB: H/W ECC + S/W LP16,17 from device */ e1 = ecc_code; for (i = 0; i < chip->ecc.total; i++) e1[i] = chip->oob_poi[eccpos[i]]; /* Generate linux-style 'ecc_code' and 'ecc_calc' */ e1 = ecc_code; e2 = ecc_calc; p = buf; for (i = 0; i < eccsteps; i++) { uint32_t ecc_afm; uint8_t lp1617; uint32_t chkcode_offs; /* Get H/W ECC */ chkcode_offs = (eccsteps == 1) ? (3 << 2) : (i << 2); ecc_afm = afm_readreg(EMINAND_AFM_ECC_CHECKCODE_REG_0 + chkcode_offs); /* Extract ecc_code and ecc_calc */ for (j = 0; j < 3; j++) { e2[j] = (unsigned char)(ecc_afm & 0xff); ecc_afm >>= 8; } /* Swap e[0] and e[1] */ t = e1[0]; e1[0] = e1[1]; e1[1] = t; t = e2[0]; e2[0] = e2[1]; e2[1] = t; /* Generate S/W LP1617 ecc_calc */ lp1617 = stm_afm_lp1617(p); /* Copy S/W LP1617 bits to standard location */ e1[2] = (e1[2] & 0xfc) | (e1[6] & 0x3); e2[2] = (e2[2] & 0xfc) | (lp1617 & 0x3); /* Move on to next ECC block */ e1 += eccbytes; e2 += eccbytes; p += eccsize; } /* Detect/Correct ECC errors */ p = buf; for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; stat = afm_correct_ecc(mtd, p, &ecc_code[i], &ecc_calc[i]); if (stat == -1) { mtd->ecc_stats.failed++; printk(KERN_CONT "step %d, page %d]\n", i / eccbytes, page); } else if (stat == 1) { printk(KERN_CONT "step %d, page = %d]\n", i / eccbytes, page); mtd->ecc_stats.corrected++; } } return 0; } /* AFM: Read Raw Page and OOB Data */ static int afm_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog; uint32_t reg; int ret; /* Select AFM program */ prog = (mtd->writesize == 512) ? &afm_prog_read_raw_sp : &afm_prog_read_raw_lp; /* Initialise RBn interrupt */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); if (mtd->writesize == 512) { /* SmallPage: Reset ECC counters */ reg = afm_readreg(EMINAND_FLEXMODE_CONFIG); reg |= (1 << 6); afm_writereg(reg, EMINAND_FLEXMODE_CONFIG); } /* Set page address */ prog->addr_reg = afm->page << 8; /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Wait for data to become available */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) { dev_err(afm->dev, "RBn timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm_disable_interrupts(afm, AFM_IRQ_RBN); return 1; } /* Read page data and OOB (SmallPage: +48 bytes dummy data) */ chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, 64); /* Disable RBn interrupts */ afm_disable_interrupts(afm, AFM_IRQ_RBN); return 0; } /* AFM: Read OOB data */ static int afm_read_oob_chip(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog; uint32_t reg; int ret; /* Select AFM program */ prog = (mtd->writesize == 512) ? &afm_prog_read_oob_sp : &afm_prog_read_oob_lp; /* Initialise RBn interrupt */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); if (mtd->writesize == 512) { /* SmallPage: Reset ECC counters and set page address */ reg = afm_readreg(EMINAND_FLEXMODE_CONFIG); reg |= (1 << 6); afm_writereg(reg, EMINAND_FLEXMODE_CONFIG); prog->addr_reg = page << 8; } else { /* LargePage: Set page address */ prog->addr_reg = (page << 8) | (2048 >> 8); } /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Wait for data to become available */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) { dev_err(afm->dev, "RBn timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm_disable_interrupts(afm, AFM_IRQ_RBN); return 1; } /* Read OOB data to chip->oob_poi buffer */ chip->read_buf(mtd, chip->oob_poi, 64); /* Disable RBn Interrupts */ afm_disable_interrupts(afm, AFM_IRQ_RBN); return 0; } /* AFM: Write Page and OOB Data, with ECC support [SmallPage] */ static void afm_write_page_ecc_sp(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog = &afm_prog_write_ecc_sp_a; uint32_t ecc_afm; uint32_t reg; int ret; afm->status = 0; /* 1. Write page data to chip's page buffer */ /* Initialise Seq interrupt */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* Reset ECC counters */ reg = afm_readreg(EMINAND_FLEXMODE_CONFIG); reg |= (1 << 6); afm_writereg(reg, EMINAND_FLEXMODE_CONFIG); /* Set page address */ prog->addr_reg = afm->page << 8; /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Write page data */ chip->write_buf(mtd, buf, mtd->writesize); /* Wait for the sequence to terminate */ ret = wait_for_completion_timeout(&afm->seq_completed, HZ/2); if (!ret) { dev_err(afm->dev, "seq timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return; } /* Disable Seq interrupt */ afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* 2. Write OOB data */ /* Populate OOB with ECC data */ ecc_afm = afm_readreg(EMINAND_AFM_ECC_CHECKCODE_REG_3); chip->oob_poi[0] = ecc_afm & 0xff; ecc_afm >>= 8; chip->oob_poi[1] = ecc_afm & 0xff; ecc_afm >>= 8; chip->oob_poi[2] = ecc_afm & 0xff; chip->oob_poi[3] = 'A'; chip->oob_poi[4] = 'F'; chip->oob_poi[5] = 'M'; chip->oob_poi[6] = stm_afm_lp1617(buf); /* Switch to FLEX mode for writing OOB */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Write OOB data */ afm_writereg(FLX_DATA_CFG_BEAT_4 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); writesl(afm->base + EMINAND_FLEX_DATA, chip->oob_poi, 4); afm_writereg(FLX_DATA_CFG_BEAT_1 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); /* Issue page program command */ afm_writereg(FLX_CMD(NAND_CMD_PAGEPROG), EMINAND_FLEX_COMMAND_REG); /* Wait for page program operation to complete */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) dev_err(afm->dev, "RBn timeout, force exit\n"); /* Get status */ afm_writereg(FLX_CMD(NAND_CMD_STATUS), EMINAND_FLEX_COMMAND_REG); afm->status = afm_readreg(EMINAND_FLEX_DATA); afm_disable_interrupts(afm, AFM_IRQ_RBN); /* 3. Switch back to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); } /* AFM: Write Page and OOB Data, with ECC support [LargePage] */ static void afm_write_page_ecc_lp(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint32_t *eccpos = chip->ecc.layout->eccpos; const uint8_t *p; struct afm_prog *prog = &afm_prog_write_ecc_lp; uint32_t reg; int ret; int i; afm->status = 0; /* Calc S/W ECC LP1617, insert into OOB area with 'AFM' signature */ p = buf; for (i = 0; i < eccsteps; i++) { chip->oob_poi[eccpos[3+i*eccbytes]] = 'A'; chip->oob_poi[eccpos[4+i*eccbytes]] = 'F'; chip->oob_poi[eccpos[5+i*eccbytes]] = 'M'; chip->oob_poi[eccpos[6+i*eccbytes]] = stm_afm_lp1617(p); p += eccsize; } /* Initialise Seq interrupt */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* Reset ECC counters */ reg = afm_readreg(EMINAND_FLEXMODE_CONFIG); reg |= (1 << 6); afm_writereg(reg, EMINAND_FLEXMODE_CONFIG); /* Set page address */ prog->addr_reg = afm->page << 8; /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Write page and oob data */ chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, 64); /* Wait for sequence to complete */ ret = wait_for_completion_timeout(&afm->seq_completed, HZ/2); if (!ret) { dev_err(afm->dev, "seq timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return; } /* Get status */ reg = afm_readreg(EMINAND_AFM_SEQUENCE_STATUS_REG); afm->status = NAND_STATUS_READY | ((reg & 0x60) >> 5); /* Disable Seq interrupt */ afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); } /* AFM: Write Raw Page and OOB Data [LargePage] */ static void afm_write_page_raw_lp(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog = &afm_prog_write_raw_lp; uint32_t reg; int ret; afm->status = 0; /* Initialise Seq Interrupts */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* Set page address */ prog->addr_reg = afm->page << 8; /* Copy program to controller, and start sequence */ memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Write page and OOB data */ chip->write_buf(mtd, buf, 2048); chip->write_buf(mtd, chip->oob_poi, 64); /* Wait for sequence to complete */ ret = wait_for_completion_timeout(&afm->seq_completed, HZ/2); if (!ret) { dev_err(afm->dev, "seq timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return; } /* Get status */ reg = afm_readreg(EMINAND_AFM_SEQUENCE_STATUS_REG); afm->status = NAND_STATUS_READY | ((reg & 0x60) >> 5); /* Disable Seq Interrupts */ afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); } /* AFM: Write Raw Page and OOB Data [SmallPage] */ static void afm_write_page_raw_sp(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog = &afm_prog_write_raw_sp_a; uint32_t reg; int ret; afm->status = 0; /* Enable sequence interrupts */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); /* 1. Write page data to chip's page buffer */ prog->addr_reg = afm->page << 8; memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); chip->write_buf(mtd, buf, mtd->writesize); ret = wait_for_completion_timeout(&afm->seq_completed, HZ/2); if (!ret) { dev_err(afm->dev, "seq timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return; } afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); reg = afm_readreg(EMINAND_AFM_SEQUENCE_STATUS_REG); if ((reg & 0x60) != 0) { dev_err(afm->dev, "error programming page data\n"); afm->status = NAND_STATUS_FAIL; return; } /* 2. Switch to FLEX mode and write OOB data */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Send OOB pointer operation */ afm_writereg(FLX_CMD(NAND_CMD_READOOB), EMINAND_FLEX_COMMAND_REG); /* Send SEQIN command */ afm_writereg(FLX_CMD(NAND_CMD_SEQIN), EMINAND_FLEX_COMMAND_REG); /* Send page address */ reg = afm->page << 8 | FLX_ADDR_REG_ADD8_VALID | FLX_ADDR_REG_CSN_STATUS; if (chip->chipsize > (32 << 20)) reg |= FLX_ADDR_REG_BEAT_4; else reg |= FLX_ADDR_REG_BEAT_3; afm_writereg(reg, EMINAND_FLEX_ADDRESS_REG); /* Send OOB data */ afm_writereg(FLX_DATA_CFG_BEAT_4 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); writesl(afm->base + EMINAND_FLEX_DATA, chip->oob_poi, 4); afm_writereg(FLX_DATA_CFG_BEAT_1 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); /* Send page program command */ afm_writereg(FLX_CMD(NAND_CMD_PAGEPROG), EMINAND_FLEX_COMMAND_REG); /* Wait for page program operation to complete */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) dev_err(afm->dev, "RBn timeout!\n"); /* Get status */ afm_writereg(FLX_CMD(NAND_CMD_STATUS), EMINAND_FLEX_COMMAND_REG); afm->status = afm_readreg(EMINAND_FLEX_DATA); afm_disable_interrupts(afm, AFM_IRQ_RBN); /* 3. Switch back to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); } /* AFM: Write OOB Data [LargePage] */ static int afm_write_oob_chip_lp(struct mtd_info *mtd, struct nand_chip *chip, int page) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct afm_prog *prog = &afm_prog_write_oob_lp; uint32_t reg; int ret; afm->status = 0; /* Enable sequence interrupts */ INIT_COMPLETION(afm->seq_completed); afm_enable_interrupts(afm, AFM_IRQ_SEQ_DREQ); prog->addr_reg = (page << 8) | (2048 >> 8); memcpy_toio(afm->base + EMINAND_AFM_SEQUENCE_REG_1, prog, 32); /* Write OOB */ chip->write_buf(mtd, chip->oob_poi, 64); /* Wait for sequence to complete */ ret = wait_for_completion_timeout(&afm->seq_completed, HZ); if (!ret) { dev_err(afm->dev, "seq timeout, force exit\n"); afm_writereg(0x00000000, EMINAND_AFM_SEQUENCE_CONFIG_REG); afm->status = NAND_STATUS_FAIL; afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return 1; } /* Get status */ reg = afm_readreg(EMINAND_AFM_SEQUENCE_STATUS_REG); afm->status = NAND_STATUS_READY | ((reg & 0x60) >> 5); /* Disable sequence interrupts */ afm_disable_interrupts(afm, AFM_IRQ_SEQ_DREQ); return afm->status & NAND_STATUS_FAIL ? -EIO : 0; } /* AFM: Write OOB Data [SmallPage] */ static int afm_write_oob_chip_sp(struct mtd_info *mtd, struct nand_chip *chip, int page) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int ret; uint32_t status; uint32_t reg; afm->status = 0; /* Initialise interrupts */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); /* Switch to Flex Mode */ afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Pointer Operation */ afm_writereg(FLX_CMD(NAND_CMD_READOOB), EMINAND_FLEX_COMMAND_REG); /* Send SEQIN command */ afm_writereg(FLX_CMD(NAND_CMD_SEQIN), EMINAND_FLEX_COMMAND_REG); /* Send Col/Page Addr */ reg = (page << 8 | FLX_ADDR_REG_RBN | FLX_ADDR_REG_ADD8_VALID | FLX_ADDR_REG_CSN_STATUS); if (chip->chipsize > (32 << 20)) /* Need extra address cycle for 'large' devices */ reg |= FLX_ADDR_REG_BEAT_4; else reg |= FLX_ADDR_REG_BEAT_3; afm_writereg(reg, EMINAND_FLEX_ADDRESS_REG); /* Write OOB data */ afm_writereg(FLX_DATA_CFG_BEAT_4 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); writesl(afm->base + EMINAND_FLEX_DATA, chip->oob_poi, 4); afm_writereg(FLX_DATA_CFG_BEAT_1 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAWRITE_CONFIG); /* Issue Page Program command */ afm_writereg(FLX_CMD(NAND_CMD_PAGEPROG), EMINAND_FLEX_COMMAND_REG); /* Wait for page program operation to complete */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) dev_err(afm->dev, "RBn timeout\n"); /* Get status */ afm_writereg(FLX_CMD(NAND_CMD_STATUS), EMINAND_FLEX_COMMAND_REG); status = afm_readreg(EMINAND_FLEX_DATA); afm->status = 0xff & status; /* Switch back to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); /* Disable RBn interrupts */ afm_disable_interrupts(afm, AFM_IRQ_RBN); return status & NAND_STATUS_FAIL ? -EIO : 0; } /* Read the device electronic signature */ static int afm_read_sig(struct mtd_info *mtd, int *maf_id, int *dev_id, uint8_t *cellinfo, uint8_t *extid) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); uint32_t ret, reg; /* Enable RBn interrupts */ INIT_COMPLETION(afm->rbn_completed); afm_enable_interrupts(afm, AFM_IRQ_RBN); /* Switch to Flex Mode */ afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Issue NAND reset */ afm_writereg(FLX_CMD(NAND_CMD_RESET), EMINAND_FLEX_COMMAND_REG); /* Wait for reset to complete */ ret = wait_for_completion_timeout(&afm->rbn_completed, HZ/2); if (!ret) dev_err(afm->dev, "RBn timeout\n"); /* Read electronic signature */ afm_writereg(FLX_CMD(NAND_CMD_READID), EMINAND_FLEX_COMMAND_REG); reg = (0x00 | FLX_ADDR_REG_BEAT_1 | FLX_ADDR_REG_RBN | FLX_ADDR_REG_CSN_STATUS); afm_writereg(reg, EMINAND_FLEX_ADDRESS_REG); afm_writereg(FLX_DATA_CFG_BEAT_4 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAREAD_CONFIG); reg = afm_readreg(EMINAND_FLEX_DATA); afm_writereg(FLX_DATA_CFG_BEAT_1 | FLX_DATA_CFG_CSN_STATUS, EMINAND_FLEX_DATAREAD_CONFIG); /* Extract manufacturer and device ID */ *maf_id = reg & 0xff; *dev_id = (reg >> 8) & 0xff; /* Newer devices have all the information in additional id bytes */ *cellinfo = (reg >> 16) & 0xff; *extid = (reg >> 24) & 0xff; /* Switch back to AFM Mode */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); /* Disable RBn interrupts */ afm_disable_interrupts(afm, AFM_IRQ_RBN); return 0; } #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* For boot-mode, we use software ECC with AFM raw read/write commands */ static int boot_calc_ecc(struct mtd_info *mtd, const unsigned char *buf, unsigned char *ecc) { stm_ecc_gen(buf, ecc, ECC_128); ecc[3] = 'B'; return 0; } static int boot_correct_ecc(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { int status; status = stm_ecc_correct(buf, read_ecc, calc_ecc, ECC_128); /* convert to MTD-compatible status */ if (status == E_NO_CHK) return 0; if (status == E_D1_CHK || status == E_C1_CHK) return 1; return -1; } static int afm_read_page_boot(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; chip->ecc.read_page_raw(mtd, chip, buf, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) boot_calc_ecc(mtd, p, &ecc_calc[i]); for (i = 0; i < chip->ecc.total; i++) ecc_code[i] = chip->oob_poi[eccpos[i]]; eccsteps = chip->ecc.steps; p = buf; for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; stat = boot_correct_ecc(mtd, p, &ecc_code[i], &ecc_calc[i]); if (stat == -1) { printk(KERN_CONT "step %d, page %d]\n", i / eccbytes, page); mtd->ecc_stats.failed++; } else if (stat == 1) { printk(KERN_CONT "step %d, page = %d]\n", i / eccbytes, page); mtd->ecc_stats.corrected += stat; } } return 0; } static void afm_write_page_boot(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; /* Software ecc calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) boot_calc_ecc(mtd, p, &ecc_calc[i]); for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; chip->ecc.write_page_raw(mtd, chip, buf); } #endif /* CONFIG_STM_NAND_AFM_BOOTMODESUPPORT */ /* AFM : Select Chip * For now we only support 1 chip per 'stm_nand_afm_device' so chipnr will be 0 * for select, -1 for deselect. */ static void afm_select_chip(struct mtd_info *mtd, int chipnr) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct nand_chip *chip = mtd->priv; struct stm_nand_afm_device *data = chip->priv; /* Deselect, do nothing */ if (chipnr == -1) { return; } else if (chipnr == 0) { /* If same chip as last time, no need to change anything */ if (data->csn == afm->current_csn) return; /* Set CSn on AFM controller */ afm->current_csn = data->csn; afm_writereg(0x1 << data->csn, EMINAND_MUXCONTROL_REG); /* Set up timing parameters */ afm_set_timings(afm, data->timing_data); } else { dev_err(afm->dev, "attempt to select chipnr = %d\n", chipnr); } return; } /* The low-level AFM chip operations wait internally, and set the status field. * All that is left to do here is return the status */ static int afm_wait(struct mtd_info *mtd, struct nand_chip *chip) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); return afm->status; } /* * afm_command() and afm_read_byte() are treated as special cases here. We need * to support nand_base.c:nand_erase_nand() because this is called directly by * nand_bbt.c (why is it not a callback?). However, nand_erase_nand() calls * nand_check_wp() which in turn calls chip->cmdfunc() and chip->read_byte() in * order to check the status register. Since nand_check_wp() is the only * function that uses these callbacks, we can implement specialised versions * such that afm_command() is empty, and afm_read_byte() queries and returns the * status register. * * Need to track updates to nand_base.c to ensure these assumptions remain valid * in the future! */ static void afm_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) { } static uint8_t afm_read_byte(struct mtd_info *mtd) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); uint32_t reg; /* Switch to Flex Mode */ afm_writereg(0x00000001, EMINAND_FLEXMODE_CONFIG); /* Write STATUS command (do not set FLX_CMD_REG_RBN!) */ reg = (NAND_CMD_STATUS | FLX_CMD_REG_BEAT_1 | FLX_CMD_REG_CSN_STATUS); afm_writereg(reg, EMINAND_FLEX_COMMAND_REG); reg = afm_readreg(EMINAND_FLEX_DATA); /* Switch back to AFM */ afm_writereg(0x00000002, EMINAND_FLEXMODE_CONFIG); return reg & 0xff; } static int afm_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { printk(KERN_ERR NAME ": %s Unsupported callback", __func__); BUG(); return 0; } static u16 afm_read_word(struct mtd_info *mtd) { printk(KERN_ERR NAME ": %s Unsupported callback", __func__); BUG(); return 0xff; } /* * AFM scan/probe NAND routines */ /* Set AFM generic call-backs (not chip-specific) */ static void afm_set_defaults(struct nand_chip *chip, int busw) { chip->chip_delay = 0; chip->cmdfunc = afm_command; chip->waitfunc = afm_wait; chip->select_chip = afm_select_chip; chip->read_byte = afm_read_byte; chip->read_word = afm_read_word; chip->block_bad = NULL; chip->block_markbad = NULL; chip->write_buf = afm_write_buf; chip->verify_buf = afm_verify_buf; chip->scan_bbt = nand_default_bbt; #ifdef CONFIG_STM_NAND_AFM_CACHED chip->read_buf = afm_read_buf_cached; #else chip->read_buf = afm_read_buf; #endif } /* Determine the NAND device paramters * [cf nand_base.c:nand_get_flash_type()] */ static struct nand_flash_dev *afm_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, int busw, int *maf_id) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct nand_flash_dev *type = NULL; int i, dev_id, maf_idx; uint8_t cellinfo; uint8_t extid; /* Select the device */ chip->select_chip(mtd, 0); /* Read the electronic signature */ afm_read_sig(mtd, maf_id, &dev_id, &cellinfo, &extid); /* Lookup device */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (dev_id == nand_flash_ids[i].id) { type = &nand_flash_ids[i]; break; } } if (!type) return ERR_PTR(-ENODEV); if (!mtd->name) mtd->name = type->name; chip->chipsize = type->chipsize << 20; if (!type->pagesize) { /* New devices use the extended chip info... */ chip->cellinfo = cellinfo; /* Calc pagesize */ mtd->writesize = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; } else { /* Old devices have chip data hardcoded in device id table */ mtd->erasesize = type->erasesize; mtd->writesize = type->pagesize; mtd->oobsize = mtd->writesize / 32; busw = type->options & NAND_BUSWIDTH_16; } afm_generic_config(afm, chip->options & NAND_BUSWIDTH_16, mtd->writesize, chip->chipsize); /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { if (nand_manuf_ids[maf_idx].id == *maf_id) break; } /* * Check, if buswidth is correct. Hardware drivers should set * chip correct ! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { dev_info(afm->dev, "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name, mtd->name); dev_info(afm->dev, "NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); return ERR_PTR(-EINVAL); } /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; /* Convert chipsize to number of pages per chip -1. */ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; chip->bbt_erase_shift = ffs(mtd->erasesize) - 1; chip->phys_erase_shift = chip->bbt_erase_shift; chip->chip_shift = ffs(chip->chipsize) - 1; /* Set the bad block position [AAC: Now obsolete?] */ chip->badblockpos = mtd->writesize > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= type->options & NAND_CHIPOPTIONS_MSK; /* * Set chip as a default. Board drivers can override it, if necessary */ chip->options |= NAND_NO_AUTOINCR; /* Check if chip is a not a samsung device. Do not clear the * options for chips which are not having an extended id. */ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; chip->erase_cmd = afm_erase_cmd; dev_info(afm->dev, "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name, type->name); return type; } /* Scan device, part 1 : Determine device paramters */ int afm_scan_ident(struct mtd_info *mtd, int maxchips) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int busw, maf_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type = NULL; if (maxchips != 1) { dev_err(afm->dev, "Only chip per MTD device allowed\n"); return 1; } busw = chip->options & NAND_BUSWIDTH_16; afm_set_defaults(chip, busw); type = afm_get_flash_type(mtd, chip, busw, &maf_id); if (IS_ERR(type)) { dev_err(afm->dev, "No NAND device found\n"); chip->select_chip(mtd, -1); return PTR_ERR(type); } /* Not dealing with multichip support just yet! */ chip->numchips = 1; mtd->size = chip->chipsize; return 0; } /* Scan device, part 2: Configure AFM according to device paramters */ static int afm_scan_tail(struct mtd_info *mtd) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); int i; struct nand_chip *chip = mtd->priv; int ret; if (!(chip->options & NAND_OWN_BUFFERS)) chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); if (!chip->buffers) return -ENOMEM; /* Set the internal oob buffer location, just after the page data */ chip->oob_poi = chip->buffers->databuf + mtd->writesize; if (mtd->writesize == 512 && mtd->oobsize == 16) { chip->ecc.layout = &afm_oob_16; chip->badblock_pattern = &bbt_scan_sp; } else if (mtd->writesize == 2048 && mtd->oobsize == 64) { chip->ecc.layout = &afm_oob_64; chip->badblock_pattern = &bbt_scan_lp; } else { dev_err(afm->dev, "Unsupported chip type " "[pagesize = %d, oobsize = %d]\n", mtd->writesize, mtd->oobsize); return 1; } #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* Handle boot-mode ECC when scanning for bad blocks */ chip->badblock_pattern->options |= NAND_BBT_SCANSTMBOOTECC; #endif /* Set ECC parameters and call-backs */ chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 512; chip->ecc.bytes = 7; chip->write_page = afm_write_page; chip->ecc.read_page = afm_read_page_ecc; chip->ecc.read_page_raw = afm_read_page_raw; chip->ecc.read_oob = afm_read_oob_chip; if (mtd->writesize == 512) { chip->ecc.write_page = afm_write_page_ecc_sp; chip->ecc.write_page_raw = afm_write_page_raw_sp; chip->ecc.write_oob = afm_write_oob_chip_sp; } else { chip->ecc.write_page = afm_write_page_ecc_lp; chip->ecc.write_page_raw = afm_write_page_raw_lp; chip->ecc.write_oob = afm_write_oob_chip_lp; } chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { dev_err(afm->dev, "Invalid ecc parameters\n"); return 1; } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; chip->ecc.calculate = NULL; /* Hard-coded in call-backs */ chip->ecc.correct = NULL; /* Count the number of OOB bytes available for client data */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length && i < MTD_MAX_OOBFREE_ENTRIES; i++) chip->ecc.layout->oobavail += chip->ecc.layout->oobfree[i].length; mtd->oobavail = chip->ecc.layout->oobavail; /* Disable subpage writes for now */ mtd->subpage_sft = 0; chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Initialize state */ chip->state = FL_READY; /* Invalidate the pagebuffer reference */ chip->pagebuf = -1; /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->erase = afm_erase; /* uses chip->erase_cmd */ mtd->point = NULL; mtd->unpoint = NULL; mtd->read = afm_read; mtd->write = afm_write; mtd->read_oob = afm_read_oob; mtd->write_oob = afm_write_oob; mtd->sync = afm_sync; mtd->lock = NULL; mtd->unlock = NULL; mtd->suspend = afm_suspend; mtd->resume = afm_resume; mtd->block_isbad = afm_block_isbad; mtd->block_markbad = afm_block_markbad; /* Propagate ecc.layout to mtd_info */ mtd->ecclayout = chip->ecc.layout; #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* Setup ECC params, for AFM and BOOT operation */ afm_setup_eccparams(mtd); #endif /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; /* Build bad block table */ ret = chip->scan_bbt(mtd); return ret; } /* Scan for the NAND device */ int afm_scan(struct mtd_info *mtd, int maxchips) { int ret; ret = afm_scan_ident(mtd, maxchips); if (!ret) ret = afm_scan_tail(mtd); return ret; } #ifdef CONFIG_STM_NAND_AFM_PBLBOOTBOUNDARY /* The NAND_BLOCK_ZERO_REMAP_REG is not implemented on current versions of the * NAND controller. We must therefore scan for the logical block 0 pattern. */ static int check_block_zero_pattern(uint8_t *buf) { uint8_t i; uint8_t *b; for (i = 0, b = buf + 128; i < 64; i++, b++) if (*b != i) return 1; return 0; } static int pbl_boot_boundary(struct mtd_info *mtd, uint32_t *_boundary) { struct stm_nand_afm_controller *afm = mtd_to_afm(mtd); struct nand_chip *chip = mtd->priv; struct stm_nand_afm_device *data = chip->priv; uint8_t *buf = chip->buffers->databuf; int block; int block_zero_phys = -1; int pages_per_block; uint32_t boundary_log = 0; uint32_t boundary_phys; /* Select boot-mode ECC */ afm_select_eccparams(mtd, data->boot_start); /* Find logical block zero */ pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); afm->col = 0; afm->page = 0; for (block = 0; block < 512; block++) { if (nand_isbad_bbt(mtd, block << chip->phys_erase_shift, 0) == 0) { afm_read_page_boot(mtd, chip, buf, afm->page); if (check_block_zero_pattern(buf) == 0) { block_zero_phys = block; boundary_log = *((uint32_t *)(buf + 0x0034)); break; } } afm->page += pages_per_block; } /* Return if we didn't find logical block zero */ if (block_zero_phys == -1) return 1; /* For bootmode_boundary, map logical offset to physical offset */ boundary_phys = block_zero_phys << chip->phys_erase_shift; while (boundary_log >= mtd->erasesize) { boundary_phys += mtd->erasesize; if (!afm_block_isbad(mtd, boundary_phys)) boundary_log -= mtd->erasesize; } boundary_phys += boundary_log; /* Add residual offset */ dev_info(afm->dev, "boot-mode boundary = 0x%08x (physical)\n", boundary_phys); *_boundary = boundary_phys; return 0; } #endif static struct stm_nand_afm_device * __init afm_init_bank(struct stm_nand_afm_controller *afm, struct stm_nand_bank_data *bank, const char *name) { struct stm_nand_afm_device *data; int err; #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT struct mtd_info *slave; struct mtd_part *part; char *boot_part_name; #ifdef CONFIG_STM_NAND_AFM_PBLBOOTBOUNDARY uint32_t boundary; #endif #endif /* Allocate memory for the driver structure (and zero it) */ data = kzalloc(sizeof(struct stm_nand_afm_device), GFP_KERNEL); if (!data) { dev_err(afm->dev, "failed to allocate device structure\n"); err = -ENOMEM; goto err1; } data->chip.priv = data; data->mtd.priv = &data->chip; data->mtd.owner = THIS_MODULE; data->dev = afm->dev; /* Use hwcontrol structure to manage access to AFM Controller */ data->chip.controller = &afm->hwcontrol; data->chip.state = FL_READY; /* Assign more sensible name (default is string from nand_ids.c!) */ data->mtd.name = name; data->csn = bank->csn; data->timing_data = bank->timing_data; data->chip.options = bank->options; data->chip.options |= NAND_NO_AUTOINCR; /* Scan to find existance of device */ if (afm_scan(&data->mtd, 1)) { dev_err(afm->dev, "device scan failed\n"); err = -ENXIO; goto err2; } #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* Set name of boot partition */ boot_part_name = nbootpart ? nbootpart : CONFIG_STM_NAND_AFM_BOOTPARTITION; dev_info(afm->dev, "using boot partition name [%s] (from %s)\n", boot_part_name, nbootpart ? "command line" : "kernel config"); #endif #ifdef CONFIG_MTD_PARTITIONS /* Try probing for MTD partitions */ data->nr_parts = parse_mtd_partitions(&data->mtd, part_probes, &data->parts, 0); /* Try platform data */ if (!data->nr_parts && bank->partitions) { data->parts = bank->partitions; data->nr_parts = bank->nr_partitions; } /* Add any partitions that were found */ if (data->nr_parts) { err = add_mtd_partitions(&data->mtd, data->parts, data->nr_parts); if (err) goto err3; #ifdef CONFIG_STM_NAND_AFM_BOOTMODESUPPORT /* Update boot-mode slave partition */ slave = get_mtd_partition_slave(&data->mtd, boot_part_name); if (slave) { dev_info(afm->dev, "found boot-mode partition " "updating ECC paramters\n"); part = PART(slave); data->boot_start = part->offset; data->boot_end = part->offset + slave->size; #ifdef CONFIG_STM_NAND_AFM_PBLBOOTBOUNDARY /* Update 'boot_end' with value in PBL image */ if (pbl_boot_boundary(&data->mtd, &boundary) != 0) { dev_info(afm->dev, "failed to get boot-mode " "boundary from PBL\n"); } else { if (boundary < data->boot_start || boundary > data->boot_end) { dev_info(afm->dev, "PBL boot-mode " "boundary lies outside " "boot partition\n"); } else { dev_info(afm->dev, "Updating boot-mode " "ECC boundary from PBL"); data->boot_end = boundary; } } #endif slave->oobavail = data->ecc_boot.ecc_ctrl.layout->oobavail; slave->subpage_sft = data->ecc_boot.subpage_sft; slave->ecclayout = data->ecc_boot.ecc_ctrl.layout; dev_info(afm->dev, "boot-mode ECC: 0x%08x->0x%08x\n", (unsigned int)data->boot_start, (unsigned int)data->boot_end); } else { dev_info(afm->dev, "failed to find boot " "partition [%s]\n", boot_part_name); } #endif } else #endif err = add_mtd_device(&data->mtd); /* Success! */ if (!err) return data; #ifdef CONFIG_MTD_PARTITIONS err3: if (data->parts && data->parts != bank->partitions) kfree(data->parts); #endif err2: kfree(data); err1: return ERR_PTR(err); } /* * stm-nand-afm device probe */ static int __init stm_afm_probe(struct platform_device *pdev) { struct stm_plat_nand_flex_data *pdata = pdev->dev.platform_data; struct stm_nand_bank_data *bank; struct stm_nand_afm_controller *afm; int n; int res; afm = afm_init_controller(pdev); if (IS_ERR(afm)) { dev_err(&pdev->dev, "failed to initialise NAND Controller.\n"); res = PTR_ERR(afm); return res; } bank = pdata->banks; for (n = 0; n < pdata->nr_banks; n++) { afm->devices[n] = afm_init_bank(afm, bank, dev_name(&pdev->dev)); bank++; } platform_set_drvdata(pdev, afm); return 0; } static int __devexit stm_afm_remove(struct platform_device *pdev) { struct stm_plat_nand_flex_data *pdata = pdev->dev.platform_data; struct stm_nand_afm_controller *afm = platform_get_drvdata(pdev); int n; for (n = 0; n < pdata->nr_banks; n++) { struct stm_nand_afm_device *data = afm->devices[n]; nand_release(&data->mtd); #ifdef CONFIG_MTD_PARTITIONS if (data->parts && data->parts != pdata->banks[n].partitions) kfree(data->parts); #endif kfree(data); } afm_exit_controller(pdev); platform_set_drvdata(pdev, NULL); return 0; } static struct platform_driver stm_afm_nand_driver = { .probe = stm_afm_probe, .remove = stm_afm_remove, .driver = { .name = NAME, .owner = THIS_MODULE, }, }; static int __init stm_afm_nand_init(void) { return platform_driver_register(&stm_afm_nand_driver); } static void __exit stm_afm_nand_exit(void) { platform_driver_unregister(&stm_afm_nand_driver); } module_init(stm_afm_nand_init); module_exit(stm_afm_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Angus Clark"); MODULE_DESCRIPTION("STM AFM-based NAND Flash driver");