diff options
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.patch | 389 |
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 + |