From patchwork Thu Mar 28 10:18:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874679 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 41DB113B5 for ; Thu, 28 Mar 2019 09:59:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2BF7A2882E for ; Thu, 28 Mar 2019 09:59:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1FD4D28BD3; Thu, 28 Mar 2019 09:59:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C33AF2882E for ; Thu, 28 Mar 2019 09:59:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726367AbfC1J7A (ORCPT ); Thu, 28 Mar 2019 05:59:00 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50396 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725875AbfC1J7A (ORCPT ); Thu, 28 Mar 2019 05:59:00 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJK052359; Thu, 28 Mar 2019 17:58:49 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 1/7] mfd: Add Macronix MX25F0A MFD controller driver Date: Thu, 28 Mar 2019 18:18:32 +0800 Message-Id: <1553768318-23149-2-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJK052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a driver for Macronix MX25F0A multifunction device controller. Signed-off-by: Mason Yang --- drivers/mfd/Kconfig | 9 ++ drivers/mfd/Makefile | 1 + drivers/mfd/mxic-mx25f0a.c | 90 ++++++++++++++++++++ include/linux/mfd/mxic-mx25f0a.h | 173 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 drivers/mfd/mxic-mx25f0a.c create mode 100644 include/linux/mfd/mxic-mx25f0a.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0ce2d8d..68aaf2a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -823,6 +823,15 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MXIC_MX25F0A + tristate "Macronix mx25f0a multifunction device support" + select MFD_CORE + help + This supports for Macronix mx25f0a multifunction device controller + for raw nand or spi. You have to select individual components like + raw nand controller or spi host controller under the corresponding + menus. + config MFD_MT6397 tristate "MediaTek MT6397 PMIC Support" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b4569ed7..dcfe8fd 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -163,6 +163,7 @@ max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o +obj-$(CONFIG_MFD_MXIC_MX25F0A) += mxic-mx25f0a.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o diff --git a/drivers/mfd/mxic-mx25f0a.c b/drivers/mfd/mxic-mx25f0a.c new file mode 100644 index 0000000..04b1173 --- /dev/null +++ b/drivers/mfd/mxic-mx25f0a.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Macronix International Co., Ltd. +// +// Author: +// Mason Yang +// + +#include +#include + +static const struct mfd_cell mx25f0a_nand_ctlr = { + .name = "mxic-nand-ctlr", + .of_compatible = "mxicy,mx25f0a-nand-ctlr", +}; + +static const struct mfd_cell mx25f0a_spi_ctlr = { + .name = "mxic-spi", + .of_compatible = "mxicy,mx25f0a-spi", +}; + +static int mx25f0a_mfd_probe(struct platform_device *pdev) +{ + struct device_node *ctlr; + const struct mfd_cell *cell; + struct mx25f0a_mfd *mxic; + struct resource *res; + int ret; + + ctlr = of_get_next_child(pdev->dev.of_node, NULL); + if (!ctlr) { + dev_warn(&pdev->dev, "no spi/nand ctlr node found\n"); + return -ENODEV; + } + + ret = of_device_is_compatible(ctlr, "mxicy,mx25f0a-nand-ctlr"); + if (ret) { + cell = &mx25f0a_nand_ctlr; + } else { + ret = of_device_is_compatible(ctlr, "mxicy,mx25f0a-spi"); + if (ret) { + cell = &mx25f0a_spi_ctlr; + } else { + dev_warn(&pdev->dev, "no any spi/nand device found\n"); + return -ENODEV; + } + } + + mxic = devm_kzalloc(&pdev->dev, sizeof(*mxic), GFP_KERNEL); + if (!mxic) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + mxic->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mxic->base)) + return PTR_ERR(mxic->base); + + if (cell == &mx25f0a_spi_ctlr) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "dirmap"); + mxic->dirmap = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mxic->dirmap)) + mxic->dirmap = NULL; + } + + platform_set_drvdata(pdev, mxic); + + ret = devm_mfd_add_devices(&pdev->dev, -1, cell, 1, NULL, 0, NULL); + + return ret; +} + +static const struct of_device_id mx25f0a_mfd_of_match[] = { + { .compatible = "mxic,mx25f0a-mfd", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mx25f0a_mfd_of_match); + +static struct platform_driver mx25f0a_mfd_driver = { + .probe = mx25f0a_mfd_probe, + .driver = { + .name = "mx25f0a-mfd", + .of_match_table = mx25f0a_mfd_of_match, + }, +}; +module_platform_driver(mx25f0a_mfd_driver); + +MODULE_AUTHOR("Mason Yang "); +MODULE_DESCRIPTION("MX25F0A controller MFD driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/mxic-mx25f0a.h b/include/linux/mfd/mxic-mx25f0a.h new file mode 100644 index 0000000..5a8cfc7 --- /dev/null +++ b/include/linux/mfd/mxic-mx25f0a.h @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Macronix International Co., Ltd. +// +// Author: +// Mason Yang +// + +#ifndef __MFD_MXIC_MX25F0A_H +#define __MFD_MXIC_MX25F0A_H + +#include +#include +#include +#include +#include +#include + +#define HC_CFG 0x0 +#define HC_CFG_IF_CFG(x) ((x) << 27) +#define HC_CFG_DUAL_SLAVE BIT(31) +#define HC_CFG_INDIVIDUAL BIT(30) +#define HC_CFG_NIO(x) (((x) / 4) << 27) +#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2))) +#define HC_CFG_TYPE_SPI_NOR 0 +#define HC_CFG_TYPE_SPI_NAND 1 +#define HC_CFG_TYPE_SPI_RAM 2 +#define HC_CFG_TYPE_RAW_NAND 3 +#define HC_CFG_SLV_ACT(x) ((x) << 21) +#define HC_CFG_CLK_PH_EN BIT(20) +#define HC_CFG_CLK_POL_INV BIT(19) +#define HC_CFG_BIG_ENDIAN BIT(18) +#define HC_CFG_DATA_PASS BIT(17) +#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16) +#define HC_CFG_MAN_START_EN BIT(3) +#define HC_CFG_MAN_START BIT(2) +#define HC_CFG_MAN_CS_EN BIT(1) +#define HC_CFG_MAN_CS_ASSERT BIT(0) + +#define INT_STS 0x4 +#define INT_STS_EN 0x8 +#define INT_SIG_EN 0xc +#define INT_STS_ALL GENMASK(31, 0) +#define INT_RDY_PIN BIT(26) +#define INT_RDY_SR BIT(25) +#define INT_LNR_SUSP BIT(24) +#define INT_ECC_ERR BIT(17) +#define INT_CRC_ERR BIT(16) +#define INT_LWR_DIS BIT(12) +#define INT_LRD_DIS BIT(11) +#define INT_SDMA_INT BIT(10) +#define INT_DMA_FINISH BIT(9) +#define INT_RX_NOT_FULL BIT(3) +#define INT_RX_NOT_EMPTY BIT(2) +#define INT_TX_NOT_FULL BIT(1) +#define INT_TX_EMPTY BIT(0) + +#define HC_EN 0x10 +#define HC_EN_BIT BIT(0) + +#define TXD(x) (0x14 + ((x) * 4)) +#define RXD 0x24 + +#define SS_CTRL(s) (0x30 + ((s) * 4)) +#define LRD_CFG 0x44 +#define LWR_CFG 0x80 +#define RWW_CFG 0x70 +#define OP_READ BIT(23) +#define OP_DUMMY_CYC(x) ((x) << 17) +#define OP_ADDR_BYTES(x) ((x) << 14) +#define OP_CMD_BYTES(x) (((x) - 1) << 13) +#define OP_OCTA_CRC_EN BIT(12) +#define OP_DQS_EN BIT(11) +#define OP_ENHC_EN BIT(10) +#define OP_PREAMBLE_EN BIT(9) +#define OP_DATA_DDR BIT(8) +#define OP_DATA_BUSW(x) ((x) << 6) +#define OP_ADDR_DDR BIT(5) +#define OP_ADDR_BUSW(x) ((x) << 3) +#define OP_CMD_DDR BIT(2) +#define OP_CMD_BUSW(x) (x) +#define OP_BUSW_1 0 +#define OP_BUSW_2 1 +#define OP_BUSW_4 2 +#define OP_BUSW_8 3 + +#define OCTA_CRC 0x38 +#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16)) +#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16))) +#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16)) + +#define ONFI_DIN_CNT(s) (0x3c + (s)) + +#define LRD_CTRL 0x48 +#define RWW_CTRL 0x74 +#define LWR_CTRL 0x84 +#define LMODE_EN BIT(31) +#define LMODE_SLV_ACT(x) ((x) << 21) +#define LMODE_CMD1(x) ((x) << 8) +#define LMODE_CMD0(x) (x) + +#define LRD_ADDR 0x4c +#define LWR_ADDR 0x88 +#define LRD_RANGE 0x50 +#define LWR_RANGE 0x8c + +#define AXI_SLV_ADDR 0x54 + +#define DMAC_RD_CFG 0x58 +#define DMAC_WR_CFG 0x94 +#define DMAC_CFG_PERIPH_EN BIT(31) +#define DMAC_CFG_ALLFLUSH_EN BIT(30) +#define DMAC_CFG_LASTFLUSH_EN BIT(29) +#define DMAC_CFG_QE(x) (((x) + 1) << 16) +#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12) +#define DMAC_CFG_BURST_SZ(x) ((x) << 8) +#define DMAC_CFG_DIR_READ BIT(1) +#define DMAC_CFG_START BIT(0) + +#define DMAC_RD_CNT 0x5c +#define DMAC_WR_CNT 0x98 + +#define SDMA_ADDR 0x60 + +#define DMAM_CFG 0x64 +#define DMAM_CFG_START BIT(31) +#define DMAM_CFG_CONT BIT(30) +#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2) +#define DMAM_CFG_DIR_READ BIT(1) +#define DMAM_CFG_EN BIT(0) + +#define DMAM_CNT 0x68 + +#define LNR_TIMER_TH 0x6c + +#define RDM_CFG0 0x78 +#define RDM_CFG0_POLY(x) (x) + +#define RDM_CFG1 0x7c +#define RDM_CFG1_RDM_EN BIT(31) +#define RDM_CFG1_SEED(x) (x) + +#define LWR_SUSP_CTRL 0x90 +#define LWR_SUSP_CTRL_EN BIT(31) + +#define DMAS_CTRL 0x9c +#define DMAS_CTRL_DIR_READ BIT(31) +#define DMAS_CTRL_EN BIT(30) + +#define DATA_STROB 0xa0 +#define DATA_STROB_EDO_EN BIT(2) +#define DATA_STROB_INV_POL BIT(1) +#define DATA_STROB_DELAY_2CYC BIT(0) + +#define IDLY_CODE(x) (0xa4 + ((x) * 4)) +#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8)) + +#define GPIO 0xc4 +#define GPIO_PT(x) BIT(3 + ((x) * 16)) +#define GPIO_RESET(x) BIT(2 + ((x) * 16)) +#define GPIO_HOLDB(x) BIT(1 + ((x) * 16)) +#define GPIO_WPB(x) BIT((x) * 16) + +#define HC_VER 0xd0 + +#define HW_TEST(x) (0xe0 + ((x) * 4)) + +struct mx25f0a_mfd { + void __iomem *base; + void __iomem *dirmap; +}; + +#endif // __MFD_MXIC_MX25F0A_H From patchwork Thu Mar 28 10:18:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874683 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 20B5F14DE for ; Thu, 28 Mar 2019 09:59:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 080DD2882E for ; Thu, 28 Mar 2019 09:59:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ED64928CC7; Thu, 28 Mar 2019 09:59:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A22272882E for ; Thu, 28 Mar 2019 09:59:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726298AbfC1J7F (ORCPT ); Thu, 28 Mar 2019 05:59:05 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50402 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725875AbfC1J7F (ORCPT ); Thu, 28 Mar 2019 05:59:05 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJL052359; Thu, 28 Mar 2019 17:58:50 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 2/7] mtd: rawnand: Add Macronix MX25F0A NAND controller driver Date: Thu, 28 Mar 2019 18:18:33 +0800 Message-Id: <1553768318-23149-3-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJL052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a driver for Macronix MX25F0A NAND controller. Signed-off-by: Mason Yang --- drivers/mtd/nand/raw/Kconfig | 6 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/mxic_nand.c | 303 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 drivers/mtd/nand/raw/mxic_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index e604625..e0329cc 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -522,6 +522,12 @@ config MTD_NAND_QCOM Enables support for NAND flash chips on SoCs containing the EBI2 NAND controller. This controller is found on IPQ806x SoC. +config MTD_NAND_MXIC + tristate "Macronix MX25F0A NAND controller" + depends on HAS_IOMEM + help + This selects the Macronix MX25F0A NAND controller driver. + config MTD_NAND_MTK tristate "Support for NAND controller on MTK SoCs" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 5a5a72f..c8a6790 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o +obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c new file mode 100644 index 0000000..03886b2 --- /dev/null +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Macronix International Co., Ltd. +// +// Authors: +// Mason Yang +// zhengxunli +// + +#include +#include +#include + +#include "internals.h" + +struct mxic_nand_ctlr { + struct nand_controller base; + struct nand_chip nand; + void __iomem *regs; +}; + +static void mxic_host_init(struct mxic_nand_ctlr *mxic) +{ + writel(DATA_STROB_EDO_EN, mxic->regs + DATA_STROB); + writel(INT_STS_ALL, mxic->regs + INT_STS_EN); + writel(0x0, mxic->regs + ONFI_DIN_CNT(0)); + writel(HC_CFG_NIO(8) | HC_CFG_SLV_ACT(0) | HC_CFG_IDLE_SIO_LVL(1) | + HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) | HC_CFG_MAN_CS_EN, + mxic->regs + HC_CFG); + writel(0x0, mxic->regs + HC_EN); +} + +static int mxic_nand_wait_ready(struct nand_chip *chip) +{ + struct mxic_nand_ctlr *mxic = nand_get_controller_data(chip); + u32 sts; + + return readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_RDY_PIN, 0, USEC_PER_SEC); +} + +static void mxic_nand_select_chip(struct nand_chip *chip, int chipnr) +{ + struct mxic_nand_ctlr *mxic = nand_get_controller_data(chip); + + switch (chipnr) { + case 0: + case 1: + writel(HC_EN_BIT, mxic->regs + HC_EN); + writel(HC_CFG_MAN_CS_ASSERT | readl(mxic->regs + HC_CFG), + mxic->regs + HC_CFG); + break; + + case -1: + writel(~HC_CFG_MAN_CS_ASSERT & readl(mxic->regs + HC_CFG), + mxic->regs + HC_CFG); + writel(0, mxic->regs + HC_EN); + break; + + default: + break; + } +} + +static int mxic_nand_data_xfer(struct mxic_nand_ctlr *mxic, const void *txbuf, + void *rxbuf, unsigned int len) +{ + unsigned int pos = 0; + + while (pos < len) { + unsigned int nbytes = len - pos; + u32 data = 0xffffffff; + u32 sts; + int ret; + + if (nbytes > 4) + nbytes = 4; + + if (txbuf) + memcpy(&data, txbuf + pos, nbytes); + + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 0, USEC_PER_SEC); + if (ret) + return ret; + + writel(data, mxic->regs + TXD(nbytes % 4)); + + if (rxbuf) { + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + data = readl(mxic->regs + RXD); + data >>= (8 * (4 - nbytes)); + memcpy(rxbuf + pos, &data, nbytes); + WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); + } else { + readl(mxic->regs + RXD); + } + WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); + + pos += nbytes; + } + + return 0; +} + +static int mxic_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + struct mxic_nand_ctlr *mxic = nand_get_controller_data(chip); + const struct nand_op_instr *instr = NULL; + int i, len = 0, ret = 0; + unsigned int op_id; + unsigned char cmdcnt = 0, addr_cnt = 0, cmd_addr[8] = {0}; + + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + cmd_addr[len++] = instr->ctx.cmd.opcode; + cmdcnt++; + break; + + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + cmd_addr[len++] = instr->ctx.addr.addrs[i]; + addr_cnt = i; + break; + + case NAND_OP_DATA_IN_INSTR: + break; + + case NAND_OP_DATA_OUT_INSTR: + writel(instr->ctx.data.len, + mxic->regs + ONFI_DIN_CNT(0)); + break; + + case NAND_OP_WAITRDY_INSTR: + break; + } + } + + if (op_id == 5 && instr->type == NAND_OP_WAITRDY_INSTR) { + /* + * In case cmd-addr-data-cmd-wait in a sequence, + * separate the 2'nd command, i.e,. nand_prog_page_op() + */ + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_ADDR_BUSW(OP_BUSW_8) | + OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_ADDR_BYTES(addr_cnt) | + OP_CMD_BYTES(1), mxic->regs + SS_CTRL(0)); + writel(0, mxic->regs + HC_EN); + writel(HC_EN_BIT, mxic->regs + HC_EN); + + mxic_nand_data_xfer(mxic, cmd_addr, NULL, len - 1); + + mxic_nand_data_xfer(mxic, instr->ctx.data.buf.out, NULL, + instr->ctx.data.len); + + writel(0, mxic->regs + HC_EN); + writel(HC_EN_BIT, mxic->regs + HC_EN); + mxic_nand_data_xfer(mxic, &cmd_addr[--len], NULL, 1); + ret = mxic_nand_wait_ready(chip); + if (ret) + goto err_out; + return ret; + } + + if (len) { + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_ADDR_BUSW(OP_BUSW_8) | + OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_ADDR_BYTES(addr_cnt) | + OP_CMD_BYTES(cmdcnt > 0 ? cmdcnt : 0), + mxic->regs + SS_CTRL(0)); + writel(0, mxic->regs + HC_EN); + writel(HC_EN_BIT, mxic->regs + HC_EN); + + mxic_nand_data_xfer(mxic, cmd_addr, NULL, len); + } + + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + case NAND_OP_ADDR_INSTR: + break; + + case NAND_OP_DATA_IN_INSTR: + writel(0x0, mxic->regs + ONFI_DIN_CNT(0)); + writel(readl(mxic->regs + SS_CTRL(0)) | OP_READ, + mxic->regs + SS_CTRL(0)); + mxic_nand_data_xfer(mxic, NULL, instr->ctx.data.buf.in, + instr->ctx.data.len); + break; + + case NAND_OP_DATA_OUT_INSTR: + mxic_nand_data_xfer(mxic, instr->ctx.data.buf.out, NULL, + instr->ctx.data.len); + break; + + case NAND_OP_WAITRDY_INSTR: + ret = mxic_nand_wait_ready(chip); + if (ret) + goto err_out; + break; + } + } + +err_out: + return ret; +} + +static const struct nand_controller_ops mxic_nand_controller_ops = { + .exec_op = mxic_nand_exec_op, +}; + +static int mx25f0a_nand_probe(struct platform_device *pdev) +{ + struct mtd_info *mtd; + struct mx25f0a_mfd *mxic_mfd = dev_get_drvdata(pdev->dev.parent); + struct mxic_nand_ctlr *mxic; + struct nand_chip *nand_chip; + int err; + + mxic = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_ctlr), + GFP_KERNEL); + if (!mxic) + return -ENOMEM; + + nand_chip = &mxic->nand; + mtd = nand_to_mtd(nand_chip); + mtd->dev.parent = &pdev->dev; + nand_chip->ecc.priv = NULL; + nand_set_flash_node(nand_chip, pdev->dev.of_node); + nand_chip->priv = mxic; + + mxic->regs = mxic_mfd->base; + if (IS_ERR(mxic->regs)) + return PTR_ERR(mxic->regs); + + nand_chip->legacy.select_chip = mxic_nand_select_chip; + + mxic->base.ops = &mxic_nand_controller_ops; + nand_controller_init(&mxic->base); + nand_chip->controller = &mxic->base; + + mxic_host_init(mxic); + + err = nand_scan(nand_chip, 1); + if (err) + goto fail; + + err = mtd_device_register(mtd, NULL, 0); + if (err) + goto fail; + + platform_set_drvdata(pdev, mxic); + + return 0; +fail: + return err; +} + +static int mx25f0a_nand_remove(struct platform_device *pdev) +{ + struct mxic_nand_ctlr *mxic = platform_get_drvdata(pdev); + + nand_release(&mxic->nand); + + return 0; +} + +static const struct of_device_id mx25f0a_nand_ids[] = { + { .compatible = "mxicy,mx25f0a-nand-ctlr", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mx25f0a_nand_ids); + +static struct platform_driver mx25f0a_nand_driver = { + .probe = mx25f0a_nand_probe, + .remove = mx25f0a_nand_remove, + .driver = { + .name = "mxic-nand-ctlr", + .of_match_table = mx25f0a_nand_ids, + }, +}; +module_platform_driver(mx25f0a_nand_driver); + +MODULE_AUTHOR("Mason Yang "); +MODULE_DESCRIPTION("MX25F0A RAW NAND controller driver"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Mar 28 10:18:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874687 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 470F813B5 for ; Thu, 28 Mar 2019 09:59:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 329EE27FA8 for ; Thu, 28 Mar 2019 09:59:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 264B828161; Thu, 28 Mar 2019 09:59:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7AD7128CA6 for ; Thu, 28 Mar 2019 09:59:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726380AbfC1J7J (ORCPT ); Thu, 28 Mar 2019 05:59:09 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50420 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726375AbfC1J7J (ORCPT ); Thu, 28 Mar 2019 05:59:09 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJM052359; Thu, 28 Mar 2019 17:58:50 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 3/7] spi: Patch Macronix MX25F0A SPI controller driver Date: Thu, 28 Mar 2019 18:18:34 +0800 Message-Id: <1553768318-23149-4-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJM052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Patch a MFD driver for Macronix MX25F0A SPI controller. Signed-off-by: Mason Yang --- drivers/spi/spi-mxic.c | 159 +------------------------------------------------ 1 file changed, 3 insertions(+), 156 deletions(-) diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index e41ae6e..fbebf89 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -9,163 +9,11 @@ // #include -#include -#include -#include -#include +#include #include #include #include -#define HC_CFG 0x0 -#define HC_CFG_IF_CFG(x) ((x) << 27) -#define HC_CFG_DUAL_SLAVE BIT(31) -#define HC_CFG_INDIVIDUAL BIT(30) -#define HC_CFG_NIO(x) (((x) / 4) << 27) -#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2))) -#define HC_CFG_TYPE_SPI_NOR 0 -#define HC_CFG_TYPE_SPI_NAND 1 -#define HC_CFG_TYPE_SPI_RAM 2 -#define HC_CFG_TYPE_RAW_NAND 3 -#define HC_CFG_SLV_ACT(x) ((x) << 21) -#define HC_CFG_CLK_PH_EN BIT(20) -#define HC_CFG_CLK_POL_INV BIT(19) -#define HC_CFG_BIG_ENDIAN BIT(18) -#define HC_CFG_DATA_PASS BIT(17) -#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16) -#define HC_CFG_MAN_START_EN BIT(3) -#define HC_CFG_MAN_START BIT(2) -#define HC_CFG_MAN_CS_EN BIT(1) -#define HC_CFG_MAN_CS_ASSERT BIT(0) - -#define INT_STS 0x4 -#define INT_STS_EN 0x8 -#define INT_SIG_EN 0xc -#define INT_STS_ALL GENMASK(31, 0) -#define INT_RDY_PIN BIT(26) -#define INT_RDY_SR BIT(25) -#define INT_LNR_SUSP BIT(24) -#define INT_ECC_ERR BIT(17) -#define INT_CRC_ERR BIT(16) -#define INT_LWR_DIS BIT(12) -#define INT_LRD_DIS BIT(11) -#define INT_SDMA_INT BIT(10) -#define INT_DMA_FINISH BIT(9) -#define INT_RX_NOT_FULL BIT(3) -#define INT_RX_NOT_EMPTY BIT(2) -#define INT_TX_NOT_FULL BIT(1) -#define INT_TX_EMPTY BIT(0) - -#define HC_EN 0x10 -#define HC_EN_BIT BIT(0) - -#define TXD(x) (0x14 + ((x) * 4)) -#define RXD 0x24 - -#define SS_CTRL(s) (0x30 + ((s) * 4)) -#define LRD_CFG 0x44 -#define LWR_CFG 0x80 -#define RWW_CFG 0x70 -#define OP_READ BIT(23) -#define OP_DUMMY_CYC(x) ((x) << 17) -#define OP_ADDR_BYTES(x) ((x) << 14) -#define OP_CMD_BYTES(x) (((x) - 1) << 13) -#define OP_OCTA_CRC_EN BIT(12) -#define OP_DQS_EN BIT(11) -#define OP_ENHC_EN BIT(10) -#define OP_PREAMBLE_EN BIT(9) -#define OP_DATA_DDR BIT(8) -#define OP_DATA_BUSW(x) ((x) << 6) -#define OP_ADDR_DDR BIT(5) -#define OP_ADDR_BUSW(x) ((x) << 3) -#define OP_CMD_DDR BIT(2) -#define OP_CMD_BUSW(x) (x) -#define OP_BUSW_1 0 -#define OP_BUSW_2 1 -#define OP_BUSW_4 2 -#define OP_BUSW_8 3 - -#define OCTA_CRC 0x38 -#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16)) -#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16))) -#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16)) - -#define ONFI_DIN_CNT(s) (0x3c + (s)) - -#define LRD_CTRL 0x48 -#define RWW_CTRL 0x74 -#define LWR_CTRL 0x84 -#define LMODE_EN BIT(31) -#define LMODE_SLV_ACT(x) ((x) << 21) -#define LMODE_CMD1(x) ((x) << 8) -#define LMODE_CMD0(x) (x) - -#define LRD_ADDR 0x4c -#define LWR_ADDR 0x88 -#define LRD_RANGE 0x50 -#define LWR_RANGE 0x8c - -#define AXI_SLV_ADDR 0x54 - -#define DMAC_RD_CFG 0x58 -#define DMAC_WR_CFG 0x94 -#define DMAC_CFG_PERIPH_EN BIT(31) -#define DMAC_CFG_ALLFLUSH_EN BIT(30) -#define DMAC_CFG_LASTFLUSH_EN BIT(29) -#define DMAC_CFG_QE(x) (((x) + 1) << 16) -#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12) -#define DMAC_CFG_BURST_SZ(x) ((x) << 8) -#define DMAC_CFG_DIR_READ BIT(1) -#define DMAC_CFG_START BIT(0) - -#define DMAC_RD_CNT 0x5c -#define DMAC_WR_CNT 0x98 - -#define SDMA_ADDR 0x60 - -#define DMAM_CFG 0x64 -#define DMAM_CFG_START BIT(31) -#define DMAM_CFG_CONT BIT(30) -#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2) -#define DMAM_CFG_DIR_READ BIT(1) -#define DMAM_CFG_EN BIT(0) - -#define DMAM_CNT 0x68 - -#define LNR_TIMER_TH 0x6c - -#define RDM_CFG0 0x78 -#define RDM_CFG0_POLY(x) (x) - -#define RDM_CFG1 0x7c -#define RDM_CFG1_RDM_EN BIT(31) -#define RDM_CFG1_SEED(x) (x) - -#define LWR_SUSP_CTRL 0x90 -#define LWR_SUSP_CTRL_EN BIT(31) - -#define DMAS_CTRL 0x9c -#define DMAS_CTRL_DIR_READ BIT(31) -#define DMAS_CTRL_EN BIT(30) - -#define DATA_STROB 0xa0 -#define DATA_STROB_EDO_EN BIT(2) -#define DATA_STROB_INV_POL BIT(1) -#define DATA_STROB_DELAY_2CYC BIT(0) - -#define IDLY_CODE(x) (0xa4 + ((x) * 4)) -#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8)) - -#define GPIO 0xc4 -#define GPIO_PT(x) BIT(3 + ((x) * 16)) -#define GPIO_RESET(x) BIT(2 + ((x) * 16)) -#define GPIO_HOLDB(x) BIT(1 + ((x) * 16)) -#define GPIO_WPB(x) BIT((x) * 16) - -#define HC_VER 0xd0 - -#define HW_TEST(x) (0xe0 + ((x) * 4)) - struct mxic_spi { struct clk *ps_clk; struct clk *send_clk; @@ -525,8 +373,8 @@ static int __maybe_unused mxic_spi_runtime_resume(struct device *dev) static int mxic_spi_probe(struct platform_device *pdev) { + struct mx25f0a_mfd *mxic_mfd = dev_get_drvdata(pdev->dev.parent); struct spi_master *master; - struct resource *res; struct mxic_spi *mxic; int ret; @@ -552,8 +400,7 @@ static int mxic_spi_probe(struct platform_device *pdev) if (IS_ERR(mxic->send_dly_clk)) return PTR_ERR(mxic->send_dly_clk); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - mxic->regs = devm_ioremap_resource(&pdev->dev, res); + mxic->regs = mxic_mfd->base; if (IS_ERR(mxic->regs)) return PTR_ERR(mxic->regs); From patchwork Thu Mar 28 10:18:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874689 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14E8A14DE for ; Thu, 28 Mar 2019 09:59:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F36A91FE8E for ; Thu, 28 Mar 2019 09:59:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E717127FA8; Thu, 28 Mar 2019 09:59:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF32D2625B for ; Thu, 28 Mar 2019 09:59:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726441AbfC1J7N (ORCPT ); Thu, 28 Mar 2019 05:59:13 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50429 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbfC1J7N (ORCPT ); Thu, 28 Mar 2019 05:59:13 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJN052359; Thu, 28 Mar 2019 17:58:52 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 4/7] dt-bindings: mfd: Document Macronix MX25F0A controller bindings Date: Thu, 28 Mar 2019 18:18:35 +0800 Message-Id: <1553768318-23149-5-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJN052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Document the bindings used by the Macronix MX25F0A MFD controller. Signed-off-by: Mason Yang --- .../devicetree/bindings/mfd/mxic-mx25f0a.txt | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mxic-mx25f0a.txt diff --git a/Documentation/devicetree/bindings/mfd/mxic-mx25f0a.txt b/Documentation/devicetree/bindings/mfd/mxic-mx25f0a.txt new file mode 100644 index 0000000..53b4839 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mxic-mx25f0a.txt @@ -0,0 +1,66 @@ +Macronix MX25F0A Multi-Function Device Tree Bindings +---------------------------------------------------- + +MX25F0A is a MultiFunction Device with SPI and raw NAND, which +supports either spi host controller or raw nand controller. + +Required properties: +- compatible: should be "mxic,mx25f0a-mfd" +- #address-cells: should be 1 +- #size-cells: should be 0 +- reg: should contain 2 entries, one for the registers and one for the direct + mapping area in SPI mode. +- reg-names: should contain "regs" and "dirmap" +- interrupts: interrupt line connected to this MFD controller + +Required nodes: + - spi : + Node for configuring the SPI controller driver. + Required properties: + - compatible = "mxicy,mx25f0a-spi"; + - clock-names: should contain "ps_clk", "send_clk" and + "send_dly_clk" + - clocks: should contain 3 entries for the "ps_clk", "send_clk" + and "send_dly_clk" clocks + +- nand : + Node for configuring the raw nand controller driver. + Required properties: + - compatible = "mxicy,mx25f0a-nand-ctlr"; + - nand-ecc-mode = "soft"; + - nand-ecc-algo = "bch"; + +Example: + + mxic: mx25f0a-mfd@43c30000 { + compatible = "mxic,mx25f0a-mfd"; + reg = <0x43c30000 0x10000>, <0xa0000000 0x4000000>; + reg-names = "regs", "dirmap"; + #address-cells = <1>; + #size-cells = <0>; + + /* either spi or nand */ + spi { + compatible = "mxicy,mx25f0a-spi"; + clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>; + clock-names = "send_clk", "send_dly_clk", "ps_clk"; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; + }; + + nand { + compatible = "mxicy,mx25f0a-nand-ctlr"; + nand-ecc-mode = "soft"; + nand-ecc-algo = "bch"; + nand-ecc-step-size = <512>; + nand-ecc-strength = <8>; + }; + }; From patchwork Thu Mar 28 10:18:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874695 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 61DA514DE for ; Thu, 28 Mar 2019 09:59:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4DB591FE8E for ; Thu, 28 Mar 2019 09:59:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 40D8027FA8; Thu, 28 Mar 2019 09:59:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05D472625B for ; Thu, 28 Mar 2019 09:59:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726375AbfC1J7S (ORCPT ); Thu, 28 Mar 2019 05:59:18 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50449 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbfC1J7S (ORCPT ); Thu, 28 Mar 2019 05:59:18 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJO052359; Thu, 28 Mar 2019 17:58:52 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 5/7] spi: Add direct mapping mode for Macronix SPI controller Date: Thu, 28 Mar 2019 18:18:36 +0800 Message-Id: <1553768318-23149-6-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJO052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add direct mapping read mode for Macronix SPI controller driver. Signed-off-by: Mason Yang --- drivers/spi/spi-mxic.c | 129 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 29 deletions(-) diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index fbebf89..9f5ff2b 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -19,6 +19,7 @@ struct mxic_spi { struct clk *send_clk; struct clk *send_dly_clk; void __iomem *regs; + void __iomem *dirmap; u32 cur_speed_hz; }; @@ -128,6 +129,42 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic) mxic->regs + HC_CFG); } +static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op) +{ + u32 cfg = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1); + + if (op->addr.nbytes) + cfg |= OP_ADDR_BYTES(op->addr.nbytes) | + OP_ADDR_BUSW(fls(op->addr.buswidth) - 1); + + if (op->dummy.nbytes) + cfg |= OP_DUMMY_CYC(op->dummy.nbytes); + + if (op->data.nbytes) { + cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1); + if (op->data.dir == SPI_MEM_DATA_IN) + cfg |= OP_READ; + } + + return cfg; +} + +static void mxic_spi_set_hc_cfg(struct spi_device *spi, u32 flags) +{ + struct mxic_spi *mxic = spi_master_get_devdata(spi->master); + int nio = 1; + + if (spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) + nio = 4; + else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) + nio = 2; + + writel(flags | HC_CFG_NIO(nio) | + HC_CFG_TYPE(spi->chip_select, HC_CFG_TYPE_SPI_NOR) | + HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1), + mxic->regs + HC_CFG); +} + static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf, void *rxbuf, unsigned int len) { @@ -201,43 +238,18 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) { struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master); - int nio = 1, i, ret; - u32 ss_ctrl; + int i, ret; u8 addr[8]; ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz); if (ret) return ret; - if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) - nio = 4; - else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) - nio = 2; + mxic_spi_set_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN); - writel(HC_CFG_NIO(nio) | - HC_CFG_TYPE(mem->spi->chip_select, HC_CFG_TYPE_SPI_NOR) | - HC_CFG_SLV_ACT(mem->spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1) | - HC_CFG_MAN_CS_EN, - mxic->regs + HC_CFG); writel(HC_EN_BIT, mxic->regs + HC_EN); - - ss_ctrl = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1); - - if (op->addr.nbytes) - ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) | - OP_ADDR_BUSW(fls(op->addr.buswidth) - 1); - - if (op->dummy.nbytes) - ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes); - - if (op->data.nbytes) { - ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1); - if (op->data.dir == SPI_MEM_DATA_IN) - ss_ctrl |= OP_READ; - } - - writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select)); - + writel(mxic_spi_mem_prep_op_cfg(op), + mxic->regs + SS_CTRL(mem->spi->chip_select)); writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT, mxic->regs + HC_CFG); @@ -271,9 +283,64 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, return ret; } +static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master); + + if (!mxic->dirmap) + return -ENOTSUPP; + + /* + * TODO: overcome this limitation by moving LWR/LRD_ADDR during a + * read/write operation. + */ + if (desc->info.offset + desc->info.length > U32_MAX) + return -ENOTSUPP; + + if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + return -ENOTSUPP; + + if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + return -ENOTSUPP; + + return 0; +} + +static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master); + int ret; + u32 sts; + + mxic_spi_set_hc_cfg(desc->mem->spi, 0); + + writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl), + mxic->regs + LRD_CFG); + writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode >> 8) | + (LMODE_CMD1(desc->info.op_tmpl.cmd.opcode) & 0xff00) | + LMODE_SLV_ACT(desc->mem->spi->chip_select) | + LMODE_EN, mxic->regs + LRD_CTRL); + + memcpy_fromio(buf, mxic->dirmap + offs, len); + + writel(INT_LRD_DIS, mxic->regs + INT_STS); + writel(0, mxic->regs + LRD_CTRL); + + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_LRD_DIS, 0, USEC_PER_SEC); + + if (ret) + return ret; + + return len; +} + static const struct spi_controller_mem_ops mxic_spi_mem_ops = { .supports_op = mxic_spi_mem_supports_op, .exec_op = mxic_spi_mem_exec_op, + .dirmap_create = mxic_spi_mem_dirmap_create, + .dirmap_read = mxic_spi_mem_dirmap_read, }; static void mxic_spi_set_cs(struct spi_device *spi, bool lvl) @@ -404,6 +471,10 @@ static int mxic_spi_probe(struct platform_device *pdev) if (IS_ERR(mxic->regs)) return PTR_ERR(mxic->regs); + mxic->dirmap = mxic_mfd->dirmap; + if (IS_ERR(mxic->dirmap)) + mxic->dirmap = NULL; + pm_runtime_enable(&pdev->dev); master->auto_runtime_pm = true; From patchwork Thu Mar 28 10:18:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874697 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AC12113B5 for ; Thu, 28 Mar 2019 09:59:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94B2C1FE8E for ; Thu, 28 Mar 2019 09:59:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 88CB428161; Thu, 28 Mar 2019 09:59:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 508161FE8E for ; Thu, 28 Mar 2019 09:59:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726428AbfC1J7Y (ORCPT ); Thu, 28 Mar 2019 05:59:24 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50463 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbfC1J7X (ORCPT ); Thu, 28 Mar 2019 05:59:23 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJP052359; Thu, 28 Mar 2019 17:58:53 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 6/7] mtd: rawnand: Add Macronix NAND read retry and randomizer support Date: Thu, 28 Mar 2019 18:18:37 +0800 Message-Id: <1553768318-23149-7-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJP052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a driver for Macronix NAND read retry and randomizer. Signed-off-by: Mason Yang --- drivers/mtd/nand/raw/nand_macronix.c | 169 +++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 47d8cda..a19caa4 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -17,6 +17,174 @@ #include "internals.h" +#define MACRONIX_READ_RETRY_BIT BIT(0) +#define MACRONIX_RANDOMIZER_BIT BIT(1) +#define MACRONIX_READ_RETRY_MODE 5 + +#define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 + +struct nand_onfi_vendor_macronix { + u8 reserved[1]; + u8 reliability_func; +} __packed; + +struct nand_chip *mxic_sysfs; + +static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0}; + int ret; + + if (mode > MACRONIX_READ_RETRY_MODE) + mode = MACRONIX_READ_RETRY_MODE; + + feature[0] = mode; + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); + if (ret) + pr_err("failed to enter read retry moded:%d\n", mode); + + if (mode == 0) + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); + if (ret) + pr_err("failed to exits read retry moded:%d\n", mode); + + return ret; +} + +static ssize_t mxic_nand_rand_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct nand_chip *chip = mxic_sysfs; + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0}; + int ret; + + nand_select_target(chip, 0); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("failed to check mxic nand device randomizer\n"); + + return sprintf(buf, "MXIC NAND device randomizer %s(0x%x)\n", + feature[0] & MACRONIX_RANDOMIZER_BIT ? + "enable" : "disable", feature[0]); +} + +static ssize_t mxic_nand_rand_type_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct nand_chip *chip = mxic_sysfs; + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0}; + unsigned int rand_layout; + int ret; + + nand_select_target(chip, 0); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + nand_deselect_target(chip); + + if (feature[0]) { + pr_err("Randomizer is enabled 0x%x\n", feature[0]); + goto err_out; + } + + ret = kstrtouint(buf, 0, &rand_layout); + if (ret) + goto err_out; + + if (rand_layout > 7) { + pr_err("Error parameter value:0x%x\n", rand_layout); + goto err_out; + } + + feature[0] = rand_layout & 0x07; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + nand_deselect_target(chip); + if (ret) { + pr_err("device randomizer set feature failed\n"); + goto err_out; + } + + feature[0] = 0x0; + nand_select_target(chip, 0); + ret = nand_prog_page_op(chip, 0, 0, feature, 1); + nand_deselect_target(chip); + if (ret) { + pr_err("Prog device randomizer failed\n"); + goto err_out; + } + + feature[0] = 0x0; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("failed to exits prog device randomizer\n"); + +err_out: + return count; +} + +static const struct kobj_attribute sysfs_mxic_nand = + __ATTR(nand_random, S_IRUGO | S_IWUSR, + mxic_nand_rand_type_show, + mxic_nand_rand_type_store); + +static void macronix_nand_onfi_init(struct nand_chip *chip) +{ + struct nand_parameters *p = &chip->parameters; + struct kobject *kobj; + int ret; + + mxic_sysfs = chip; + if (p->onfi) { + struct nand_onfi_vendor_macronix *mxic = + (void *)p->onfi->vendor; + + if (mxic->reliability_func & MACRONIX_READ_RETRY_BIT) { + chip->read_retries = MACRONIX_READ_RETRY_MODE + 1; + chip->setup_read_retry = + macronix_nand_setup_read_retry; + if (p->supports_set_get_features) { + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, + p->set_feature_list); + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, + p->get_feature_list); + } + } + + if (mxic->reliability_func & MACRONIX_RANDOMIZER_BIT) { + if (p->supports_set_get_features) { + set_bit(ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + p->set_feature_list); + set_bit(ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + p->get_feature_list); + /* + * create syfs-fs for MXIC NAND device + * randomizer status check & enable + * operations. + */ + kobj = kobject_create_and_add("mxic_rand_nand", + NULL); + if (!kobj) + return; + + ret = sysfs_create_file(kobj, + &sysfs_mxic_nand.attr); + if (ret) { + pr_err("Err: mxic_rand_nand sysfs"); + kobject_put(kobj); + } + } + } + } +} + /* * Macronix AC series does not support using SET/GET_FEATURES to change * the timings unlike what is declared in the parameter page. Unflag @@ -65,6 +233,7 @@ static int macronix_nand_init(struct nand_chip *chip) chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; macronix_nand_fix_broken_get_timings(chip); + macronix_nand_onfi_init(chip); return 0; } From patchwork Thu Mar 28 10:18:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mason Yang X-Patchwork-Id: 10874699 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3363F13B5 for ; Thu, 28 Mar 2019 09:59:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1ED482625B for ; Thu, 28 Mar 2019 09:59:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 11FDE2832D; Thu, 28 Mar 2019 09:59:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B67782625B for ; Thu, 28 Mar 2019 09:59:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726476AbfC1J71 (ORCPT ); Thu, 28 Mar 2019 05:59:27 -0400 Received: from twhmllg3.macronix.com ([122.147.135.201]:50490 "EHLO TWHMLLG3.macronix.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726393AbfC1J71 (ORCPT ); Thu, 28 Mar 2019 05:59:27 -0400 Received: from localhost.localdomain ([172.17.195.96]) by TWHMLLG3.macronix.com with ESMTP id x2S9wlJQ052359; Thu, 28 Mar 2019 17:58:54 +0800 (GMT-8) (envelope-from masonccyang@mxic.com.tw) From: Mason Yang To: broonie@kernel.org, marek.vasut@gmail.com, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, bbrezillon@kernel.org, dwmw2@infradead.org, lee.jones@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, computersforpeace@gmal.com, paul.burton@mips.com, stefan@agner.ch, christophe.kerello@st.com, liang.yang@amlogic.com, geert@linux-m68k.org, devicetree@vger.kernel.org, marcel.ziswiler@toradex.com, linux-mtd@lists.infradead.org, richard@nod.at, miquel.raynal@bootlin.com Cc: juliensu@mxic.com.tw, zhengxunli@mxic.com.tw, Mason Yang Subject: [PATCH 7/7] mtd: rawnand: Add Macronix NAND block protection driver Date: Thu, 28 Mar 2019 18:18:38 +0800 Message-Id: <1553768318-23149-8-git-send-email-masonccyang@mxic.com.tw> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> References: <1553768318-23149-1-git-send-email-masonccyang@mxic.com.tw> X-MAIL: TWHMLLG3.macronix.com x2S9wlJQ052359 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a driver for Macronix NAND block protection function. Signed-off-by: Mason Yang --- drivers/mtd/nand/raw/mxic_nand.c | 3 +++ drivers/mtd/nand/raw/nand_macronix.c | 47 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/mxic-mx25f0a.h | 3 +++ 3 files changed, 53 insertions(+) diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c index 03886b2..9307ca2 100644 --- a/drivers/mtd/nand/raw/mxic_nand.c +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -262,6 +262,9 @@ static int mx25f0a_nand_probe(struct platform_device *pdev) if (err) goto fail; + mtd->_lock = mxic_nand_lock; + mtd->_unlock = mxic_nand_unlock; + err = mtd_device_register(mtd, NULL, 0); if (err) goto fail; diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index a19caa4..db63350 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -21,8 +21,12 @@ #define MACRONIX_RANDOMIZER_BIT BIT(1) #define MACRONIX_READ_RETRY_MODE 5 +#define ONFI_FEATURE_ADDR_MXIC_PROTECTION 0xA0 #define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 +#define MXIC_BLOCK_PROTECTION_ALL_LOCK 0x38 +#define MXIC_BLOCK_PROTECTION_ALL_UNLOCK 0x0 + struct nand_onfi_vendor_macronix { u8 reserved[1]; u8 reliability_func; @@ -146,6 +150,13 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) struct nand_onfi_vendor_macronix *mxic = (void *)p->onfi->vendor; + if (p->supports_set_get_features) { + set_bit(ONFI_FEATURE_ADDR_MXIC_PROTECTION, + p->get_feature_list); + set_bit(ONFI_FEATURE_ADDR_MXIC_PROTECTION, + p->set_feature_list); + } + if (mxic->reliability_func & MACRONIX_READ_RETRY_BIT) { chip->read_retries = MACRONIX_READ_RETRY_MODE + 1; chip->setup_read_retry = @@ -241,3 +252,39 @@ static int macronix_nand_init(struct nand_chip *chip) const struct nand_manufacturer_ops macronix_nand_manuf_ops = { .init = macronix_nand_init, }; + +int mxic_nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0}; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_LOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("Lock MXIC NAND all blocks failed, err:%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(mxic_nand_lock); + +int mxic_nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0}; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("Unlock MXIC NAND all blocks failed, err:%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(mxic_nand_unlock); diff --git a/include/linux/mfd/mxic-mx25f0a.h b/include/linux/mfd/mxic-mx25f0a.h index 5a8cfc7..cfce992 100644 --- a/include/linux/mfd/mxic-mx25f0a.h +++ b/include/linux/mfd/mxic-mx25f0a.h @@ -170,4 +170,7 @@ struct mx25f0a_mfd { void __iomem *dirmap; }; +int mxic_nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +int mxic_nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); + #endif // __MFD_MXIC_MX25F0A_H