From nobody Tue Feb 10 02:51:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DDACCE8FDD1 for ; Wed, 4 Oct 2023 08:22:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241642AbjJDIWx (ORCPT ); Wed, 4 Oct 2023 04:22:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53106 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232743AbjJDIWt (ORCPT ); Wed, 4 Oct 2023 04:22:49 -0400 Received: from forward102a.mail.yandex.net (forward102a.mail.yandex.net [IPv6:2a02:6b8:c0e:500:1:45:d181:d102]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5B4E2A9 for ; Wed, 4 Oct 2023 01:22:42 -0700 (PDT) Received: from mail-nwsmtp-smtp-production-main-64.vla.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-64.vla.yp-c.yandex.net [IPv6:2a02:6b8:c0f:170e:0:640:d60c:0]) by forward102a.mail.yandex.net (Yandex) with ESMTP id 9B05346C79; Wed, 4 Oct 2023 11:22:36 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-64.vla.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id ZMSiN1UDWuQ0-6ZdMzIvA; Wed, 04 Oct 2023 11:22:36 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=maquefel.me; s=mail; t=1696407756; bh=NBlXq2/znwEY79YbEQPznFhggdABhgMjN7KtvmANE5g=; h=Message-Id:Date:Cc:Subject:To:From; b=YzfPvXUuO0vFJkNmGFnUGxqnbMX3bWst2lR9xnJyiIjz0+97bKcYmgRVyY7c9Pkjg SWFi1oU/DX0Lvu5hSmQpYbfBhWtjNj6fQK/pssoWmccyVavPRusmmFJ7pSgq3vb0a7 ZWuSS2r22kb6QK81K2goaepfW1BfPiIn1jOeeD04= Authentication-Results: mail-nwsmtp-smtp-production-main-64.vla.yp-c.yandex.net; dkim=pass header.i=@maquefel.me From: Nikita Shubin To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra Cc: Arnd Bergmann , Nikita Shubin , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org Subject: [RFC PATCH v2] mtd: nand: add support for ts72xx Date: Wed, 4 Oct 2023 11:22:23 +0300 Message-Id: <20231004082223.12762-1-nikita.shubin@maquefel.me> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Technologic Systems has it's own nand controller implementation in CPLD. Signed-off-by: Nikita Shubin --- Changelog v2: - dropped check for READCACHE - reordered Makefile Link: https://lore.kernel.org/linux-mtd/20230926132725.5d570e1b@xps-13/T/#m= d7e5e944a6a08e24f4f1e20068a49f94794ab945 --- drivers/mtd/nand/raw/Kconfig | 7 + drivers/mtd/nand/raw/Makefile | 1 + .../nand/raw/technologic-nand-controller.c | 220 ++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 drivers/mtd/nand/raw/technologic-nand-controller.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index b523354dfb00..16219909d4c3 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -456,6 +456,13 @@ config MTD_NAND_RENESAS Enables support for the NAND controller found on Renesas R-Car Gen3 and RZ/N1 SoC families. =20 +config MTD_NAND_TS72XX + tristate "ts72xx NAND controller" + depends on ARCH_EP93XX && HAS_IOMEM + help + Enables support for NAND controller on ts72xx SBCs. + This is a legacy driver based on gen_nand. + comment "Misc" =20 config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index d93e861d8ba7..c0c42385d1ed 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) +=3D lpc32xx_mlc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) +=3D sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) +=3D mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) +=3D socrates_nand.o +obj-$(CONFIG_MTD_NAND_TS72XX) +=3D technologic-nand-controller.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) +=3D txx9ndfmc.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) +=3D mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_VF610_NFC) +=3D vf610_nfc.o diff --git a/drivers/mtd/nand/raw/technologic-nand-controller.c b/drivers/m= td/nand/raw/technologic-nand-controller.c new file mode 100644 index 000000000000..2d163a523dcc --- /dev/null +++ b/drivers/mtd/nand/raw/technologic-nand-controller.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technologic Systems TS72xx NAND controller driver + * + * Copyright (C) 2023 Nikita Shubin + * + * Derived from: plat_nand.c + * Author: Vitaly Wool + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TS72XX_NAND_CONTROL_ADDR_LINE BIT(22) /* 0xN0400000 */ +#define TS72XX_NAND_BUSY_ADDR_LINE BIT(23) /* 0xN0800000 */ + +#define TS72XX_NAND_ALE BIT(0) +#define TS72XX_NAND_CLE BIT(1) +#define TS72XX_NAND_NCE BIT(2) + +#define TS72XX_NAND_CTRL_CLE (TS72XX_NAND_NCE | TS72XX_NAND_CLE) +#define TS72XX_NAND_CTRL_ALE (TS72XX_NAND_NCE | TS72XX_NAND_ALE) + +struct ts72xx_nand_data { + struct nand_controller controller; + struct nand_chip chip; + void __iomem *base; + void __iomem *ctrl; + void __iomem *busy; +}; + +static inline struct ts72xx_nand_data *chip_to_ts72xx(struct nand_chip *ch= ip) +{ + return container_of(chip, struct ts72xx_nand_data, chip); +} + +static int ts72xx_nand_attach_chip(struct nand_chip *chip) +{ + switch (chip->ecc.engine_type) { + case NAND_ECC_ENGINE_TYPE_SOFT: + if (chip->ecc.algo =3D=3D NAND_ECC_ALGO_UNKNOWN) + chip->ecc.algo =3D NAND_ECC_ALGO_HAMMING; + chip->ecc.algo =3D NAND_ECC_ALGO_HAMMING; + break; + case NAND_ECC_ENGINE_TYPE_ON_HOST: + return -EINVAL; + default: + break; + } + + return 0; +} + +static void ts72xx_nand_ctrl(struct nand_chip *chip, u8 value) +{ + struct ts72xx_nand_data *data =3D chip_to_ts72xx(chip); + unsigned char bits =3D ioread8(data->ctrl) & ~GENMASK(2, 0); + + iowrite8(bits | value, data->ctrl); +} + +static int ts72xx_nand_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct ts72xx_nand_data *data =3D chip_to_ts72xx(chip); + unsigned int i, timeout_us; + u32 status; + int ret; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_CLE); + iowrite8(instr->ctx.cmd.opcode, data->base); + ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE); + break; + + case NAND_OP_ADDR_INSTR: + ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_ALE); + for (i =3D 0; i < instr->ctx.addr.naddrs; i++) + iowrite8(instr->ctx.addr.addrs[i], data->base); + ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE); + break; + + case NAND_OP_DATA_IN_INSTR: + ioread8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len); + break; + + case NAND_OP_DATA_OUT_INSTR: + iowrite8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len); + break; + + case NAND_OP_WAITRDY_INSTR: + timeout_us =3D instr->ctx.waitrdy.timeout_ms * 1000; + ret =3D readb_poll_timeout(data->busy, status, status & BIT(5), 0, timeo= ut_us); + if (ret) + return ret; + + break; + } + + if (instr->delay_ns) + ndelay(instr->delay_ns); + + return 0; +} + +static int ts72xx_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + unsigned int i; + int ret; + + for (i =3D 0; i < op->ninstrs; i++) { + ret =3D ts72xx_nand_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct nand_controller_ops ts72xx_nand_ops =3D { + .attach_chip =3D ts72xx_nand_attach_chip, + .exec_op =3D ts72xx_nand_exec_op, +}; + +static int ts72xx_nand_probe(struct platform_device *pdev) +{ + struct ts72xx_nand_data *data; + struct fwnode_handle *child; + struct mtd_info *mtd; + int err; + + data =3D devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + nand_controller_init(&data->controller); + data->controller.ops =3D &ts72xx_nand_ops; + data->chip.controller =3D &data->controller; + + data->base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + data->ctrl =3D data->base + TS72XX_NAND_CONTROL_ADDR_LINE; + data->busy =3D data->base + TS72XX_NAND_BUSY_ADDR_LINE; + + child =3D fwnode_get_next_child_node(dev_fwnode(&pdev->dev), NULL); + if (!child) + return dev_err_probe(&pdev->dev, -ENXIO, + "ts72xx controller node should have exactly one child\n"); + + nand_set_flash_node(&data->chip, to_of_node(child)); + mtd =3D nand_to_mtd(&data->chip); + mtd->dev.parent =3D &pdev->dev; + platform_set_drvdata(pdev, data); + + /* + * This driver assumes that the default ECC engine should be TYPE_SOFT. + * Set ->engine_type before registering the NAND devices in order to + * provide a driver specific default value. + */ + data->chip.ecc.engine_type =3D NAND_ECC_ENGINE_TYPE_SOFT; + + /* Scan to find existence of the device */ + err =3D nand_scan(&data->chip, 1); + if (err) + goto err_handle_put; + + err =3D mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); + if (err) + goto err_clean_nand; + + return 0; + +err_clean_nand: + nand_cleanup(&data->chip); +err_handle_put: + fwnode_handle_put(child); + return err; +} + +static void ts72xx_nand_remove(struct platform_device *pdev) +{ + struct ts72xx_nand_data *data =3D platform_get_drvdata(pdev); + struct nand_chip *chip =3D &data->chip; + int ret; + + ret =3D mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); +} + +static const struct of_device_id ts72xx_id_table[] =3D { + { .compatible =3D "technologic,ts7200-nand" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ts72xx_id_table); + +static struct platform_driver ts72xx_nand_driver =3D { + .driver =3D { + .name =3D "ts72xx-nand", + .of_match_table =3D ts72xx_id_table, + }, + .probe =3D ts72xx_nand_probe, + .remove_new =3D ts72xx_nand_remove, +}; +module_platform_driver(ts72xx_nand_driver); + +MODULE_AUTHOR("Nikita Shubin "); +MODULE_DESCRIPTION("Technologic Systems TS72xx NAND controller driver"); +MODULE_LICENSE("GPL"); --=20 2.39.2