From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/mtd/nand/raw/mtk_nand.c | 287 ++++++++++++++++++++++++++++++++++----------------------
1 files changed, 174 insertions(+), 113 deletions(-)
diff --git a/kernel/drivers/mtd/nand/raw/mtk_nand.c b/kernel/drivers/mtd/nand/raw/mtk_nand.c
index bb40022..5c5c921 100644
--- a/kernel/drivers/mtd/nand/raw/mtk_nand.c
+++ b/kernel/drivers/mtd/nand/raw/mtk_nand.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* 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>
@@ -87,6 +79,10 @@
#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
#define NFI_FDM_MAX_SIZE (8)
#define NFI_FDM_MIN_SIZE (1)
+#define NFI_DEBUG_CON1 (0x220)
+#define STROBE_MASK GENMASK(4, 3)
+#define STROBE_SHIFT (3)
+#define MAX_STROBE_DLY (3)
#define NFI_MASTER_STA (0x224)
#define MASTER_STA_MASK (0x0FFF)
#define NFI_EMPTY_THRESH (0x23C)
@@ -135,7 +131,7 @@
u32 spare_per_sector;
int nsels;
- u8 sels[0];
+ u8 sels[];
/* nothing after this field */
};
@@ -158,6 +154,8 @@
struct list_head chips;
u8 *buffer;
+
+ unsigned long assigned_cs;
};
/*
@@ -389,44 +387,6 @@
return 0;
}
-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct mtk_nfc *nfc = nand_get_controller_data(nand);
- struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
-
- if (chip < 0)
- return;
-
- mtk_nfc_hw_runtime_config(mtd);
-
- nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
-}
-
-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
-{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-
- if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
- return 0;
-
- return 1;
-}
-
-static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-
- if (ctrl & NAND_ALE) {
- mtk_nfc_send_address(nfc, dat);
- } else if (ctrl & NAND_CLE) {
- mtk_nfc_hw_reset(nfc);
-
- nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
- mtk_nfc_send_command(nfc, dat);
- }
-}
-
static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
{
int rc;
@@ -438,9 +398,8 @@
dev_err(nfc->dev, "data not ready\n");
}
-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+static inline u8 mtk_nfc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
@@ -467,17 +426,17 @@
return nfi_readb(nfc, NFI_DATAR);
}
-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- buf[i] = mtk_nfc_read_byte(mtd);
+ buf[i] = mtk_nfc_read_byte(chip);
}
-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
@@ -496,21 +455,89 @@
nfi_writeb(nfc, byte, NFI_DATAW);
}
-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- mtk_nfc_write_byte(mtd, buf[i]);
+ mtk_nfc_write_byte(chip, buf[i]);
}
-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
- const struct nand_data_interface *conf)
+static int mtk_nfc_exec_instr(struct nand_chip *chip,
+ const struct nand_op_instr *instr)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
+ unsigned int i;
+ u32 status;
+
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ mtk_nfc_send_command(nfc, instr->ctx.cmd.opcode);
+ return 0;
+ case NAND_OP_ADDR_INSTR:
+ for (i = 0; i < instr->ctx.addr.naddrs; i++)
+ mtk_nfc_send_address(nfc, instr->ctx.addr.addrs[i]);
+ return 0;
+ case NAND_OP_DATA_IN_INSTR:
+ mtk_nfc_read_buf(chip, instr->ctx.data.buf.in,
+ instr->ctx.data.len);
+ return 0;
+ case NAND_OP_DATA_OUT_INSTR:
+ mtk_nfc_write_buf(chip, instr->ctx.data.buf.out,
+ instr->ctx.data.len);
+ return 0;
+ case NAND_OP_WAITRDY_INSTR:
+ return readl_poll_timeout(nfc->regs + NFI_STA, status,
+ !(status & STA_BUSY), 20,
+ instr->ctx.waitrdy.timeout_ms * 1000);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static void mtk_nfc_select_target(struct nand_chip *nand, unsigned int cs)
+{
+ struct mtk_nfc *nfc = nand_get_controller_data(nand);
+ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
+
+ mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
+
+ nfi_writel(nfc, mtk_nand->sels[cs], NFI_CSEL);
+}
+
+static int mtk_nfc_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op,
+ bool check_only)
+{
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
+ unsigned int i;
+ int ret = 0;
+
+ if (check_only)
+ return 0;
+
+ mtk_nfc_hw_reset(nfc);
+ nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
+ mtk_nfc_select_target(chip, op->cs);
+
+ for (i = 0; i < op->ninstrs; i++) {
+ ret = mtk_nfc_exec_instr(chip, &op->instrs[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int mtk_nfc_setup_interface(struct nand_chip *chip, int csline,
+ const struct nand_interface_config *conf)
+{
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0;
- u32 thold;
+ u32 temp, tsel = 0;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
@@ -547,29 +574,51 @@
twh &= 0xf;
/* Calculate real WE#/RE# hold time in nanosecond */
- thold = (twh + 1) * 1000000 / rate;
+ temp = (twh + 1) * 1000000 / rate;
/* nanosecond to picosecond */
- thold *= 1000;
+ temp *= 1000;
/*
* WE# low level time should be expaned to meet WE# pulse time
* and WE# cycle time at the same time.
*/
- if (thold < timings->tWC_min)
- twst = timings->tWC_min - thold;
+ if (temp < timings->tWC_min)
+ twst = timings->tWC_min - temp;
twst = max(timings->tWP_min, twst) / 1000;
twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
twst &= 0xf;
/*
- * RE# low level time should be expaned to meet RE# pulse time,
- * RE# access time and RE# cycle time at the same time.
+ * RE# low level time should be expaned to meet RE# pulse time
+ * and RE# cycle time at the same time.
*/
- if (thold < timings->tRC_min)
- trlt = timings->tRC_min - thold;
- trlt = max3(trlt, timings->tREA_max, timings->tRP_min) / 1000;
+ if (temp < timings->tRC_min)
+ trlt = timings->tRC_min - temp;
+ trlt = max(trlt, timings->tRP_min) / 1000;
trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
trlt &= 0xf;
+
+ /* Calculate RE# pulse time in nanosecond. */
+ temp = (trlt + 1) * 1000000 / rate;
+ /* nanosecond to picosecond */
+ temp *= 1000;
+ /*
+ * If RE# access time is bigger than RE# pulse time,
+ * delay sampling data timing.
+ */
+ if (temp < timings->tREA_max) {
+ tsel = timings->tREA_max / 1000;
+ tsel = DIV_ROUND_UP(tsel * rate, 1000000);
+ tsel -= (trlt + 1);
+ if (tsel > MAX_STROBE_DLY) {
+ trlt += tsel - MAX_STROBE_DLY;
+ tsel = MAX_STROBE_DLY;
+ }
+ }
+ temp = nfi_readl(nfc, NFI_DEBUG_CON1);
+ temp &= ~STROBE_MASK;
+ temp |= tsel << STROBE_SHIFT;
+ nfi_writel(nfc, temp, NFI_DEBUG_CON1);
/*
* ACCON: access timing control register
@@ -784,6 +833,7 @@
u32 reg;
int ret;
+ mtk_nfc_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (!raw) {
@@ -825,27 +875,27 @@
return nand_prog_page_end_op(chip);
}
-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
int oob_on, int page)
{
- return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+ return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0);
}
-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_on, int pg)
+static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_on, int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
mtk_nfc_format_page(mtd, buf);
return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
}
-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 offset,
+static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset,
u32 data_len, const u8 *buf,
int oob_on, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
int ret;
@@ -857,10 +907,9 @@
return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
}
-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_write_page_raw(chip, NULL, 1, page);
}
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 start,
@@ -902,6 +951,7 @@
u8 *buf;
int rc;
+ mtk_nfc_select_target(chip, chip->cur_cs);
start = data_offs / chip->ecc.size;
end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
@@ -986,23 +1036,25 @@
return bitflips;
}
-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 off,
+static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off,
u32 len, u8 *p, int pg)
{
- return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+ return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg,
+ 0);
}
-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *p,
- int oob_on, int pg)
+static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on,
+ int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
}
-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_on, int page)
+static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -1028,10 +1080,9 @@
return ret;
}
-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_read_page_raw(chip, NULL, 1, page);
}
static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
@@ -1202,21 +1253,23 @@
static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
{
struct nand_chip *nand = mtd_to_nand(mtd);
+ const struct nand_ecc_props *requirements =
+ nanddev_get_ecc_requirements(&nand->base);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
u32 spare;
int free, ret;
/* support only ecc hw mode */
- if (nand->ecc.mode != NAND_ECC_HW) {
- dev_err(dev, "ecc.mode not supported\n");
+ if (nand->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
+ dev_err(dev, "ecc.engine_type not supported\n");
return -EINVAL;
}
/* if optional dt settings not present */
if (!nand->ecc.size || !nand->ecc.strength) {
/* use datasheet requirements */
- nand->ecc.strength = nand->ecc_strength_ds;
- nand->ecc.size = nand->ecc_step_ds;
+ nand->ecc.strength = requirements->strength;
+ nand->ecc.size = requirements->step_size;
/*
* align eccstrength and eccsize
@@ -1306,6 +1359,8 @@
static const struct nand_controller_ops mtk_nfc_controller_ops = {
.attach_chip = mtk_nfc_attach_chip,
+ .setup_interface = mtk_nfc_setup_interface,
+ .exec_op = mtk_nfc_exec_op,
};
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
@@ -1340,6 +1395,17 @@
dev_err(dev, "reg property failure : %d\n", ret);
return ret;
}
+
+ if (tmp >= MTK_NAND_MAX_NSELS) {
+ dev_err(dev, "invalid CS: %u\n", tmp);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+ dev_err(dev, "CS %u already assigned\n", tmp);
+ return -EINVAL;
+ }
+
chip->sels[i] = tmp;
}
@@ -1349,18 +1415,10 @@
nand_set_flash_node(nand, np);
nand_set_controller_data(nand, nfc);
- nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
- nand->dev_ready = mtk_nfc_dev_ready;
- nand->select_chip = mtk_nfc_select_chip;
- nand->write_byte = mtk_nfc_write_byte;
- nand->write_buf = mtk_nfc_write_buf;
- nand->read_byte = mtk_nfc_read_byte;
- nand->read_buf = mtk_nfc_read_buf;
- nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
- nand->setup_data_interface = mtk_nfc_setup_data_interface;
+ nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ;
/* set default mode in case dt entry is missing */
- nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
@@ -1469,8 +1527,7 @@
if (!nfc)
return -ENOMEM;
- spin_lock_init(&nfc->controller.lock);
- init_waitqueue_head(&nfc->controller.wq);
+ nand_controller_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops;
@@ -1511,7 +1568,6 @@
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(dev, "no nfi irq resource\n");
ret = -EINVAL;
goto clk_disable;
}
@@ -1550,13 +1606,18 @@
static int mtk_nfc_remove(struct platform_device *pdev)
{
struct mtk_nfc *nfc = platform_get_drvdata(pdev);
- struct mtk_nfc_nand_chip *chip;
+ struct mtk_nfc_nand_chip *mtk_chip;
+ struct nand_chip *chip;
+ int ret;
while (!list_empty(&nfc->chips)) {
- chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
- node);
- nand_release(&chip->nand);
- list_del(&chip->node);
+ mtk_chip = list_first_entry(&nfc->chips,
+ struct mtk_nfc_nand_chip, node);
+ chip = &mtk_chip->nand;
+ ret = mtd_device_unregister(nand_to_mtd(chip));
+ WARN_ON(ret);
+ nand_cleanup(chip);
+ list_del(&mtk_chip->node);
}
mtk_ecc_release(nfc->ecc);
@@ -1616,6 +1677,6 @@
module_platform_driver(mtk_nfc_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
--
Gitblit v1.6.2