/* 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 void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); uint32_t addr, id; uint32_t pages_per_block; uint32_t block; int i; switch (cmd) { case NAND_CMD_PAGEPROG: break; case NAND_CMD_STATUS: read_status(denali); break; case NAND_CMD_READID: reset_buf(denali); /* * sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand */ addr = MODE_11 | BANK(denali->flash_bank); index_addr(denali, addr | 0, 0x90); index_addr(denali, addr | 1, col); for (i = 0; i < 8; i++) { index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } break; case NAND_CMD_PARAM: reset_buf(denali); /* turn on R/B interrupt */ denali_set_intr_modes(denali, false); denali_irq_mask = DENALI_IRQ_ALL | INTR_STATUS__INT_ACT; clear_interrupts(denali); denali_irq_enable(denali, denali_irq_mask); denali_set_intr_modes(denali, true); addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, cmd); index_addr(denali, (uint32_t)addr | 1, col & 0xFF); /* Wait tR time... */ udelay(25); /* And then wait for R/B interrupt */ wait_for_irq(denali, INTR_STATUS__INT_ACT); /* turn off R/B interrupt now */ denali_irq_mask = DENALI_IRQ_ALL; denali_set_intr_modes(denali, false); denali_irq_enable(denali, denali_irq_mask); denali_set_intr_modes(denali, true); for (i = 0; i < 256; i++) { index_addr_read_data(denali, (uint32_t)addr | 2, &id); write_byte_to_buf(denali, id); } break; case NAND_CMD_READ0: case NAND_CMD_SEQIN: denali->page = page; break; case NAND_CMD_RESET: reset_bank(denali); break; case NAND_CMD_READOOB: /* TODO: Read OOB data */ break; case NAND_CMD_UNLOCK1: pages_per_block = mtd->erasesize / mtd->writesize; block = page / pages_per_block; addr = (uint32_t)MODE_10 | (block * pages_per_block); index_addr(denali, addr, 0x10); break; case NAND_CMD_UNLOCK2: pages_per_block = mtd->erasesize / mtd->writesize; block = (page+pages_per_block-1) / pages_per_block; addr = (uint32_t)MODE_10 | (block * pages_per_block); index_addr(denali, addr, 0x11); break; case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: addr = MODE_10 | BANK(denali->flash_bank) | page; index_addr(denali, addr, 0x1); break; default: pr_err(": unsupported command received 0x%x\n", cmd); break; } }
int __start() { printf("-- boot complete -- \r\n"); refresh = 0; old_img_addr = SRAM_BASEADDR; new_img_addr = SRAM_BASEADDR + 0x80000; clr_screen(old_img_addr); clr_screen(new_img_addr); draw_gun(0, 30); /* blinker */ set_pixel(old_img_addr, 20, 10, 1); set_pixel(old_img_addr, 20, 11, 1); set_pixel(old_img_addr, 20, 12, 1); /* another blinker */ set_pixel(old_img_addr, 30, 10, 1); set_pixel(old_img_addr, 31, 10, 1); set_pixel(old_img_addr, 32, 10, 1); /* pixel alone, will die after the first iteration */ set_pixel(old_img_addr, 32, 30, 1); /* start vga */ write_mem(VGA_BASEADDR + VGA_CFG_OFFSET, old_img_addr); /* program timer: 0x01000000 / (50MHz) = 0.33554432 seconds */ write_mem(TIMER_BASEADDR + TIMER_0_TLR_OFFSET, 0x04000000); write_mem(TIMER_BASEADDR + TIMER_0_CSR_OFFSET, TIMER_RELOAD); write_mem(TIMER_BASEADDR + TIMER_0_CSR_OFFSET, TIMER_START); /* program gpio to input */ write_mem(GPIO_BASEADDR + GPIO_TRI_OFFSET, GPIO_INPUT); while (1) { /* glider */ set_pixel(old_img_addr, 11, 10, 1); set_pixel(old_img_addr, 12, 11, 1); set_pixel(old_img_addr, 10, 12, 1); set_pixel(old_img_addr, 11, 12, 1); set_pixel(old_img_addr, 12, 12, 1); /* another glider */ set_pixel(old_img_addr, 51, 10, 1); set_pixel(old_img_addr, 50, 11, 1); set_pixel(old_img_addr, 52, 12, 1); set_pixel(old_img_addr, 51, 12, 1); set_pixel(old_img_addr, 50, 12, 1); while (1) { uint32_t d = read_mem(GPIO_BASEADDR + GPIO_DATA_OFFSET); if (TEST_BIT(d, GPIO_BTN0)) { break; } // put cpu in a lower consumption state while waiting for an int wait_for_irq(); //cpu_relax(); } } 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 = 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; }