diff options
Diffstat (limited to 'drivers/mtd/nand/mtk_ecc.c')
-rw-r--r-- | drivers/mtd/nand/mtk_ecc.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c index ae513038b34f..4958121cb827 100644 --- a/drivers/mtd/nand/mtk_ecc.c +++ b/drivers/mtd/nand/mtk_ecc.c @@ -28,6 +28,7 @@ #define ECC_IDLE_MASK BIT(0) #define ECC_IRQ_EN BIT(0) +#define ECC_PG_IRQ_SEL BIT(1) #define ECC_OP_ENABLE (1) #define ECC_OP_DISABLE (0) @@ -37,7 +38,6 @@ #define ECC_MS_SHIFT (16) #define ECC_ENCDIADDR (0x08) #define ECC_ENCIDLE (0x0C) -#define ECC_ENCPAR(x) (0x10 + (x) * sizeof(u32)) #define ECC_ENCIRQ_EN (0x80) #define ECC_ENCIRQ_STA (0x84) #define ECC_DECCON (0x100) @@ -61,6 +61,8 @@ struct mtk_ecc_caps { u32 err_mask; const u8 *ecc_strength; u8 num_ecc_strength; + u32 encode_parity_reg0; + int pg_irq_sel; }; struct mtk_ecc { @@ -76,12 +78,17 @@ struct mtk_ecc { u8 *eccdata; }; -/* ecc strength that mt2701 supports */ +/* ecc strength that each IP supports */ static const u8 ecc_strength_mt2701[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60 }; +static const u8 ecc_strength_mt2712[] = { + 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 60, 68, 72, 80 +}; + static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, enum mtk_ecc_operation op) { @@ -254,6 +261,7 @@ EXPORT_SYMBOL(of_mtk_ecc_get); int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) { enum mtk_ecc_operation op = config->op; + u16 reg_val; int ret; ret = mutex_lock_interruptible(&ecc->lock); @@ -271,7 +279,15 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op)); init_completion(&ecc->done); - writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op)); + reg_val = ECC_IRQ_EN; + /* + * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it + * means this chip can only generate one ecc irq during page + * read / write. If is 0, generate one ecc irq each ecc step. + */ + if ((ecc->caps->pg_irq_sel) && (config->mode == ECC_NFI_MODE)) + reg_val |= ECC_PG_IRQ_SEL; + writew(reg_val, ecc->regs + ECC_IRQ_REG(op)); return 0; } @@ -341,7 +357,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, len = (config->strength * ECC_PARITY_BITS + 7) >> 3; /* write the parity bytes generated by the ECC back to temp buffer */ - __ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4)); + __ioread32_copy(ecc->eccdata, + ecc->regs + ecc->caps->encode_parity_reg0, + round_up(len, 4)); /* copy into possibly unaligned OOB region with actual length */ memcpy(data + bytes, ecc->eccdata, len); @@ -377,12 +395,25 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = { .err_mask = 0x3f, .ecc_strength = ecc_strength_mt2701, .num_ecc_strength = 20, + .encode_parity_reg0 = 0x10, + .pg_irq_sel = 0, +}; + +static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = { + .err_mask = 0x7f, + .ecc_strength = ecc_strength_mt2712, + .num_ecc_strength = 23, + .encode_parity_reg0 = 0x300, + .pg_irq_sel = 1, }; static const struct of_device_id mtk_ecc_dt_match[] = { { .compatible = "mediatek,mt2701-ecc", .data = &mtk_ecc_caps_mt2701, + }, { + .compatible = "mediatek,mt2712-ecc", + .data = &mtk_ecc_caps_mt2712, }, {}, }; |