|
@@ -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,
|
|
|
},
|
|
|
{},
|
|
|
};
|