All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lubomir Rintel <lkundrak@v3.sk>
To: u-boot@lists.denx.de
Subject: [PATCH RFC 14/20] nand/raw: Add Ingenic JZ4730 NAND flash driver
Date: Tue, 17 Nov 2020 22:00:12 +0100	[thread overview]
Message-ID: <20201117210018.751469-15-lkundrak@v3.sk> (raw)
In-Reply-To: <20201117210018.751469-1-lkundrak@v3.sk>

This adds driver for the NAND flash driver for JZ4730 SoC.

Can also be used in the NAND SPL that is too constrained (needs to fit in
4K) to be DT-driven.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
 drivers/mtd/nand/raw/Kconfig       |  10 ++
 drivers/mtd/nand/raw/Makefile      |   1 +
 drivers/mtd/nand/raw/jz4730_nand.c | 212 +++++++++++++++++++++++++++++
 3 files changed, 223 insertions(+)
 create mode 100644 drivers/mtd/nand/raw/jz4730_nand.c

diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 3cf3b14f05b..be6146a71f2 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -121,6 +121,16 @@ config NAND_DENALI_DT
 	  Enable the driver for NAND flash on platforms using a Denali NAND
 	  controller as a DT device.
 
+config NAND_JZ4730
+	bool "Support JZ4730 NAND controller"
+	select SYS_NAND_SELF_INIT
+	depends on DM_MTD && SOC_JZ4730
+	imply CMD_NAND
+	default y
+	help
+	  Enable this driver for NAND flash controllers available in
+	  Ingenic JZ4730 SoCs.
+
 config NAND_LPC32XX_SLC
 	bool "Support LPC32XX_SLC controller"
 	help
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index 24c51b6924a..8a4b18728eb 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+obj-$(CONFIG_NAND_JZ4730) += jz4730_nand.o
 obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
 obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
