static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { uint32_t intr_status = 0; uint64_t start; if (!is_flash_bank_valid(denali->flash_bank)) { dev_dbg(denali->dev, "No valid chip selected (%d)\n", denali->flash_bank); return 0; } start = get_time_ns(); while (!is_timeout(start, 1000 * MSECOND)) { intr_status = read_interrupt_status(denali); if (intr_status != 0) clear_interrupt(denali, intr_status); if (intr_status & irq_mask) return intr_status; } /* timeout */ dev_dbg(denali->dev, "timeout occurred, status = 0x%x, mask = 0x%x\n", intr_status, irq_mask); return 0; }
static void clear_interrupts(struct denali_nand_info *denali) { uint32_t status; status = read_interrupt_status(denali); clear_interrupt(denali, status); denali->irq_status = 0x0; }
static void clear_interrupts(struct denali_nand_info *denali) { uint32_t status = 0x0; spin_lock_irq(&denali->irq_lock); status = read_interrupt_status(denali); clear_interrupt(denali, status); denali->irq_status = 0x0; spin_unlock_irq(&denali->irq_lock); }
static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { unsigned long timeout = 1000000; uint32_t intr_status; do { intr_status = read_interrupt_status(denali) & DENALI_IRQ_ALL; if (intr_status & irq_mask) { denali->irq_status &= ~irq_mask; /* our interrupt was detected */ break; } udelay(1); timeout--; } while (timeout != 0); if (timeout == 0) { /* timeout */ printf("Denali timeout with interrupt status %08x\n", read_interrupt_status(denali)); intr_status = 0; } return intr_status; }
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, uint32_t irq_status) { bool check_erased_page = false; if (irq_status & INTR_STATUS__ECC_ERR) { uint32_t err_address = 0, err_correction_info = 0; uint32_t err_byte = 0, err_sector = 0, err_device = 0; uint32_t err_correction_value = 0; denali_set_intr_modes(denali, false); do { err_address = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS); err_sector = ECC_SECTOR(err_address); err_byte = ECC_BYTE(err_address); err_correction_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO); err_correction_value = ECC_CORRECTION_VALUE(err_correction_info); err_device = ECC_ERR_DEVICE(err_correction_info); if (ECC_ERROR_CORRECTABLE(err_correction_info)) { if (err_byte < ECC_SECTOR_SIZE) { int offset; offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * denali->devnum + err_device; buf[offset] ^= err_correction_value; denali->mtd.ecc_stats.corrected++; } } else { check_erased_page = true; } } while (!ECC_LAST_ERR(err_correction_info)); while (!(read_interrupt_status(denali) & INTR_STATUS__ECC_TRANSACTION_DONE)) cpu_relax(); clear_interrupts(denali); denali_set_intr_modes(denali, true); } return check_erased_page; }
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, uint32_t irq_status, unsigned int *max_bitflips) { bool check_erased_page = false; unsigned int bitflips = 0; if (irq_status & INTR_STATUS__ECC_ERR) { /* read the ECC errors. we'll ignore them for now */ uint32_t err_address = 0, err_correction_info = 0; uint32_t err_byte = 0, err_sector = 0, err_device = 0; uint32_t err_correction_value = 0; denali_set_intr_modes(denali, false); do { err_address = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS); err_sector = ECC_SECTOR(err_address); err_byte = ECC_BYTE(err_address); err_correction_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO); err_correction_value = ECC_CORRECTION_VALUE(err_correction_info); err_device = ECC_ERR_DEVICE(err_correction_info); if (ECC_ERROR_CORRECTABLE(err_correction_info)) { /* If err_byte is larger than ECC_SECTOR_SIZE, * means error happened in OOB, so we ignore * it. It's no need for us to correct it * err_device is represented the NAND error * bits are happened in if there are more * than one NAND connected. * */ if (err_byte < ECC_SECTOR_SIZE) { int offset; offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * denali->devnum + err_device; /* correct the ECC error */ buf[offset] ^= err_correction_value; denali->mtd.ecc_stats.corrected++; bitflips++; } } else { /* if the error is not correctable, need to * look at the page to see if it is an erased * page. if so, then it's not a real ECC error * */ check_erased_page = true; } } while (!ECC_LAST_ERR(err_correction_info)); /* Once handle all ecc errors, controller will triger * a ECC_TRANSACTION_DONE interrupt, so here just wait * for a while for this interrupt * */ while (!(read_interrupt_status(denali) & INTR_STATUS__ECC_TRANSACTION_DONE)) cpu_relax(); clear_interrupts(denali); denali_set_intr_modes(denali, true); } *max_bitflips = bitflips; return check_erased_page; }
/* This function only returns when an interrupt that this driver cares about * occurs. This is to reduce the overhead of servicing interrupts */ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) { return read_interrupt_status(denali) & DENALI_IRQ_ALL; }