static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { dev_err(denali->dev, "IN %s: page %d is not equal to denali->page %d", __func__, page, denali->page); BUG(); } setup_ecc_for_xfer(denali, false, true); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); clear_interrupts(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); denali_enable_dma(denali, false); memcpy(buf, denali->buf.buf, mtd->writesize); memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize); return 0; }
/* Common DMA function */ static uint32_t denali_dma_configuration(struct denali_nand_info *denali, uint32_t ops, bool raw_xfer, uint32_t irq_mask, int oob_required) { uint32_t irq_status = 0; /* setup_ecc_for_xfer(bool ecc_en, bool transfer_spare) */ setup_ecc_for_xfer(denali, !raw_xfer, oob_required); /* clear any previous interrupt flags */ clear_interrupts(denali); /* enable the DMA */ denali_enable_dma(denali, true); /* setup the DMA */ denali_setup_dma(denali, ops); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); /* if ECC fault happen, seems we need delay before turning off DMA. * If not, the controller will go into non responsive condition */ if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) udelay(100); /* disable the DMA */ denali_enable_dma(denali, false); return irq_status; }
/* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare, int access_type, int op) { uint32_t addr, cmd, irq_status; static uint32_t page_count = 1; setup_ecc_for_xfer(denali, ecc_en, transfer_spare); clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; /* setup the acccess type */ cmd = MODE_10 | addr; index_addr(denali, cmd, access_type); /* setup the pipeline command */ index_addr(denali, cmd, 0x2000 | op | page_count); cmd = MODE_01 | addr; writel(cmd, denali->flash_mem + INDEX_CTRL_REG); if (op == DENALI_READ) { /* wait for command to be accepted */ irq_status = wait_for_irq(denali, INTR_STATUS__LOAD_COMP); if (irq_status == 0) return -EIO; } return 0; }
/* writes a page. user specifies type, and this function handles the * configuration details. */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status = 0; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; /* if it is a raw xfer, we want to disable ecc, and send * the spare area. * !raw_xfer - enable ecc * raw_xfer - transfer spare */ setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); /* copy buffer into DMA buffer */ memcpy(denali->buf.buf, buf, mtd->writesize); if (raw_xfer) { /* transfer the data to the spare area */ memcpy(denali->buf.buf + mtd->writesize, chip->oob_poi, mtd->oobsize); } dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); clear_interrupts(denali); denali_enable_dma(denali, true); denali_setup_dma(denali, DENALI_WRITE); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); denali->status = (irq_status & INTR_STATUS__PROGRAM_FAIL) ? NAND_STATUS_FAIL : PASS; } denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); return 0; }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { unsigned int max_bitflips; struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status = 0; uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR; bool check_erased_page = false; if (page != denali->page) { dev_err(denali->dev, "IN %s: page %d is not" " equal to denali->page %d, investigate!!", __func__, page, denali->page); BUG(); } setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); clear_interrupts(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); memcpy(buf, denali->buf.buf, mtd->writesize); check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); denali_enable_dma(denali, false); if (check_erased_page) { read_oob_data(&denali->mtd, chip->oob_poi, denali->page); /* check ECC failures that may have occurred on erased pages */ if (check_erased_page) { if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; if (!is_erased(buf, denali->mtd.oobsize)) denali->mtd.ecc_stats.failed++; } } return max_bitflips; }
static void write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status = 0; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); memcpy(denali->buf.buf, buf, mtd->writesize); if (raw_xfer) { memcpy(denali->buf.buf + mtd->writesize, chip->oob_poi, mtd->oobsize); } dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); clear_interrupts(denali); denali_enable_dma(denali, true); denali_setup_dma(denali, DENALI_WRITE); irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); denali->status = (irq_status & INTR_STATUS__PROGRAM_FAIL) ? NAND_STATUS_FAIL : PASS; } denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); }
/* sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare, int access_type, int op) { int status = PASS; uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, irq_mask = 0; if (op == DENALI_READ) irq_mask = INTR_STATUS__LOAD_COMP; else if (op == DENALI_WRITE) irq_mask = 0; else BUG(); setup_ecc_for_xfer(denali, ecc_en, transfer_spare); /* clear interrupts */ clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { /* read spare area */ cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_READ) { /* setup page read request for access type */ cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); /* page 33 of the NAND controller spec indicates we should not use the pipeline commands in Spare area only mode. So we don't. */ if (access_type == SPARE_ACCESS) { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else { index_addr(denali, (uint32_t)cmd, 0x2000 | op | page_count); /* wait for command to be accepted * can always use status0 bit as the * mask is identical for each * bank. */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { dev_err(denali->dev, "cmd, page, addr on timeout " "(0x%x, 0x%x, 0x%x)\n", cmd, denali->page, addr); status = FAIL; } else { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } } } return status; }
static int denali_send_pipeline_cmd(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare, int access_type, int op) { int status = PASS; uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, irq_mask = 0; if (op == DENALI_READ) irq_mask = INTR_STATUS__LOAD_COMP; else if (op == DENALI_WRITE) irq_mask = 0; else BUG(); setup_ecc_for_xfer(denali, ecc_en, transfer_spare); clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_READ) { cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); if (access_type == SPARE_ACCESS) { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else { index_addr(denali, (uint32_t)cmd, 0x2000 | op | page_count); irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { dev_err(denali->dev, "cmd, page, addr on timeout " "(0x%x, 0x%x, 0x%x)\n", cmd, denali->page, addr); status = FAIL; } else { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } } } return status; }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { unsigned int max_bitflips = 0; struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = (unsigned long)denali->buf.buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status; uint32_t irq_mask = denali->have_hw_ecc_fixup ? (INTR_STATUS__DMA_CMD_COMP) : (INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR); bool check_erased_page = false; if (page != denali->page) { dev_err(denali->dev, "IN %s: page %d is not equal to denali->page %d", __func__, page, denali->page); BUG(); } setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE); clear_interrupts(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(addr, size, DMA_FROM_DEVICE); memcpy(buf, denali->buf.buf, mtd->writesize); check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); denali_enable_dma(denali, false); if (check_erased_page) { if (denali->have_hw_ecc_fixup) { /* When we have hw ecc fixup, don't check oob. * That code below looks jacked up anyway. I mean, * look at it, wtf? */ if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; } else { read_oob_data(&denali->mtd, chip->oob_poi, denali->page); /* check ECC failures that may have occurred on * erased pages */ if (check_erased_page) { if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; if (!is_erased(buf, denali->mtd.oobsize)) denali->mtd.ecc_stats.failed++; } } } return max_bitflips; }