aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch')
-rw-r--r--target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch389
1 files changed, 389 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch b/target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch
new file mode 100644
index 0000000000..b890a8d766
--- /dev/null
+++ b/target/linux/mediatek/patches-4.14/0166-mtd-nand-mtk-Support-different-MTK-NAND-flash-contro.patch
@@ -0,0 +1,389 @@
+From fd1a1eabf2473e769b5cafc704e0336d11f61961 Mon Sep 17 00:00:00 2001
+From: RogerCC Lin <rogercc.lin@mediatek.com>
+Date: Thu, 30 Nov 2017 22:10:44 +0800
+Subject: [PATCH 166/224] mtd: nand: mtk: Support different MTK NAND flash
+ controller IP
+
+MT7622 uses an MTK's earlier NAND flash controller IP which support
+different sector size, max spare size per sector and paraity bits...,
+some register's offset and definition also been changed in the NAND
+flash controller, this patch is the preparation to support MT7622
+NAND flash controller.
+
+MT7622 NFC and ECC engine are similar to MT2701's, except below
+differences:
+(1)MT7622 NFC's max sector size(ECC data size) is 512 bytes, and
+ MT2701's is 1024, and MT7622's max sector number is 8.
+(2)The parity bit of MT7622 is 13, MT2701 is 14.
+(3)MT7622 ECC supports less ECC strength, max to 16 bit ecc strength.
+(4)MT7622 supports less spare size per sector, max spare size per
+ sector is 28 bytes.
+(5)Some register's offset are different, include ECC_ENCIRQ_EN,
+ ECC_ENCIRQ_STA, ECC_DECDONE, ECC_DECIRQ_EN and ECC_DECIRQ_STA.
+(6)ENC_MODE of ECC_ENCCNFG register is moved from bit 5-6 to bit 4-5.
+
+Signed-off-by: RogerCC Lin <rogercc.lin@mediatek.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/mtd/nand/mtk_ecc.c | 100 ++++++++++++++++++++++++++++++--------------
+ drivers/mtd/nand/mtk_ecc.h | 3 +-
+ drivers/mtd/nand/mtk_nand.c | 27 ++++++++----
+ 3 files changed, 89 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
+index c51d214d169e..6610eefaa92b 100644
+--- a/drivers/mtd/nand/mtk_ecc.c
++++ b/drivers/mtd/nand/mtk_ecc.c
+@@ -34,34 +34,28 @@
+
+ #define ECC_ENCCON (0x00)
+ #define ECC_ENCCNFG (0x04)
+-#define ECC_MODE_SHIFT (5)
+ #define ECC_MS_SHIFT (16)
+ #define ECC_ENCDIADDR (0x08)
+ #define ECC_ENCIDLE (0x0C)
+-#define ECC_ENCIRQ_EN (0x80)
+-#define ECC_ENCIRQ_STA (0x84)
+ #define ECC_DECCON (0x100)
+ #define ECC_DECCNFG (0x104)
+ #define DEC_EMPTY_EN BIT(31)
+ #define DEC_CNFG_CORRECT (0x3 << 12)
+ #define ECC_DECIDLE (0x10C)
+ #define ECC_DECENUM0 (0x114)
+-#define ECC_DECDONE (0x124)
+-#define ECC_DECIRQ_EN (0x200)
+-#define ECC_DECIRQ_STA (0x204)
+
+ #define ECC_TIMEOUT (500000)
+
+ #define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+ #define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+-#define ECC_IRQ_REG(op) ((op) == ECC_ENCODE ? \
+- ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
+
+ struct mtk_ecc_caps {
+ u32 err_mask;
+ const u8 *ecc_strength;
++ const u32 *ecc_regs;
+ u8 num_ecc_strength;
+- u32 encode_parity_reg0;
++ u8 ecc_mode_shift;
++ u32 parity_bits;
+ int pg_irq_sel;
+ };
+
+@@ -89,6 +83,33 @@ static const u8 ecc_strength_mt2712[] = {
+ 40, 44, 48, 52, 56, 60, 68, 72, 80
+ };
+
++enum mtk_ecc_regs {
++ ECC_ENCPAR00,
++ ECC_ENCIRQ_EN,
++ ECC_ENCIRQ_STA,
++ ECC_DECDONE,
++ ECC_DECIRQ_EN,
++ ECC_DECIRQ_STA,
++};
++
++static int mt2701_ecc_regs[] = {
++ [ECC_ENCPAR00] = 0x10,
++ [ECC_ENCIRQ_EN] = 0x80,
++ [ECC_ENCIRQ_STA] = 0x84,
++ [ECC_DECDONE] = 0x124,
++ [ECC_DECIRQ_EN] = 0x200,
++ [ECC_DECIRQ_STA] = 0x204,
++};
++
++static int mt2712_ecc_regs[] = {
++ [ECC_ENCPAR00] = 0x300,
++ [ECC_ENCIRQ_EN] = 0x80,
++ [ECC_ENCIRQ_STA] = 0x84,
++ [ECC_DECDONE] = 0x124,
++ [ECC_DECIRQ_EN] = 0x200,
++ [ECC_DECIRQ_STA] = 0x204,
++};
++
+ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+ enum mtk_ecc_operation op)
+ {
+@@ -107,32 +128,30 @@ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+ static irqreturn_t mtk_ecc_irq(int irq, void *id)
+ {
+ struct mtk_ecc *ecc = id;
+- enum mtk_ecc_operation op;
+ u32 dec, enc;
+
+- dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
++ dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA])
++ & ECC_IRQ_EN;
+ if (dec) {
+- op = ECC_DECODE;
+- dec = readw(ecc->regs + ECC_DECDONE);
++ dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
+ if (dec & ecc->sectors) {
+ /*
+ * Clear decode IRQ status once again to ensure that
+ * there will be no extra IRQ.
+ */
+- readw(ecc->regs + ECC_DECIRQ_STA);
++ readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA]);
+ ecc->sectors = 0;
+ complete(&ecc->done);
+ } else {
+ return IRQ_HANDLED;
+ }
+ } else {
+- enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+- if (enc) {
+- op = ECC_ENCODE;
++ enc = readl(ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_STA])
++ & ECC_IRQ_EN;
++ if (enc)
+ complete(&ecc->done);
+- } else {
++ else
+ return IRQ_NONE;
+- }
+ }
+
+ return IRQ_HANDLED;
+@@ -160,7 +179,7 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+ /* configure ECC encoder (in bits) */
+ enc_sz = config->len << 3;
+
+- reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
++ reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
+ reg |= (enc_sz << ECC_MS_SHIFT);
+ writel(reg, ecc->regs + ECC_ENCCNFG);
+
+@@ -171,9 +190,9 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+ } else {
+ /* configure ECC decoder (in bits) */
+ dec_sz = (config->len << 3) +
+- config->strength * ECC_PARITY_BITS;
++ config->strength * ecc->caps->parity_bits;
+
+- reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
++ reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
+ reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
+ reg |= DEC_EMPTY_EN;
+ writel(reg, ecc->regs + ECC_DECCNFG);
+@@ -291,7 +310,12 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+ */
+ 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));
++ if (op == ECC_ENCODE)
++ writew(reg_val, ecc->regs +
++ ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
++ else
++ writew(reg_val, ecc->regs +
++ ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
+ }
+
+ writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+@@ -310,13 +334,17 @@ void mtk_ecc_disable(struct mtk_ecc *ecc)
+
+ /* disable it */
+ mtk_ecc_wait_idle(ecc, op);
+- if (op == ECC_DECODE)
++ if (op == ECC_DECODE) {
+ /*
+ * Clear decode IRQ status in case there is a timeout to wait
+ * decode IRQ.
+ */
+- readw(ecc->regs + ECC_DECIRQ_STA);
+- writew(0, ecc->regs + ECC_IRQ_REG(op));
++ readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
++ writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
++ } else {
++ writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
++ }
++
+ writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+ mutex_unlock(&ecc->lock);
+@@ -367,11 +395,11 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+ mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+
+ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+- len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
++ len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
+
+ /* write the parity bytes generated by the ECC back to temp buffer */
+ __ioread32_copy(ecc->eccdata,
+- ecc->regs + ecc->caps->encode_parity_reg0,
++ ecc->regs + ecc->caps->ecc_regs[ECC_ENCPAR00],
+ round_up(len, 4));
+
+ /* copy into possibly unaligned OOB region with actual length */
+@@ -404,19 +432,29 @@ void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
+ }
+ EXPORT_SYMBOL(mtk_ecc_adjust_strength);
+
++unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
++{
++ return ecc->caps->parity_bits;
++}
++EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
++
+ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+ .err_mask = 0x3f,
+ .ecc_strength = ecc_strength_mt2701,
++ .ecc_regs = mt2701_ecc_regs,
+ .num_ecc_strength = 20,
+- .encode_parity_reg0 = 0x10,
++ .ecc_mode_shift = 5,
++ .parity_bits = 14,
+ .pg_irq_sel = 0,
+ };
+
+ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+ .err_mask = 0x7f,
+ .ecc_strength = ecc_strength_mt2712,
++ .ecc_regs = mt2712_ecc_regs,
+ .num_ecc_strength = 23,
+- .encode_parity_reg0 = 0x300,
++ .ecc_mode_shift = 5,
++ .parity_bits = 14,
+ .pg_irq_sel = 1,
+ };
+
+@@ -452,7 +490,7 @@ static int mtk_ecc_probe(struct platform_device *pdev)
+
+ max_eccdata_size = ecc->caps->num_ecc_strength - 1;
+ max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
+- max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3;
++ max_eccdata_size = (max_eccdata_size * ecc->caps->parity_bits + 7) >> 3;
+ max_eccdata_size = round_up(max_eccdata_size, 4);
+ ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
+ if (!ecc->eccdata)
+diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/mtk_ecc.h
+index d245c14f1b80..a455df080952 100644
+--- a/drivers/mtd/nand/mtk_ecc.h
++++ b/drivers/mtd/nand/mtk_ecc.h
+@@ -14,8 +14,6 @@
+
+ #include <linux/types.h>
+
+-#define ECC_PARITY_BITS (14)
+-
+ enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+ enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+
+@@ -43,6 +41,7 @@ int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+ int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+ void mtk_ecc_disable(struct mtk_ecc *);
+ void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
++unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
+
+ struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+ void mtk_ecc_release(struct mtk_ecc *);
+diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
+index 6d0101e13ef6..7349aa846f9a 100644
+--- a/drivers/mtd/nand/mtk_nand.c
++++ b/drivers/mtd/nand/mtk_nand.c
+@@ -97,7 +97,6 @@
+
+ #define MTK_TIMEOUT (500000)
+ #define MTK_RESET_TIMEOUT (1000000)
+-#define MTK_MAX_SECTOR (16)
+ #define MTK_NAND_MAX_NSELS (2)
+ #define MTK_NFC_MIN_SPARE (16)
+ #define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
+@@ -109,6 +108,8 @@ struct mtk_nfc_caps {
+ u8 num_spare_size;
+ u8 pageformat_spare_shift;
+ u8 nfi_clk_div;
++ u8 max_sector;
++ u32 max_sector_size;
+ };
+
+ struct mtk_nfc_bad_mark_ctl {
+@@ -450,7 +451,7 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+ * set to max sector to allow the HW to continue reading over
+ * unaligned accesses
+ */
+- reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
++ reg = (nfc->caps->max_sector << CON_SEC_SHIFT) | CON_BRD;
+ nfi_writel(nfc, reg, NFI_CON);
+
+ /* trigger to fetch data */
+@@ -481,7 +482,7 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+ nfi_writew(nfc, reg, NFI_CNFG);
+
+- reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
++ reg = nfc->caps->max_sector << CON_SEC_SHIFT | CON_BWR;
+ nfi_writel(nfc, reg, NFI_CON);
+
+ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+@@ -1126,9 +1127,11 @@ static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
+ {
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
++ struct mtk_nfc *nfc = nand_get_controller_data(nand);
+ u32 ecc_bytes;
+
+- ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++ ecc_bytes = DIV_ROUND_UP(nand->ecc.strength *
++ mtk_ecc_get_parity_bits(nfc->ecc), 8);
+
+ fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+ if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+@@ -1208,7 +1211,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+ * this controller only supports 512 and 1024 sizes
+ */
+ if (nand->ecc.size < 1024) {
+- if (mtd->writesize > 512) {
++ if (mtd->writesize > 512 &&
++ nfc->caps->max_sector_size > 512) {
+ nand->ecc.size = 1024;
+ nand->ecc.strength <<= 1;
+ } else {
+@@ -1223,7 +1227,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+ return ret;
+
+ /* calculate oob bytes except ecc parity data */
+- free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
++ free = (nand->ecc.strength * mtk_ecc_get_parity_bits(nfc->ecc)
++ + 7) >> 3;
+ free = spare - free;
+
+ /*
+@@ -1233,10 +1238,12 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+ */
+ if (free > NFI_FDM_MAX_SIZE) {
+ spare -= NFI_FDM_MAX_SIZE;
+- nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++ nand->ecc.strength = (spare << 3) /
++ mtk_ecc_get_parity_bits(nfc->ecc);
+ } else if (free < 0) {
+ spare -= NFI_FDM_MIN_SIZE;
+- nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++ nand->ecc.strength = (spare << 3) /
++ mtk_ecc_get_parity_bits(nfc->ecc);
+ }
+ }
+
+@@ -1389,6 +1396,8 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
+ .num_spare_size = 16,
+ .pageformat_spare_shift = 4,
+ .nfi_clk_div = 1,
++ .max_sector = 16,
++ .max_sector_size = 1024,
+ };
+
+ static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
+@@ -1396,6 +1405,8 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
+ .num_spare_size = 19,
+ .pageformat_spare_shift = 16,
+ .nfi_clk_div = 2,
++ .max_sector = 16,
++ .max_sector_size = 1024,
+ };
+
+ static const struct of_device_id mtk_nfc_id_table[] = {
+--
+2.11.0
+