/*
* MTK NAND Flash controller driver.
* Copyright (C) 2016 MediaTek Inc.
* Authors: Xiaolei Li <xiaolei.li@mediatek.com>
* Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/mtd.h>
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "mtk_ecc.h"
/* NAND controller register definition */
#define NFI_CNFG (0x00)
#define CNFG_AHB BIT(0)
#define CNFG_READ_EN BIT(1)
#define CNFG_DMA_BURST_EN BIT(2)
#define CNFG_BYTE_RW BIT(6)
#define CNFG_HW_ECC_EN BIT(8)
#define CNFG_AUTO_FMT_EN BIT(9)
#define CNFG_OP_CUST (6 << 12)
#define NFI_PAGEFMT (0x04)
#define PAGEFMT_FDM_ECC_SHIFT (12)
#define PAGEFMT_FDM_SHIFT (8)
#define PAGEFMT_SEC_SEL_512 BIT(2)
#define PAGEFMT_512_2K (0)
#define PAGEFMT_2K_4K (1)
#define PAGEFMT_4K_8K (2)
#define PAGEFMT_8K_16K (3)
/* NFI control */
#define NFI_CON (0x08)
#define CON_FIFO_FLUSH BIT(0)
#define CON_NFI_RST BIT(1)
#define CON_BRD BIT(8) /* burst read */
#define CON_BWR BIT(9) /* burst write */
#define CON_SEC_SHIFT (12)
/* Timming control register */
#define NFI_ACCCON (0x0C)
#define NFI_INTR_EN (0x10)
#define INTR_AHB_DONE_EN BIT(6)
#define NFI_INTR_STA (0x14)
#define NFI_CMD (0x20)
#define NFI_ADDRNOB (0x30)
#define NFI_COLADDR (0x34)
#define NFI_ROWADDR (0x38)
#define NFI_STRDATA (0x40)
#define STAR_EN (1)
#define STAR_DE (0)
#define NFI_CNRNB (0x44)
#define NFI_DATAW (0x50)
#define NFI_DATAR (0x54)
#define NFI_PIO_DIRDY (0x58)
#define PIO_DI_RDY (0x01)
#define NFI_STA (0x60)
#define STA_CMD BIT(0)
#define STA_ADDR BIT(1)
#define STA_BUSY BIT(8)
#define STA_EMP_PAGE BIT(12)
#define NFI_FSM_CUSTDATA (0xe << 16)
#define NFI_FSM_MASK (0xf << 16)
#define NFI_ADDRCNTR (0x70)
#define CNTR_MASK GENMASK(16, 12)
#define ADDRCNTR_SEC_SHIFT (12)
#define ADDRCNTR_SEC(val) \
(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
#define NFI_STRADDR (0x80)
#define NFI_BYTELEN (0x84)
#define NFI_CSEL (0x90)
#define NFI_FDML(x) (0xA0 + (x) * sizeof(u32) * 2)
#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
#define NFI_FDM_MAX_SIZE (8)
#define NFI_FDM_MIN_SIZE (1)
#define NFI_MASTER_STA (0x224)
#define MASTER_STA_MASK (0x0FFF)
#define NFI_EMPTY_THRESH (0x23C)
#define MTK_NAME "mtk-nand"
#define KB(x) ((x) * 1024UL)
#define MB(x) (KB(x) * 1024UL)
#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) \
((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
struct mtk_nfc_caps {
const u8 *spare_size;
u8 num_spare_size;
u8 pageformat_spare_shift;
u8 nfi_clk_div;
};
struct mtk_nfc_bad_mark_ctl {
void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
u32 sec;
u32 pos;
};
/*
* FDM: region used to store free OOB data
*/
struct mtk_nfc_fdm {
u32 reg_size;
u32 ecc_size;
};
struct mtk_nfc_nand_chip {
struct list_head node;
struct nand_chip nand;
struct mtk_nfc_bad_mark_ctl bad_mark;
struct mtk_nfc_fdm fdm;
u32 spare_per_sector;
int nsels;
u8 sels[0];
/* nothing after this field */
};
struct mtk_nfc_clk {
struct clk *nfi_clk;
struct clk *pad_clk;
};
struct mtk_nfc {
struct nand_hw_control controller;
struct mtk_ecc_config ecc_cfg;
struct mtk_nfc_clk clk;
struct mtk_ecc *ecc;
struct device *dev;
const struct mtk_nfc_caps *caps;
void __iomem *regs;
struct completion done;
struct list_head chips;
u8 *buffer;
};
/*
* supported spare size of each IP.
* order should be the same with the spare size bitfiled defination of
* register NFI_PAGEFMT.
*/
static const u8 spare_size_mt2701[] = {
16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 63, 64
};
static const u8 spare_size_mt2712[] = {
16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
74
};
static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
{
return container_of(nand, struct mtk_nfc_nand_chip, nand);
}
static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
{
return (u8 *)p + i * chip->ecc.size;
}
static inline u8 *oob_ptr(struct nand_chip *chip, int i)
{
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
u8 *poi;
/* map the sector's FDM data to free oob:
* the beginning of the oob area stores the FDM data of bad mark sectors
*/
if (i < mtk_nand->bad_mark.sec)
poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
else if (i == mtk_nand->bad_mark.sec)
poi = chip->oob_poi;
else
poi = chip->oob_poi + i * mtk_nand-&g
|