Esempio n. 1
0
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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
/* 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;
}