diff --git a/drivers/mtd/nand/raw/jz4730_nand.c b/drivers/mtd/nand/raw/jz4730_nand.c
new file mode 100644
index 00000000000..aa4631971fc
--- /dev/null
+++ b/drivers/mtd/nand/raw/jz4730_nand.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4730 NAND flash driver.
+ *
+ * Copyright (c) 2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <nand.h>
+
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/rawnand.h>
+
+#define EMC_SMCR3	0x1c
+#define EMC_NFCSR	0x50
+#define EMC_NFECC	0x54
+
+#define EMC_NFCSR_NFE	BIT(0)
+#define EMC_NFCSR_FCE	BIT(1)
+#define EMC_NFCSR_ECCE	BIT(2)
+#define EMC_NFCSR_ERST	BIT(3)
+#define EMC_NFCSR_RB	BIT(7)
+
+struct jz4730_nand_priv {
+	void __iomem *base;
+	struct nand_chip nand;
+};
+
+static inline void __iomem *mtd_to_base(struct mtd_info *mtd);
+
+static void jz4730_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, uint ctrl)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	void __iomem *base = mtd_to_base(mtd);
+	unsigned long IO_ADDR_W;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		IO_ADDR_W = (unsigned long)nand->IO_ADDR_W;
+
+		if (ctrl & NAND_NCE)
+			setbits_32(base + EMC_NFCSR, EMC_NFCSR_FCE);
+		else
+			clrbits_32(base + EMC_NFCSR, EMC_NFCSR_FCE);
+
+		IO_ADDR_W &= ~(BIT(18) | BIT(19));
+		if (ctrl & NAND_CLE)
+			IO_ADDR_W |= BIT(18);
+		if (ctrl & NAND_ALE)
+			IO_ADDR_W |= BIT(19);
+
+		nand->IO_ADDR_W = (void *)IO_ADDR_W;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, nand->IO_ADDR_W);
+}
+
+static int jz4730_nand_dev_ready(struct mtd_info *mtd)
+{
+	void __iomem *base = mtd_to_base(mtd);
+
+	return (readl(base + EMC_NFCSR) & EMC_NFCSR_RB) ? 1 : 0;
+}
+
+static void jz4730_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	unsigned long IO_ADDR_R = (unsigned long)nand->IO_ADDR_R;
+	unsigned long IO_ADDR_W = (unsigned long)nand->IO_ADDR_W;
+
+	if (chip == 0) {
+		IO_ADDR_R &= ~(BIT(16) | BIT(17));
+		IO_ADDR_W &= ~(BIT(16) | BIT(17));
+	} else if (chip == 1) {
+		IO_ADDR_R |= (BIT(16) | BIT(17));
+		IO_ADDR_W |= (BIT(16) | BIT(17));
+	}
+
+	nand->IO_ADDR_R = (void *)IO_ADDR_R;
+	nand->IO_ADDR_W = (void *)IO_ADDR_W;
+}
+
+static void jz4730_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	void __iomem *base = mtd_to_base(mtd);
+
+	setbits_32(base + EMC_NFCSR, EMC_NFCSR_ECCE | EMC_NFCSR_ERST);
+}
+
+static int jz4730_nand_ecc_calculate(struct mtd_info *mtd,
+				     const u_char *dat, u_char *ecc)
+{
+	void __iomem *base = mtd_to_base(mtd);
+	u32 val = readl(base + EMC_NFECC);
+
+	clrbits_32(base + EMC_NFCSR, EMC_NFCSR_ECCE);
+	val = readl(base + EMC_NFECC);
+	val = ~val | 0x00030000;
+
+	ecc[0] = val >> 8;
+	ecc[1] = val;
+	ecc[2] = val >> 16;
+
+	return 0;
+}
+
+void jz4730_nand_chip_init(struct nand_chip *nand)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	void __iomem *base = mtd_to_base(mtd);
+
+	if (!IS_ENABLED(SPL_BUILD) || IS_ENABLED(SPL_NAND_ECC)) {
+		nand->ecc.mode = NAND_ECC_HW;
+		nand->ecc.hwctl = jz4730_nand_ecc_hwctl;
+		nand->ecc.calculate = jz4730_nand_ecc_calculate;
+		nand->ecc.correct = nand_correct_data;
+		nand->ecc.bytes = 3;
+	}
+
+	nand->cmd_ctrl = jz4730_nand_cmd_ctrl;
+	nand->dev_ready = jz4730_nand_dev_ready;
+	nand->select_chip = jz4730_nand_select_chip;
+	nand->IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE;
+	nand->IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE;
+	nand->chip_delay = 20;
+
+	/* Enable the NAND functionality. */
+	setbits_32(base + EMC_NFCSR, EMC_NFCSR_NFE);
+
+	/* Nobody knows what does this do. */
+	writel(0x06644400, base + EMC_SMCR3);
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+
+static inline void __iomem *mtd_to_base(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	return container_of(nand, struct jz4730_nand_priv, nand)->base;
+}
+
+static int jz4730_nand_probe(struct udevice *dev)
+{
+	struct jz4730_nand_priv *priv = dev_get_priv(dev);
+	struct nand_chip *nand = &priv->nand;
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	ofnode node;
+	int ret;
+
+	priv->base = dev_remap_addr(dev->parent);
+	if (!priv->base)
+		return -EINVAL;
+
+	jz4730_nand_chip_init(nand);
+
+	ofnode_for_each_subnode(node, dev->node)
+		nand_set_flash_node(nand, node);
+
+	ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS);
+	if (ret)
+		return ret;
+
+	return nand_register(0, mtd);
+}
+
+static const struct udevice_id jz4730_nand_dt_ids[] = {
+	{ .compatible = "ingenic,jz4730-nand", },
+	{ }
+};
+
+U_BOOT_DRIVER(jz4730_nand_dt) = {
+	.name = "jz4730-nand",
+	.id = UCLASS_MTD,
+	.of_match = jz4730_nand_dt_ids,
+	.probe = jz4730_nand_probe,
+	.priv_auto_alloc_size = sizeof(struct jz4730_nand_priv),
+};
+
+void board_nand_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_MTD,
+					  DM_GET_DRIVER(jz4730_nand_dt),
+					  &dev);
+	if (ret && ret != -ENODEV)
+		pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
+}
+
+#else /* CONFIG_SPL_BUILD */
+
+static inline void __iomem *mtd_to_base(struct mtd_info *mtd)
+{
+	return (void __iomem *)KSEG1 + 0x13010000;
+}
+
+int board_nand_init(struct nand_chip *nand)
+{
+	jz4730_nand_chip_init(nand);
+	nand->read_buf = nand_read_buf;
+
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
-- 
2.28.0

  parent reply	other threads:[~2020-11-17 21:00 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-17 20:59 [PATCH RFC 00/20] MIPS: Add support for JZ4730 and Skytone Alpha 400 Lubomir Rintel
2020-11-17 20:59 ` [PATCH RFC 01/20] config: Remove CONFIG_SYS_ID_EEPROM Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 02/20] mtd: Allow building nand_spl_simple w/o SPL_NAND_ECC Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 03/20] cmd/mac: Don't build unless CONFIG_CMD_MAC is enabled Lubomir Rintel
2020-11-17 22:17   ` Daniel Schwierzeck
2020-11-17 21:00 ` [PATCH RFC 04/20] mips: Don't access CP0_EBASE on JZ47XX Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 05/20] ns16550: Turn on the UME bit if on ARCH_JZ47XX Lubomir Rintel
2020-11-17 22:29   ` Daniel Schwierzeck
2020-11-18  6:55     ` Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 06/20] clk: Add driver for Ingenic JZ4730 CGU Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 07/20] timer-uclass: Tolerate failure to get clock rate in pre_probe Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 08/20] timer: Add Ingenic JZ4730 timer driver Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 09/20] mmc: Default to JZ47XX_MMC=y on ARCH_JZ47XX Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 10/20] mmc/jz_mmc: Add a JZ4740 compatible string Lubomir Rintel
2020-11-18 13:56   ` Ezequiel Garcia
2020-11-17 21:00 ` [PATCH RFC 11/20] mmc/jz_mmc: Support wp-gpio/cd-gpio Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 12/20] pinctrl: Add Ingenic JZ4730 pin control and GPIO driver Lubomir Rintel
2020-11-17 22:39   ` Daniel Schwierzeck
2020-11-17 21:00 ` [PATCH RFC 13/20] nand: Use correct prototype of board_nand_init() with SPL_NAND_SIMPLE Lubomir Rintel
2020-11-17 21:00 ` Lubomir Rintel [this message]
2020-11-17 21:00 ` [PATCH RFC 15/20] watchdog: Add Ingenic JZ4730 watchdog timer driver Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 16/20] net: Add Ingenic JZ4730 Ethernet driver Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 17/20] mips: dts: Add Ingenic JZ4730 Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 18/20] mips/mach-jz47xx: Add Ingenic JZ4730 support Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 19/20] mips: dts: Add Skytone Alpha 400 Lubomir Rintel
2020-11-17 21:00 ` [PATCH RFC 20/20] board: " Lubomir Rintel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201117210018.751469-15-lkundrak@v3.sk \
    --to=lkundrak@v3.sk \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.