/* * Write a page to NAND. */ static void mxs_nand_ecc_write_page(struct mtd_info *mtd, struct nand_chip *nand, const uint8_t *buf) { struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; int ret; memcpy(nand_info->data_buf, buf, mtd->writesize); memcpy(nand_info->oob_buf, nand->oob_poi, mtd->oobsize); /* Handle block mark swapping. */ mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); /* Compile the DMA descriptor - write data. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WRITE | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA; d->cmd.pio_words[1] = 0; d->cmd.pio_words[2] = GPMI_ECCCTRL_ENABLE_ECC | GPMI_ECCCTRL_ECC_CMD_ENCODE | GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; d->cmd.pio_words[3] = mtd->writesize + mtd->oobsize; d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; flush_buffers(mtd, nand_info); mxs_dma_desc_append(channel, d); /* Flush caches */ mxs_nand_flush_data_buf(nand_info); /* Execute the DMA chain. */ ret = mxs_dma_go(channel); if (ret) { printf("%s: DMA write error\n", __func__); goto rtn; } ret = mxs_nand_wait_for_bch_complete(); if (ret) { printf("%s: BCH write timeout\n", __func__); goto rtn; } rtn: mxs_nand_return_dma_descs(nand_info); }
/* * Write data to NAND. */ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int length) { struct nand_chip *nand = mtd->priv; struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; int ret; if (length > NAND_MAX_PAGESIZE) { printf("MXS NAND: DMA buffer too big\n"); return; } if (!buf) { printf("MXS NAND: DMA buffer is NULL\n"); return; } memcpy(nand_info->data_buf, buf, length); /* Compile the DMA descriptor - a descriptor that writes data. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | (length << MXS_DMA_DESC_BYTES_OFFSET); d->cmd.address = (dma_addr_t)nand_info->data_buf; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WRITE | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA | length; mxs_dma_desc_append(channel, d); /* Flush caches */ mxs_nand_flush_data_buf(nand_info); /* Execute the DMA chain. */ ret = mxs_dma_go(channel); if (ret) printf("MXS NAND: DMA write error\n"); mxs_nand_return_dma_descs(nand_info); }
/* * Read a page from NAND. */ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, uint8_t *buf, int page) { struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; uint32_t corrected = 0, failed = 0; uint8_t *status; int i, ret; /* Compile the DMA descriptor - wait for ready. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA; mxs_dma_desc_append(channel, d); /* Compile the DMA descriptor - enable the BCH block and read. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_WAIT4END | (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_READ | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA | (mtd->writesize + mtd->oobsize); d->cmd.pio_words[1] = 0; d->cmd.pio_words[2] = GPMI_ECCCTRL_ENABLE_ECC | GPMI_ECCCTRL_ECC_CMD_DECODE | GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; d->cmd.pio_words[3] = mtd->writesize + mtd->oobsize; d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; mxs_dma_desc_append(channel, d); /* Compile the DMA descriptor - disable the BCH block. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA | (mtd->writesize + mtd->oobsize); d->cmd.pio_words[1] = 0; d->cmd.pio_words[2] = 0; mxs_dma_desc_append(channel, d); /* Compile the DMA descriptor - deassert the NAND lock and interrupt. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM; d->cmd.address = 0; mxs_dma_desc_append(channel, d); /* Execute the DMA chain. */ ret = mxs_dma_go(channel); if (ret) { printf("MXS NAND: DMA read error\n"); goto rtn; } ret = mxs_nand_wait_for_bch_complete(); if (ret) { printf("MXS NAND: BCH read timeout\n"); goto rtn; } /* Invalidate caches */ mxs_nand_inval_data_buf(nand_info); /* Read DMA completed, now do the mark swapping. */ mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); /* Loop over status bytes, accumulating ECC status. */ status = nand_info->oob_buf + mxs_nand_aux_status_offset(); for (i = 0; i < mxs_nand_ecc_chunk_cnt(mtd->writesize); i++) { if (status[i] == 0x00) continue; if (status[i] == 0xff) continue; if (status[i] == 0xfe) { failed++; continue; } corrected += status[i]; } /* Propagate ECC status to the owning MTD. */ mtd->ecc_stats.failed += failed; mtd->ecc_stats.corrected += corrected; /* * It's time to deliver the OOB bytes. See mxs_nand_ecc_read_oob() for * details about our policy for delivering the OOB. * * We fill the caller's buffer with set bits, and then copy the block * mark to the caller's buffer. Note that, if block mark swapping was * necessary, it has already been done, so we can rely on the first * byte of the auxiliary buffer to contain the block mark. */ memset(nand->oob_poi, 0xff, mtd->oobsize); nand->oob_poi[0] = nand_info->oob_buf[0]; memcpy(buf, nand_info->data_buf, mtd->writesize); rtn: mxs_nand_return_dma_descs(nand_info); return ret; }
/* * Read data from NAND. */ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) { struct nand_chip *nand = mtd->priv; struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; int ret; if (length > NAND_MAX_PAGESIZE) { printf("MXS NAND: DMA buffer too big\n"); return; } if (!buf) { printf("MXS NAND: DMA buffer is NULL\n"); return; } /* Compile the DMA descriptor - a descriptor that reads data. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | (length << MXS_DMA_DESC_BYTES_OFFSET); d->cmd.address = (dma_addr_t)nand_info->data_buf; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_READ | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA | length; mxs_dma_desc_append(channel, d); /* * A DMA descriptor that waits for the command to end and the chip to * become ready. * * I think we actually should *not* be waiting for the chip to become * ready because, after all, we don't care. I think the original code * did that and no one has re-thought it yet. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET); d->cmd.address = 0; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_DATA; mxs_dma_desc_append(channel, d); /* Execute the DMA chain. */ ret = mxs_dma_go(channel); if (ret) { printf("MXS NAND: DMA read error\n"); goto rtn; } /* Invalidate caches */ mxs_nand_inval_data_buf(nand_info); memcpy(buf, nand_info->data_buf, length); rtn: mxs_nand_return_dma_descs(nand_info); }
/* * This is the function that we install in the cmd_ctrl function pointer of the * owning struct nand_chip. The only functions in the reference implementation * that use these functions pointers are cmdfunc and select_chip. * * In this driver, we implement our own select_chip, so this function will only * be called by the reference implementation's cmdfunc. For this reason, we can * ignore the chip enable bit and concentrate only on sending bytes to the NAND * Flash. */ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) { struct nand_chip *nand = mtd->priv; struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; int ret; /* * If this condition is true, something is _VERY_ wrong in MTD * subsystem! */ if (nand_info->cmd_queue_len == MXS_NAND_COMMAND_BUFFER_SIZE) { printf("MXS NAND: Command queue too long\n"); return; } /* * Every operation begins with a command byte and a series of zero or * more address bytes. These are distinguished by either the Address * Latch Enable (ALE) or Command Latch Enable (CLE) signals being * asserted. When MTD is ready to execute the command, it will * deasert both latch enables. * * Rather than run a separate DMA operation for every single byte, we * queue them up and run a single DMA operation for the entire series * of command and data bytes. */ if (ctrl & (NAND_ALE | NAND_CLE)) { if (data != NAND_CMD_NONE) nand_info->cmd_buf[nand_info->cmd_queue_len++] = data; return; } /* * If control arrives here, MTD has deasserted both the ALE and CLE, * which means it's ready to run an operation. Check if we have any * bytes to send. */ if (nand_info->cmd_queue_len == 0) return; /* Compile the DMA descriptor -- a descriptor that sends command. */ d = mxs_nand_get_dma_desc(nand_info); d->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | (nand_info->cmd_queue_len << MXS_DMA_DESC_BYTES_OFFSET); d->cmd.address = (dma_addr_t)nand_info->cmd_buf; d->cmd.pio_words[0] = GPMI_CTRL0_COMMAND_MODE_WRITE | GPMI_CTRL0_WORD_LENGTH | (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | GPMI_CTRL0_ADDRESS_NAND_CLE | GPMI_CTRL0_ADDRESS_INCREMENT | nand_info->cmd_queue_len; mxs_dma_desc_append(channel, d); /* Flush caches */ mxs_nand_flush_cmd_buf(nand_info); /* Execute the DMA chain. */ ret = mxs_dma_go(channel); if (ret) printf("MXS NAND: Error sending command\n"); mxs_nand_return_dma_descs(nand_info); /* Reset the command queue. */ nand_info->cmd_queue_len = 0; }