From patchwork Wed Sep 27 14:15:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nikita Shubin X-Patchwork-Id: 145555 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:cae8:0:b0:403:3b70:6f57 with SMTP id r8csp2852906vqu; Wed, 27 Sep 2023 12:27:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE0XRFlCLgFts4BhJD8lo57WEIx7Kv3ttJlSpWgP5kW5tJ8oAAZUHdQdmVTjA+pTJZaD0hz X-Received: by 2002:a17:902:a40e:b0:1c6:362:3553 with SMTP id p14-20020a170902a40e00b001c603623553mr3337431plq.31.1695842845275; Wed, 27 Sep 2023 12:27:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695842845; cv=none; d=google.com; s=arc-20160816; b=gNsy7R3rJF38z64ZlzbHh/mDZpRK0KyPVb9LZkPh6kXMitLb8GSM0tfKHkOeSVEaTL jr98VeRUUbiAmJeXEP32EECvdK8dj60rmOCb0yoMWZS8mrP+NGz7XZSbyx9zj4ACUMQJ y6ImTbdXXZv4/e3O8Z/kJlXR/LsV6BaG8j7jBOROsl9QG7IMlgBo2uzV2Cu16XLsjL7a 6KklqOwIu0/sae7OvdScGy+3o+DnLJPZnFKlREda5E4D3gJ333/vz1UK35vho5FLXQXn wCCf+eIS0m1wKO8WkKwcmGPDoyJMgNsK+FmB9eAIaIH/pIctjSHvGDOA5PUnZ1FwxnPU 1Y2Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=aeHwYt1SjUcVXCfZhg9GtQOuDvp3I0qbmol6N2Jju/4=; fh=B3MMBKvFG82VeLPfJuZZRHVg/KnWP1UX0q263zpNwOs=; b=Uuel72McozMe9R5X4TY/7FW2JFbLValBDSXCGPYM96ihGKEcPiE66V28R5dd8uFzKf 11AafVXg1KZdrrTnSw+NOP4DQN76PQ8rS50QD8gD/hbiFJ4WAt8vmfS66MMdKkZ9d3/Y 5ciKd88ojl7QDH8DGwXbRoDW3lBXW36vSs7GUYWYPmnccIZPJPAL0nRgrAEvfitAm/07 BJgVl0B0eUJ8zf2WCkM/bhrevPAN/HQpnkHs0PU23SQa6MKDMR1G0Sa13fo9We9c7I/j 3hwkk0/JPkK+UEHsCS5r9EyvHWewj5Hsz9AS2sqCutvQ1O2zGHMZU6/O1OMvC9jq+cs9 1CHA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@maquefel.me header.s=mail header.b=kiDNH+0j; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from pete.vger.email (pete.vger.email. [23.128.96.36]) by mx.google.com with ESMTPS id q15-20020a170902dacf00b001bbb56b34e4si17663372plx.331.2023.09.27.12.27.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Sep 2023 12:27:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) client-ip=23.128.96.36; Authentication-Results: mx.google.com; dkim=pass header.i=@maquefel.me header.s=mail header.b=kiDNH+0j; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by pete.vger.email (Postfix) with ESMTP id 02FAD807C85B; Wed, 27 Sep 2023 07:16:52 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at pete.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232079AbjI0OP7 (ORCPT + 21 others); Wed, 27 Sep 2023 10:15:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232001AbjI0OP5 (ORCPT ); Wed, 27 Sep 2023 10:15:57 -0400 Received: from forward101a.mail.yandex.net (forward101a.mail.yandex.net [IPv6:2a02:6b8:c0e:500:1:45:d181:d101]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FD92FC for ; Wed, 27 Sep 2023 07:15:54 -0700 (PDT) Received: from mail-nwsmtp-smtp-production-main-67.vla.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-67.vla.yp-c.yandex.net [IPv6:2a02:6b8:c15:2c95:0:640:f90:0]) by forward101a.mail.yandex.net (Yandex) with ESMTP id 1677F46C7C; Wed, 27 Sep 2023 17:15:50 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-67.vla.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id lFRTMEYDS8c0-8GpxeEjA; Wed, 27 Sep 2023 17:15:49 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=maquefel.me; s=mail; t=1695824149; bh=aeHwYt1SjUcVXCfZhg9GtQOuDvp3I0qbmol6N2Jju/4=; h=Message-Id:Date:Cc:Subject:To:From; b=kiDNH+0jb3SdCJXBARwVakGwEXYev9s5zSg9zdv5gVt+XaSpVmAiwxHwUVIwfjJGX xwWQQM02Perwn0QnMY9BOGJOdla8DGtBFgFHMhHGAjkqMpHo5xD8mvCnt6hv7djo0F te+XVMLod4JJ0C1C9o75njM80kUDfEwl5cN2tiuo= Authentication-Results: mail-nwsmtp-smtp-production-main-67.vla.yp-c.yandex.net; dkim=pass header.i=@maquefel.me From: Nikita Shubin To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Arnd Bergmann , Linus Walleij , Jean Delvare , Nikita Shubin , Neil Armstrong , Christophe Kerello , Chris Packham , Johan Jonker Cc: Daniel Lezcano , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org Subject: [RFC PATCH] mtd: nand: add support for ts72xx Date: Wed, 27 Sep 2023 17:15:25 +0300 Message-Id: <20230927141532.25525-1-nikita.shubin@maquefel.me> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on pete.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (pete.vger.email [0.0.0.0]); Wed, 27 Sep 2023 07:16:52 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1778220107482682747 X-GMAIL-MSGID: 1778220107482682747 Technologic Systems has it's own nand controller implementation in CPLD. Signed-off-by: Nikita Shubin --- Hello Miquèl. Can you please take a look on it as RFC, so no need for the whole series spinning ? I've got rid of all legacy stuff i think, however: - look's like i me ts7250 is missing READCACHE and i couldn't find any docs for this controller, so as legacy had no READCACHE, i mark it as non-supported - legacy wait implementation had no delays - only timeout and if i set readb_poll_timeout() to something reasonable i experience speed degradation on mtd_speedtest, can it be left as 0 ? --- drivers/mtd/nand/raw/Kconfig | 7 + drivers/mtd/nand/raw/Makefile | 1 + .../nand/raw/technologic-nand-controller.c | 233 ++++++++++++++++++ 3 files changed, 241 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 cbf8ae85e1ae..3937c10dea1c 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -449,6 +449,13 @@ config MTD_NAND_RENESAS Enables support for the NAND controller found on Renesas R-Car Gen3 and RZ/N1 SoC families. +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" config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 25120a4afada..44d8f5b7cfd2 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -23,6 +23,7 @@ omap2_nand-objs := omap2.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o +obj-$(CONFIG_MTD_NAND_TS72XX) += technologic-nand-controller.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o diff --git a/drivers/mtd/nand/raw/technologic-nand-controller.c b/drivers/mtd/nand/raw/technologic-nand-controller.c new file mode 100644 index 000000000000..4751955f26ee --- /dev/null +++ b/drivers/mtd/nand/raw/technologic-nand-controller.c @@ -0,0 +1,233 @@ +// 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 *chip) +{ + 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 == NAND_ECC_ALGO_UNKNOWN) + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + chip->ecc.algo = 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 = chip_to_ts72xx(chip); + unsigned char bits = 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 = 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 = 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 = instr->ctx.waitrdy.timeout_ms * 1000; + ret = readb_poll_timeout(data->busy, status, status & BIT(5), 0, timeout_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) +{ + const struct nand_op_instr *instr = NULL; + unsigned int i, op_id; + int ret; + + if (check_only) { + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + if (instr->type == NAND_OP_CMD_INSTR && + (instr->ctx.cmd.opcode == NAND_CMD_READCACHEEND || + instr->ctx.cmd.opcode == NAND_CMD_READCACHESEQ)) + return -EOPNOTSUPP; + } + + return 0; + } + + for (i = 0; i < op->ninstrs; i++) { + ret = ts72xx_nand_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct nand_controller_ops ts72xx_nand_ops = { + .attach_chip = ts72xx_nand_attach_chip, + .exec_op = 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 = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + nand_controller_init(&data->controller); + data->controller.ops = &ts72xx_nand_ops; + data->chip.controller = &data->controller; + + data->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + data->ctrl = data->base + TS72XX_NAND_CONTROL_ADDR_LINE; + data->busy = data->base + TS72XX_NAND_BUSY_ADDR_LINE; + + child = 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 = nand_to_mtd(&data->chip); + mtd->dev.parent = &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 = NAND_ECC_ENGINE_TYPE_SOFT; + + /* Scan to find existence of the device */ + err = nand_scan(&data->chip, 1); + if (err) + goto err_handle_put; + + err = 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 = platform_get_drvdata(pdev); + struct nand_chip *chip = &data->chip; + int ret; + + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); +} + +static const struct of_device_id ts72xx_id_table[] = { + { .compatible = "technologic,ts7200-nand" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ts72xx_id_table); + +static struct platform_driver ts72xx_nand_driver = { + .driver = { + .name = "ts72xx-nand", + .of_match_table = ts72xx_id_table, + }, + .probe = ts72xx_nand_probe, + .remove_new = ts72xx_nand_remove, +}; +module_platform_driver(ts72xx_nand_driver); + +MODULE_AUTHOR("Nikita Shubin