#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
-#if defined(CONFIG_SOC_MX6)
+#if defined(CONFIG_ARCH_MX6)
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 2
#else
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0
#endif
#define MXS_NAND_METADATA_SIZE 10
-
+#define MXS_NAND_BITS_PER_ECC_LEVEL 13
#define MXS_NAND_COMMAND_BUFFER_SIZE 32
/* BCH timeout in microseconds */
#endif
struct nand_ecclayout fake_ecc_layout;
+static int chunk_data_size = MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
+static int galois_field = 13;
/*
* Cache management functions
info->desc_index = 0;
}
-static uint32_t mxs_nand_ecc_chunk_cnt(struct mtd_info *mtd)
+static uint32_t mxs_nand_ecc_chunk_cnt(uint32_t page_data_size)
{
- struct nand_chip *nand = mtd->priv;
- return mtd->writesize / nand->ecc.size;
+ return page_data_size / chunk_data_size;
}
-static inline uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength)
+static uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength)
{
- return ecc_strength * 13;
+ return ecc_strength * galois_field;
}
static uint32_t mxs_nand_aux_status_offset(void)
/* Reset the GPMI block. */
ret = mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg);
- if (ret)
+ if (ret) {
+ printf("Failed to reset GPMI block\n");
return ret;
+ }
+
+ ret = mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
+ if (ret) {
+ printf("Failed to reset BCH block\n");
+ return ret;
+ }
/*
* Choose NAND mode, set IRQ polarity, disable write protection and
static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
uint32_t page_oob_size)
{
- if (page_data_size == 2048) {
- if (page_oob_size == 64)
- return 8;
+ int ecc_strength;
- if (page_oob_size == 112)
- return 14;
- }
-
- if (page_data_size == 4096) {
- if (page_oob_size == 128)
- return 8;
-
- if (page_oob_size == 218)
- return 16;
-
- if (page_oob_size == 224)
- return 16;
- }
+ /*
+ * Determine the ECC layout with the formula:
+ * ECC bits per chunk = (total page spare data bits) /
+ * (bits per ECC level) / (chunks per page)
+ * where:
+ * total page spare data bits =
+ * (page oob size - meta data size) * (bits per byte)
+ */
+ ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
+ / (galois_field *
+ mxs_nand_ecc_chunk_cnt(page_data_size));
- return 0;
+ return round_down(ecc_strength, 2);
}
static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
uint32_t block_mark_chunk_bit_offset;
uint32_t block_mark_bit_offset;
- chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
+ chunk_data_size_in_bits = chunk_data_size * 8;
chunk_ecc_size_in_bits = mxs_nand_ecc_size_in_bits(ecc_strength);
chunk_total_size_in_bits =
return;
}
- memset(buf, 0xee, length);
-
/* Compile the DMA descriptor - a descriptor that reads data. */
d = mxs_nand_get_dma_desc(nand_info);
d->cmd.data =
length;
mxs_dma_desc_append(channel, d);
-#ifndef CONFIG_SOC_MX6Q
+
+#ifndef CONFIG_ARCH_MX6
/*
* A DMA descriptor that waits for the command to end and the chip to
* become ready.
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);
+ MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET);
d->cmd.address = 0;
mxs_dma_desc_append(channel, d);
#endif
+
+ /* Invalidate caches */
+ mxs_nand_inval_data_buf(nand_info);
+
/* Execute the DMA chain. */
ret = mxs_dma_go(channel);
if (ret) {
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) |
+ (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
(length << MXS_DMA_DESC_BYTES_OFFSET);
d->cmd.address = (dma_addr_t)nand_info->data_buf;
mxs_dma_desc_append(channel, d);
+ /* Invalidate caches */
+ mxs_nand_inval_data_buf(nand_info);
+
/* Execute the DMA chain. */
ret = mxs_dma_go(channel);
if (ret) {
/* 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); i++) {
+ for (i = 0; i < mxs_nand_ecc_chunk_cnt(mtd->writesize); i++) {
if (status[i] == 0x00)
continue;
struct mxs_nand_info *nand_info = nand->priv;
uint32_t tmp;
+ if (mtd->oobsize > MXS_NAND_CHUNK_DATA_CHUNK_SIZE) {
+ galois_field = 14;
+ chunk_data_size = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 2;
+ }
+
+ if (mtd->oobsize > chunk_data_size) {
+ printf("OOB size of chip (%u bytes) is larger than max. supported size (%u bytes)\n",
+ mtd->oobsize, chunk_data_size);
+ return -EINVAL;
+ }
+
/* Configure BCH and set NFC geometry */
- if (readl(&bch_regs->hw_bch_ctrl_reg) &
- (BCH_CTRL_SFTRST | BCH_CTRL_CLKGATE))
- /* When booting from NAND the BCH engine will already
- * be operational and obviously does not like being reset here.
- * There will be occasional read errors upon boot when this
- * reset is done.
- */
- mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
- readl(&bch_regs->hw_bch_ctrl_reg);
+ mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
debug("mtd->writesize=%d\n", mtd->writesize);
debug("mtd->oobsize=%d\n", mtd->oobsize);
debug("ecc_strength=%d\n", mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize));
/* Configure layout 0 */
- tmp = (mxs_nand_ecc_chunk_cnt(mtd) - 1)
+ tmp = (mxs_nand_ecc_chunk_cnt(mtd->writesize) - 1)
<< BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
<< BCH_FLASHLAYOUT0_ECC0_OFFSET;
- tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
- >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= chunk_data_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= (14 == galois_field ? 1 : 0) <<
+ BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout0);
tmp = (mtd->writesize + mtd->oobsize)
<< BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
<< BCH_FLASHLAYOUT1_ECCN_OFFSET;
- tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE
- >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= chunk_data_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= (14 == galois_field ? 1 : 0) <<
+ BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout1);
/* Set *all* chip selects to use layout 0 */
int ret;
int i;
- info->desc = malloc(sizeof(struct mxs_dma_desc *) *
- MXS_NAND_DMA_DESCRIPTOR_COUNT);
+ info->desc = calloc(MXS_NAND_DMA_DESCRIPTOR_COUNT,
+ sizeof(struct mxs_dma_desc *));
+
if (!info->desc) {
printf("MXS NAND: Unable to allocate DMA descriptor table\n");
ret = -ENOMEM;
* information that is used by the suspend, resume and
* remove functions
*
- * @return The function always returns 0.
+ * @return 0 for success; errno value in case of error
*/
int board_nand_init(struct nand_chip *nand)
{
struct mxs_nand_info *nand_info;
int err;
- nand_info = calloc(1, sizeof(struct mxs_nand_info));
+ nand_info = kzalloc(sizeof(struct mxs_nand_info), 0);
if (!nand_info) {
printf("MXS NAND: Failed to allocate private data\n");
return -ENOMEM;