All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
@ 2021-05-25 21:49 Chris Morgan
  2021-05-25 21:49 ` [PATCH 1/5] spi: " Chris Morgan
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

Requesting comments for a proposed patchset for adding the Rockchip
serial flash controller to u-boot. The goal of these patches is to
enable it for the Odroid Go Advance so that it may eventually boot
exclusively from the SFC on mainline U-boot (I have tested this and
it works).

The specific help I need with this patch is:

1) I don't know the best way to upstream the XTX25F128B flash chip.
This chip uses a continuation code for the manufacturer ID, however I
cannot seem to find any way to actually read the continuation code.
There is a risk of this driver, used as-is, to collide with another
chip which has the same manufacturer ID with a different continuation
code.

2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
U-Boot sources) supports SPI NAND and chips of varying sizes, but my
implementation only permits me to test with a single 128Mb flash chip.
The driver itself does some checking on the bitlen in the routine
rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
I'm not sure if there is a better way to do this. Additionally, I have
to bit-shift the address written to the SFC as I suspect the value is
meant to be left justified, but I never tested it further.

Additionally, it might be worth mentioning but I noticed the Rockchip
BROM will only boot the TPL/SPL off of the SFC if I write it to address
0x10000. This is not documented and different than the address looked
at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
like the SD card driver I can confirm that if DMA is enabled at the SPL
stage A-TF seems to fail silently, then when Linux loads it hangs.
There is an ifdef to force FIFO mode only in the SPL stage.

Tested: Read (works)
	Write (works if you write to an erased sector)
	Erase (works)
	SPL Read (works if you edit the u-boot,spl-boot-order)

Chris Morgan (5):
  spi: rockchip_sfc: add support for Rockchip SFC
  rockchip: px30: Add support for using SFC
  rockchip: px30: add the serial flash controller
  mtd: spi-nor-ids: Add XTX XT25F128B
  rockchip: px30: add support for SFC for Odroid Go Advance

 arch/arm/dts/px30.dtsi                     |  38 ++
 arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
 arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
 arch/arm/mach-rockchip/px30/px30.c         |  64 ++
 drivers/mtd/spi/Kconfig                    |   6 +
 drivers/mtd/spi/spi-nor-ids.c              |   8 +
 drivers/spi/Kconfig                        |   8 +
 drivers/spi/Makefile                       |   1 +
 drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
 9 files changed, 926 insertions(+), 1 deletion(-)
 create mode 100644 drivers/spi/rockchip_sfc.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/5] spi: rockchip_sfc: add support for Rockchip SFC
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
@ 2021-05-25 21:49 ` Chris Morgan
  2021-05-25 21:49 ` [PATCH 2/5] rockchip: px30: Add support for using SFC Chris Morgan
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

This patch adds support for the Rockchip serial flash controller
found on the PX30 SoC. It should work the same for all SoCs which
use the same serial flash controller IP (referred to as the v3).

This is adapted from the SPI subsystem driver from Rockchip's BSP
U-boot package. I made a few small changes to get it working on
my board.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
 drivers/spi/Kconfig        |   8 +
 drivers/spi/Makefile       |   1 +
 drivers/spi/rockchip_sfc.c | 652 +++++++++++++++++++++++++++++++++++++
 3 files changed, 661 insertions(+)
 create mode 100644 drivers/spi/rockchip_sfc.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 1494c91763..bef36f2931 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -312,6 +312,14 @@ config RENESAS_RPC_SPI
 	  on Renesas RCar Gen3 SoCs. This uses driver model and requires a
 	  device tree binding to operate.
 
+config ROCKCHIP_SFC
+	bool "Rockchip SFC Driver"
+	help
+	  Enable the Rockchip SFC Driver for SPI NOR flash. This device is
+	  a limited purpose SPI controller for driving NOR flash on certain
+	  Rockchip SoCs. This uses driver model and requires a device tree
+	  binding to operate.
+
 config ROCKCHIP_SPI
 	bool "Rockchip SPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index cfe4fae1d4..f02e84b5f1 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_PIC32_SPI) += pic32_spi.o
 obj-$(CONFIG_PL022_SPI) += pl022_spi.o
 obj-$(CONFIG_SPI_QUP) += spi-qup.o
 obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
+obj-$(CONFIG_ROCKCHIP_SFC) += rockchip_sfc.o
 obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
 obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
 obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c
new file mode 100644
index 0000000000..d865fedc34
--- /dev/null
+++ b/drivers/spi/rockchip_sfc.c
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SFC Driver for Rockchip
+ *
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
+ * Yifeng.zhao, Software Engineering, <zhao0116@gmail.com>.
+ */
+
+#include <common.h>
+#include <bouncebuf.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <spi.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef SFC_DEBUG
+#define SFC_DBG printf
+#else
+#define SFC_DBG(args...)
+#endif
+
+struct rockchip_sfc_reg {
+	u32 ctrl;
+	u32 imr;
+	u32 iclr;
+	u32 ftlr;
+	u32 rcvr;
+	u32 ax;
+	u32 abit;
+	u32 isr;
+	u32 fsr;
+	u32 sr;
+	u32 risr;
+	u32 ver;
+	u32 reserved[20];
+	u32 dmatr;
+	u32 dmaaddr;
+	u32 len_ctrl;
+	u32 len_ext;
+	u32 reserved1[28];
+	u32 cmd;
+	u32 addr;
+	u32 data;
+};
+
+check_member(rockchip_sfc_reg, data, 0x108);
+
+/*SFC_CTRL*/
+#define SFC_DATA_WIDTH_SHIFT	12
+#define SFC_DATA_WIDTH_MASK	GENMASK(13, 12)
+#define SFC_ADDR_WIDTH_SHIFT	10
+#define SFC_ADDR_WIDTH_MASK	GENMASK(11, 10)
+#define SFC_CMD_WIDTH_SHIFT	8
+#define SFC_CMD_WIDTH_MASK	GENMASK(9, 8)
+#define SFC_DATA_SHIFT_NEGETIVE	BIT(1)
+
+/*SFC_CMD*/
+#define SFC_DUMMY_BITS_SHIFT	8
+#define SFC_RW_SHIFT		12
+#define SFC_WR			1
+#define SFC_RD			0
+#define SFC_ADDR_BITS_SHIFT	14
+#define SFC_ADDR_BITS_MASK	GENMASK(15, 14)
+#define SFC_ADDR_0BITS		0
+#define SFC_ADDR_24BITS		1
+#define SFC_ADDR_32BITS		2
+#define SFC_ADDR_XBITS		3
+#define SFC_TRB_SHIFT		(16)
+#define SFC_TRB_MASK		GENMASK(29, 16)
+
+/* Dma start trigger signal. Auto cleared after write */
+#define SFC_DMA_START		BIT(0)
+
+#define SFC_RESET		BIT(0)
+
+/*SFC_FSR*/
+#define SFC_RXLV_SHIFT		(16)
+#define SFC_RXLV_MASK		GENMASK(20, 16)
+#define SFC_TXLV_SHIFT		(8)
+#define SFC_TXLV_MASK		GENMASK(12, 8)
+#define SFC_RX_FULL		BIT(3)	/* rx fifo full */
+#define SFC_RX_EMPTY		BIT(2)	/* rx fifo empty */
+#define SFC_TX_EMPTY		BIT(1)	/* tx fifo empty */
+#define SFC_TX_FULL		BIT(0)	/* tx fifo full */
+
+#define SFC_BUSY		BIT(0)	/* sfc busy flag */
+
+/*SFC_RISR*/
+#define DMA_FINISH_INT		BIT(7)        /* dma interrupt */
+#define SPI_ERR_INT		BIT(6)        /* Nspi error interrupt */
+#define AHB_ERR_INT		BIT(5)        /* Ahb bus error interrupt */
+#define TRANS_FINISH_INT	BIT(4)        /* Transfer finish interrupt */
+#define TX_EMPTY_INT		BIT(3)        /* Tx fifo empty interrupt */
+#define TX_OF_INT		BIT(2)        /* Tx fifo overflow interrupt */
+#define RX_UF_INT		BIT(1)        /* Rx fifo underflow interrupt */
+#define RX_FULL_INT		BIT(0)        /* Rx fifo full interrupt */
+
+/* maximum address size permitted by SFC is 16k - 1 */
+#define SFC_MAX_TRB	(1024 << 3)
+
+#define SFC_MAX_RATE		(100 * 1000 * 1000)
+#define SFC_DEFAULT_RATE	(80 * 1000 * 1000)
+#define SFC_MIN_RATE		(10 * 1000 * 1000)
+
+enum rockchip_sfc_if_type {
+	IF_TYPE_STD,
+	IF_TYPE_DUAL,
+	IF_TYPE_QUAD,
+};
+
+struct rockchip_sfc_platdata {
+	s32 frequency;
+	fdt_addr_t base;
+};
+
+struct rockchip_sfc {
+	struct rockchip_sfc_reg *regbase;
+	struct clk clk;
+	unsigned int max_freq;
+	unsigned int mode;
+	unsigned int speed_hz;
+	u32 max_iosize;
+	u32 cmd;
+	u32 addr;
+	u8 addr_bits;
+	u8 addr_xbits_ext;
+	u8 dummy_bits;
+	u8 rw;
+	u32 trb;
+	bool fifo_mode;
+};
+
+static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus)
+{
+	struct rockchip_sfc_platdata *plat = dev_get_plat(bus);
+	struct rockchip_sfc *sfc = dev_get_priv(bus);
+	int ret;
+
+	plat->base = dev_read_addr(bus);
+	ret = clk_get_by_index(bus, 0, &sfc->clk);
+	if (ret < 0) {
+		printf("Could not get clock for %s: %d\n", bus->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sfc_probe(struct udevice *bus)
+{
+	struct rockchip_sfc_platdata *plat = dev_get_plat(bus);
+	struct rockchip_sfc *sfc = dev_get_priv(bus);
+	struct rockchip_sfc_reg *regs;
+	struct dm_spi_bus *dm_spi_bus;
+
+	dm_spi_bus = bus->uclass_priv_;
+	dm_spi_bus->max_hz = plat->frequency;
+	sfc->regbase = (struct rockchip_sfc_reg *)plat->base;
+	sfc->max_freq = SFC_MAX_RATE;
+	sfc->speed_hz = SFC_DEFAULT_RATE;
+	clk_set_rate(&sfc->clk, sfc->speed_hz);
+
+	regs = sfc->regbase;
+	sfc->max_iosize = SFC_MAX_TRB;
+
+/* DMA causes A-TF to fail, disabling it in SPL stage */
+#ifdef CONFIG_SPL_BUILD
+	sfc->fifo_mode = 1;
+#endif
+	return 0;
+}
+
+static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	int tbase = get_timer(0);
+	u32 rcvr;
+	int ret = 0;
+
+	writel(SFC_RESET, &regs->rcvr);
+	do {
+		rcvr = readl(&regs->rcvr);
+		if (get_timer(tbase) > 1000) {
+			printf("sfc reset timeout\n");
+			ret =  -ETIMEDOUT;
+			break;
+		}
+		udelay(1);
+	} while (rcvr);
+
+	writel(0xFFFFFFFF, &regs->iclr);
+
+	debug("sfc reset\n");
+
+	return ret;
+}
+
+/* The SFC_CTRL register is a global control register,
+ * when the controller is in busy state(SFC_SR),
+ * SFC_CTRL cannot be set.
+ */
+static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc,
+				  u32 timeout_ms)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	unsigned long tbase = get_timer(0);
+	u32 sr, fsr;
+
+	while (1) {
+		sr = readl(&regs->sr);
+		fsr = readl(&regs->fsr);
+		if ((fsr & SFC_TX_EMPTY) &&
+		    (fsr & SFC_RX_EMPTY) &&
+		    !(sr & SFC_BUSY))
+			break;
+		if (get_timer(tbase) > timeout_ms) {
+			printf("wait sfc idle timeout(sr:0x%08x fsr:0x%08x)\n",
+			       sr, fsr);
+			rockchip_sfc_reset(sfc);
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+
+	return 0;
+}
+
+static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc)
+{
+	int type = IF_TYPE_STD;
+
+	if (sfc->rw == SFC_WR) {
+		if (sfc->mode & SPI_TX_QUAD)
+			type = IF_TYPE_QUAD;
+		else if (sfc->mode & SPI_TX_DUAL)
+			type = IF_TYPE_DUAL;
+		else
+			type = IF_TYPE_STD;
+	} else {
+		if (sfc->mode & SPI_RX_QUAD)
+			type = IF_TYPE_QUAD;
+		else if (sfc->mode & SPI_RX_DUAL)
+			type = IF_TYPE_DUAL;
+		else
+			type = IF_TYPE_STD;
+	}
+
+	return type;
+}
+
+static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	u32 val;
+	u8 data_width = IF_TYPE_STD;
+
+	rockchip_sfc_wait_idle(sfc, 10);
+
+	if (sfc->addr_bits == SFC_ADDR_24BITS ||
+	    sfc->addr_bits == SFC_ADDR_32BITS)
+		data_width = rockchip_sfc_get_if_type(sfc);
+
+	SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits);
+	if (sfc->addr_bits == SFC_ADDR_XBITS)
+		writel(sfc->addr_xbits_ext - 1, &regs->abit);
+
+	val = 0x02;
+	val |= (data_width << SFC_DATA_WIDTH_SHIFT);
+
+	SFC_DBG("--- sfc.ctrl %x\n", val);
+	writel(val, &regs->ctrl);
+
+	val = sfc->cmd;
+	val |= (trb & 0x3fff) << SFC_TRB_SHIFT;
+	val |= sfc->rw << SFC_RW_SHIFT;
+	val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT;
+	val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT;
+
+	SFC_DBG("--- sfc.cmd %x\n", val);
+	writel(val, &regs->cmd);
+
+	if (sfc->addr_bits & SFC_ADDR_XBITS) {
+		SFC_DBG("--- sfc.addr %x\n", sfc->addr);
+		writel(sfc->addr, &regs->addr);
+	}
+}
+
+static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer,
+				 size_t trb)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	struct bounce_buffer bb;
+	unsigned int bb_flags;
+	int timeout = trb * 1000;
+	int ret = 0;
+	int risr;
+	unsigned long tbase;
+
+	if (sfc->rw == SFC_WR)
+		bb_flags = GEN_BB_READ;
+	else
+		bb_flags = GEN_BB_WRITE;
+
+	ret = bounce_buffer_start(&bb, buffer, trb, bb_flags);
+	if (ret)
+		return ret;
+
+	rockchip_sfc_setup_xfer(sfc, bb.len_aligned);
+
+	writel(0xFFFFFFFF, &regs->iclr);
+	writel((unsigned long)bb.bounce_buffer, &regs->dmaaddr);
+	writel(SFC_DMA_START, &regs->dmatr);
+
+	tbase = get_timer(0);
+	do {
+		udelay(1);
+		risr = readl(&regs->risr);
+		if (get_timer(tbase) > timeout) {
+			debug("dma timeout\n");
+			ret = -ETIMEDOUT;
+			break;
+		}
+	} while (!(risr & TRANS_FINISH_INT));
+
+	writel(0xFFFFFFFF, &regs->iclr);
+
+	bounce_buffer_stop(&bb);
+
+	return ret;
+}
+
+static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw,
+					u32 timeout)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	unsigned long tbase = get_timer(0);
+	u8 level;
+	u32 fsr;
+
+	do {
+		fsr = readl(&regs->fsr);
+		if (rw == SFC_WR)
+			level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT;
+		else
+			level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT;
+		if (get_timer(tbase) > timeout) {
+			printf("SFC FIFO Timeout\n");
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	} while (!level);
+
+	return level;
+}
+
+static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	u32 bytes = len & 0x3;
+	u32 words = len >> 2;
+	int tx_level = 0;
+	u32 val = 0;
+	u8 count;
+
+	while (words) {
+		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
+		if (tx_level <= 0)
+			return tx_level;
+		count = min(words, (u32)tx_level);
+		writesl(&regs->data, buf, count);
+		buf += count;
+		words -= count;
+	}
+
+	/* handle the last non 4byte aligned bytes */
+	if (bytes) {
+		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
+		if (tx_level <= 0)
+			return tx_level;
+		memcpy(&val, buf, bytes);
+		writel(val, &regs->data);
+	}
+
+	return 0;
+}
+
+static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
+{
+	struct rockchip_sfc_reg *regs = sfc->regbase;
+	u32 bytes = len & 0x3;
+	u32 words = len >> 2;
+	int rx_level = 0;
+	u32 count;
+	u32 val;
+
+	while (words) {
+		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
+		if (rx_level <= 0)
+			return rx_level;
+		count = min(words, (u32)rx_level);
+		readsl(&regs->data, buf, count);
+		buf += count;
+		words -= count;
+	}
+
+	/* handle the last non 4 bytes aligned bytes */
+	if (bytes) {
+		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
+		if (rx_level <= 0)
+			return rx_level;
+		val = readl(&regs->data);
+		memcpy(buf, &val, bytes);
+	}
+
+	return 0;
+}
+
+static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len)
+{
+	int ret = 0;
+
+	rockchip_sfc_setup_xfer(sfc, len);
+
+	if (len) {
+		if (sfc->rw == SFC_WR)
+			ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len);
+		else
+			ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len);
+	}
+
+	return ret;
+}
+
+static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset,
+			     void *buf, size_t len)
+{
+	u32 dma_trans;
+	u32 pio_trans;
+	u32 trb;
+	u32 bytes;
+	int ret;
+
+	if (sfc->fifo_mode) {
+		pio_trans = len;
+		while (pio_trans) {
+			trb = min_t(size_t, pio_trans, sfc->max_iosize);
+			ret = rockchip_sfc_pio_xfer(sfc, buf, trb);
+			if (ret < 0)
+				return ret;
+			pio_trans -= trb;
+	/* if I don't bit-shift this address, it doesn't work, but I haven't figured out why yet */
+			sfc->addr += (trb << 8);
+			buf += trb;
+		}
+
+	} else {
+		if (len >= ARCH_DMA_MINALIGN) {
+			bytes = len & (ARCH_DMA_MINALIGN - 1);
+			dma_trans = len - bytes;
+		} else {
+			dma_trans = 0;
+			bytes = len;
+		}
+
+		while (dma_trans) {
+			trb = min_t(size_t, dma_trans, sfc->max_iosize);
+			ret = rockchip_sfc_dma_xfer(sfc, buf, trb);
+			if (ret < 0)
+				return ret;
+			dma_trans -= trb;
+	/* bit shifting again */
+			sfc->addr += (trb << 8);
+			buf += trb;
+		}
+
+	/*
+	 * transfer the last non dma aligned byte by pio mode
+	 */
+		if (bytes)
+			ret = rockchip_sfc_pio_xfer(sfc, buf, bytes);
+	}
+
+	return 0;
+}
+
+static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset,
+			      void *buf, size_t len)
+{
+	if (len > sfc->max_iosize) {
+		printf("out of the max sfc trb");
+		return -EINVAL;
+	}
+
+	if (len && !(len & (ARCH_DMA_MINALIGN - 1)) && !sfc->fifo_mode)
+		return rockchip_sfc_dma_xfer(sfc, buf, len);
+	else
+		return rockchip_sfc_pio_xfer(sfc, buf, len);
+
+	return 0;
+}
+
+static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len)
+{
+	if (sfc->rw)
+		return rockchip_sfc_write(sfc, sfc->addr, buf, len);
+	else
+		return rockchip_sfc_read(sfc, sfc->addr, buf, len);
+}
+
+static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen,
+			     const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct rockchip_sfc *sfc = dev_get_priv(bus);
+	int len = bitlen >> 3;
+	u8 *pcmd = (u8 *)dout;
+	void *data_buf;
+	int ret = 0;
+
+	/* I haven't figured out why it's checking the command lengths, that said I only have
+	 * a 128Mb NOR flash chip to test against.
+	 */
+
+	if (flags & SPI_XFER_BEGIN) {
+		sfc->cmd = pcmd[0];
+		switch (len) {
+		case 6: /* Nor >16MB 0x6b dummy op */
+			sfc->addr_bits = SFC_ADDR_32BITS;
+			sfc->dummy_bits = 8;
+			sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24);
+			break;
+		case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */
+			if (sfc->cmd == 0x6b) {
+				sfc->addr_bits = SFC_ADDR_24BITS;
+				sfc->dummy_bits = 8;
+				sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
+			} else {
+				sfc->addr_bits = SFC_ADDR_32BITS;
+				sfc->dummy_bits = 0;
+				sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) |
+					    (pcmd[1] << 24);
+			}
+			break;
+		case 4: /* Nand erase and read, Nor <=16MB no dummy op */
+			sfc->addr_bits = SFC_ADDR_24BITS;
+			sfc->dummy_bits = 0;
+			sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
+			break;
+		case 3: /* Nand prog,  */
+			sfc->addr_bits = SFC_ADDR_XBITS;
+			sfc->addr_xbits_ext = 16;
+			sfc->dummy_bits = 0;
+			sfc->addr = pcmd[2] | pcmd[1] << 8;
+			break;
+		case 2: /* Nand read/write feature */
+			sfc->addr_bits = SFC_ADDR_XBITS;
+			sfc->addr_xbits_ext = 8;
+			sfc->dummy_bits = 0;
+			sfc->addr = pcmd[1];
+			break;
+		default: /* Nand/Nor Read/Write status */
+			sfc->addr_bits = SFC_ADDR_0BITS;
+			sfc->dummy_bits = 0;
+			sfc->addr = 0;
+			break;
+		}
+		SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd,
+			sfc->addr_bits, sfc->dummy_bits, sfc->addr);
+	}
+	if (flags & SPI_XFER_END) {
+		if (din) {
+			sfc->rw = SFC_RD;
+			data_buf = din;
+		} else {
+			sfc->rw = SFC_WR;
+			data_buf = (void *)dout;
+		}
+
+		if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
+			len = 0;
+			data_buf = NULL;
+		}
+
+		if (sfc->cmd == 0x9f && len == 4) {
+			/* SPI Nand read id */
+			sfc->addr_bits = SFC_ADDR_XBITS;
+			sfc->addr_xbits_ext = 8;
+			sfc->dummy_bits = 0;
+			sfc->addr = 0;
+			((u8 *)data_buf)[0] = 0xff;
+			ret = rockchip_sfc_do_xfer(sfc, &((u8 *)data_buf)[1], 3);
+		} else {
+			ret = rockchip_sfc_do_xfer(sfc, data_buf, len);
+		}
+	}
+
+	return ret;
+}
+
+static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
+{
+	struct rockchip_sfc *sfc = dev_get_priv(bus);
+
+	if (speed > sfc->max_freq)
+		speed = sfc->max_freq;
+
+	sfc->speed_hz = speed;
+	clk_set_rate(&sfc->clk, sfc->speed_hz);
+	SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk));
+
+	return 0;
+}
+
+static int rockchip_sfc_set_mode(struct udevice *bus, uint mode)
+{
+	struct rockchip_sfc *sfc = dev_get_priv(bus);
+
+	sfc->mode = mode;
+
+	return 0;
+}
+
+static const struct dm_spi_ops rockchip_sfc_ops = {
+	.xfer		= rockchip_sfc_xfer,
+	.set_speed	= rockchip_sfc_set_speed,
+	.set_mode	= rockchip_sfc_set_mode,
+};
+
+static const struct udevice_id rockchip_sfc_ids[] = {
+	{ .compatible = "rockchip,sfc" },
+	{ }
+};
+
+U_BOOT_DRIVER(rockchip_sfc_driver) = {
+	.name	= "rockchip_sfc",
+	.id	= UCLASS_SPI,
+	.of_match = rockchip_sfc_ids,
+	.ops	= &rockchip_sfc_ops,
+	.of_to_plat = rockchip_sfc_ofdata_to_platdata,
+	.plat_auto = sizeof(struct rockchip_sfc_platdata),
+	.priv_auto = sizeof(struct rockchip_sfc),
+	.probe	= rockchip_sfc_probe,
+};
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/5] rockchip: px30: Add support for using SFC
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
  2021-05-25 21:49 ` [PATCH 1/5] spi: " Chris Morgan
@ 2021-05-25 21:49 ` Chris Morgan
  2021-05-25 21:49 ` [PATCH 3/5] rockchip: px30: add the serial flash controller Chris Morgan
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

This patch adds support for setting the correct pin configuration
for the Rockchip Serial Flash Controller found on the PX30.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
 arch/arm/mach-rockchip/px30/px30.c | 64 ++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/arm/mach-rockchip/px30/px30.c b/arch/arm/mach-rockchip/px30/px30.c
index 6fcef63c1b..8674e815da 100644
--- a/arch/arm/mach-rockchip/px30/px30.c
+++ b/arch/arm/mach-rockchip/px30/px30.c
@@ -51,6 +51,57 @@ struct mm_region *mem_map = px30_mem_map;
 
 #define QOS_PRIORITY_LEVEL(h, l)	((((h) & 3) << 8) | ((l) & 3))
 
+/* GRF_GPIO1AL_IOMUX */
+enum {
+	GPIO1A3_SHIFT		= 12,
+	GPIO1A3_MASK		= 0xf << GPIO1A3_SHIFT,
+	GPIO1A3_GPIO		= 0,
+	GPIO1A3_FLASH_D3,
+	GPIO1A3_EMMC_D3,
+	GPIO1A3_SFC_SIO3,
+
+	GPIO1A2_SHIFT		= 8,
+	GPIO1A2_MASK		= 0xf << GPIO1A2_SHIFT,
+	GPIO1A2_GPIO		= 0,
+	GPIO1A2_FLASH_D2,
+	GPIO1A2_EMMC_D2,
+	GPIO1A2_SFC_SIO2,
+
+	GPIO1A1_SHIFT		= 4,
+	GPIO1A1_MASK		= 0xf << GPIO1A1_SHIFT,
+	GPIO1A1_GPIO		= 0,
+	GPIO1A1_FLASH_D1,
+	GPIO1A1_EMMC_D1,
+	GPIO1A1_SFC_SIO1,
+
+	GPIO1A0_SHIFT		= 0,
+	GPIO1A0_MASK		= 0xf << GPIO1A0_SHIFT,
+	GPIO1A0_GPIO		= 0,
+	GPIO1A0_FLASH_D0,
+	GPIO1A0_EMMC_D0,
+	GPIO1A0_SFC_SIO0,
+};
+
+/* GRF_GPIO1AH_IOMUX */
+enum {
+	GPIO1A4_SHIFT		= 0,
+	GPIO1A4_MASK		= 0xf << GPIO1A4_SHIFT,
+	GPIO1A4_GPIO		= 0,
+	GPIO1A4_FLASH_D4,
+	GPIO1A4_EMMC_D4,
+	GPIO1A4_SFC_CSN0,
+};
+
+/* GRF_GPIO1BL_IOMUX */
+enum {
+	GPIO1B1_SHIFT		= 4,
+	GPIO1B1_MASK		= 0xf << GPIO1B1_SHIFT,
+	GPIO1B1_GPIO		= 0,
+	GPIO1B1_FLASH_RDY,
+	GPIO1B1_EMMC_CLKOUT,
+	GPIO1B1_SFC_CLK,
+};
+
 /* GRF_GPIO1BH_IOMUX */
 enum {
 	GPIO1B7_SHIFT		= 12,
@@ -193,6 +244,19 @@ int arch_cpu_init(void)
 		     GPIO1D4_SDMMC_D2 << GPIO1D4_SHIFT);
 #endif
 
+#ifdef CONFIG_ROCKCHIP_SFC
+	rk_clrsetreg(&grf->gpio1al_iomux,
+		     GPIO1A3_MASK | GPIO1A2_MASK | GPIO1A1_MASK | GPIO1A0_MASK,
+		     GPIO1A3_SFC_SIO3 << GPIO1A3_SHIFT |
+		     GPIO1A2_SFC_SIO2 << GPIO1A2_SHIFT |
+		     GPIO1A1_SFC_SIO1 << GPIO1A1_SHIFT |
+		     GPIO1A0_SFC_SIO0 << GPIO1A0_SHIFT);
+	rk_clrsetreg(&grf->gpio1ah_iomux, GPIO1A4_MASK,
+		     GPIO1A4_SFC_CSN0 << GPIO1A4_SHIFT);
+	rk_clrsetreg(&grf->gpio1bl_iomux, GPIO1B1_MASK,
+		     GPIO1B1_SFC_CLK << GPIO1B1_SHIFT);
+#endif
+
 #endif
 
 	/* Enable PD_VO (default disable at reset) */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/5] rockchip: px30: add the serial flash controller
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
  2021-05-25 21:49 ` [PATCH 1/5] spi: " Chris Morgan
  2021-05-25 21:49 ` [PATCH 2/5] rockchip: px30: Add support for using SFC Chris Morgan
@ 2021-05-25 21:49 ` Chris Morgan
  2021-05-25 21:49 ` [PATCH 4/5] mtd: spi-nor-ids: Add XTX XT25F128B Chris Morgan
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

Add the serial flash controller to the devicetree for the PX30.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
 arch/arm/dts/px30.dtsi | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm/dts/px30.dtsi b/arch/arm/dts/px30.dtsi
index b6c79e7ed3..aaa8ae2235 100644
--- a/arch/arm/dts/px30.dtsi
+++ b/arch/arm/dts/px30.dtsi
@@ -960,6 +960,18 @@
 		status = "disabled";
 	};
 
+	sfc: sfc@ff3a0000 {
+		compatible = "rockchip,sfc";
+		reg = <0x0 0xff3a0000 0x0 0x4000>;
+		interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_SFC>, <&cru HCLK_SFC>;
+		clock-names = "clk_sfc", "hclk_sfc";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sfc_clk &sfc_cs &sfc_bus4>;
+		power-domains = <&power PX30_PD_MMC_NAND>;
+		status = "disabled";
+	};
+
 	gpu: gpu@ff400000 {
 		compatible = "rockchip,px30-mali", "arm,mali-bifrost";
 		reg = <0x0 0xff400000 0x0 0x4000>;
@@ -1926,6 +1938,32 @@
 			};
 		};
 
+		serial_flash {
+			sfc_bus4: sfc-bus4 {
+				rockchip,pins =
+					<1 RK_PA0 3 &pcfg_pull_none>,
+					<1 RK_PA1 3 &pcfg_pull_none>,
+					<1 RK_PA2 3 &pcfg_pull_none>,
+					<1 RK_PA3 3 &pcfg_pull_none>;
+			};
+
+			sfc_bus2: sfc-bus2 {
+				rockchip,pins =
+					<1 RK_PA0 3 &pcfg_pull_none>,
+					<1 RK_PA1 3 &pcfg_pull_none>;
+			};
+
+			sfc_cs: sfc-cs {
+				rockchip,pins =
+					<1 RK_PA4 3 &pcfg_pull_none>;
+			};
+
+			sfc_clk: sfc-clk {
+				rockchip,pins =
+					<1 RK_PB1 3 &pcfg_pull_none>;
+			};
+		};
+
 		lcdc {
 			lcdc_rgb_dclk_pin: lcdc-rgb-dclk-pin {
 				rockchip,pins =
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/5] mtd: spi-nor-ids: Add XTX XT25F128B
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
                   ` (2 preceding siblings ...)
  2021-05-25 21:49 ` [PATCH 3/5] rockchip: px30: add the serial flash controller Chris Morgan
@ 2021-05-25 21:49 ` Chris Morgan
  2021-05-25 21:49 ` [PATCH 5/5] rockchip: px30: add support for SFC for Odroid Go Advance Chris Morgan
  2021-06-01 12:22 ` [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Kever Yang
  5 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

Adds support for XT25F128B used on Odroid Go Advance. Unfortunately
this chip uses a continuation code which I cannot seem to parse, so
there are likely going to be collisions with chips that use the same
manufacturer/ID.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
 drivers/mtd/spi/Kconfig       | 6 ++++++
 drivers/mtd/spi/spi-nor-ids.c | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index f8db8e5213..8c797d1e03 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -162,6 +162,12 @@ config SPI_FLASH_XMC
 	  Add support for various XMC (Wuhan Xinxin Semiconductor
 	  Manufacturing Corp.) SPI flash chips (XM25xxx)
 
+config SPI_FLASH_XTX
+	bool "XTX SPI flash support"
+	help
+	  Add support for various XTX (XTX Technology Limited)
+	  SPI flash chips (XT25xxx).
+
 endif
 
 config SPI_FLASH_USE_4K_SECTORS
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 2b57797954..78166f408e 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -336,6 +336,14 @@ const struct flash_info spi_nor_ids[] = {
 	/* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */
 	{ INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+#endif
+#ifdef CONFIG_SPI_FLASH_XTX
+	/* XTX Technology (Shenzhen) Limited */
+	{
+		INFO("xt25f128b", 0x0b4018, 0, 64 * 1024, 256,
+		     SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+		     SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
 #endif
 	{ },
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/5] rockchip: px30: add support for SFC for Odroid Go Advance
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
                   ` (3 preceding siblings ...)
  2021-05-25 21:49 ` [PATCH 4/5] mtd: spi-nor-ids: Add XTX XT25F128B Chris Morgan
@ 2021-05-25 21:49 ` Chris Morgan
  2021-06-01 12:22 ` [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Kever Yang
  5 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-05-25 21:49 UTC (permalink / raw)
  To: u-boot
  Cc: heiko.stuebner, vigneshr, jagan, kever.yang, philipp.tomsich,
	sjg, Chris Morgan

From: Chris Morgan <macromorgan@hotmail.com>

The Odroid Go Advance uses a Rockchip Serial Flash Controller
with an XT25F128B SPI NOR flash chip. This adds support for both.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
 arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  8 ++++++++
 arch/arm/dts/rk3326-odroid-go2.dts         | 22 ++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi b/arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi
index 00767d2abd..7527a6ed0e 100644
--- a/arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi
+++ b/arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi
@@ -57,6 +57,14 @@
 	u-boot,spl-fifo-mode;
 };
 
+&sfc {
+	u-boot,dm-pre-reloc;
+};
+
+&spi_flash {
+	u-boot,dm-pre-reloc;
+};
+
 &uart1 {
 	clock-frequency = <24000000>;
 	u-boot,dm-pre-reloc;
diff --git a/arch/arm/dts/rk3326-odroid-go2.dts b/arch/arm/dts/rk3326-odroid-go2.dts
index 8cd4688c49..eb8a21ce66 100644
--- a/arch/arm/dts/rk3326-odroid-go2.dts
+++ b/arch/arm/dts/rk3326-odroid-go2.dts
@@ -48,6 +48,14 @@
 		};
 	};
 
+	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		spi0 = &sfc;
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		pinctrl-names = "default";
@@ -617,6 +625,20 @@
 	status = "okay";
 };
 
+&sfc {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sfc_clk &sfc_cs &sfc_bus2>;
+	status = "okay";
+
+	spi_flash: xt25f128b@0 {
+		reg = <0>;
+		compatible = "xtx,xt25f128b","jedec,spi-nor";
+		spi-max-frequency = <108000000>;
+	};
+};
+
 &tsadc {
 	status = "okay";
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
                   ` (4 preceding siblings ...)
  2021-05-25 21:49 ` [PATCH 5/5] rockchip: px30: add support for SFC for Odroid Go Advance Chris Morgan
@ 2021-06-01 12:22 ` Kever Yang
  2021-06-01 16:54   ` Chris Morgan
  5 siblings, 1 reply; 13+ messages in thread
From: Kever Yang @ 2021-06-01 12:22 UTC (permalink / raw)
  To: Chris Morgan, u-boot
  Cc: heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰, 林鼎强

Add Yifeng from rockchip.

Hi Chris,

     First of all, I think you should remain the origin author info in 
the signed-off.


Hi Yifeng,

     Please help to review this driver.


Thanks,

- Kever

On 2021/5/26 上午5:49, Chris Morgan wrote:
> From: Chris Morgan <macromorgan@hotmail.com>
>
> Requesting comments for a proposed patchset for adding the Rockchip
> serial flash controller to u-boot. The goal of these patches is to
> enable it for the Odroid Go Advance so that it may eventually boot
> exclusively from the SFC on mainline U-boot (I have tested this and
> it works).
>
> The specific help I need with this patch is:
>
> 1) I don't know the best way to upstream the XTX25F128B flash chip.
> This chip uses a continuation code for the manufacturer ID, however I
> cannot seem to find any way to actually read the continuation code.
> There is a risk of this driver, used as-is, to collide with another
> chip which has the same manufacturer ID with a different continuation
> code.
>
> 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
> U-Boot sources) supports SPI NAND and chips of varying sizes, but my
> implementation only permits me to test with a single 128Mb flash chip.
> The driver itself does some checking on the bitlen in the routine
> rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
> I'm not sure if there is a better way to do this. Additionally, I have
> to bit-shift the address written to the SFC as I suspect the value is
> meant to be left justified, but I never tested it further.
>
> Additionally, it might be worth mentioning but I noticed the Rockchip
> BROM will only boot the TPL/SPL off of the SFC if I write it to address
> 0x10000. This is not documented and different than the address looked
> at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
> like the SD card driver I can confirm that if DMA is enabled at the SPL
> stage A-TF seems to fail silently, then when Linux loads it hangs.
> There is an ifdef to force FIFO mode only in the SPL stage.
>
> Tested: Read (works)
> 	Write (works if you write to an erased sector)
> 	Erase (works)
> 	SPL Read (works if you edit the u-boot,spl-boot-order)
>
> Chris Morgan (5):
>    spi: rockchip_sfc: add support for Rockchip SFC
>    rockchip: px30: Add support for using SFC
>    rockchip: px30: add the serial flash controller
>    mtd: spi-nor-ids: Add XTX XT25F128B
>    rockchip: px30: add support for SFC for Odroid Go Advance
>
>   arch/arm/dts/px30.dtsi                     |  38 ++
>   arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
>   arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
>   arch/arm/mach-rockchip/px30/px30.c         |  64 ++
>   drivers/mtd/spi/Kconfig                    |   6 +
>   drivers/mtd/spi/spi-nor-ids.c              |   8 +
>   drivers/spi/Kconfig                        |   8 +
>   drivers/spi/Makefile                       |   1 +
>   drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
>   9 files changed, 926 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/spi/rockchip_sfc.c
>



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-01 12:22 ` [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Kever Yang
@ 2021-06-01 16:54   ` Chris Morgan
  2021-06-02  1:27     ` Kever Yang
  0 siblings, 1 reply; 13+ messages in thread
From: Chris Morgan @ 2021-06-01 16:54 UTC (permalink / raw)
  To: Kever Yang
  Cc: u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰, 林鼎强

On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
> Add Yifeng from rockchip.
> 
> Hi Chris,
> 
>     First of all, I think you should remain the origin author info in the
> signed-off.

Okay, I can do that. Please note that since I submitted this I was
asked to redo the upstream linux proposed driver to use the spi-mem
framework. I think for now honestly I'd like to abandon this patch
and resubmit a little later with one that is more or less the same
(using the spi-mem framework) as the Linux driver.

https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/

> 
> 
> Hi Yifeng,
> 
>     Please help to review this driver.
> 
> 
> Thanks,
> 
> - Kever
> 
> On 2021/5/26 上午5:49, Chris Morgan wrote:
> > From: Chris Morgan <macromorgan@hotmail.com>
> > 
> > Requesting comments for a proposed patchset for adding the Rockchip
> > serial flash controller to u-boot. The goal of these patches is to
> > enable it for the Odroid Go Advance so that it may eventually boot
> > exclusively from the SFC on mainline U-boot (I have tested this and
> > it works).
> > 
> > The specific help I need with this patch is:
> > 
> > 1) I don't know the best way to upstream the XTX25F128B flash chip.
> > This chip uses a continuation code for the manufacturer ID, however I
> > cannot seem to find any way to actually read the continuation code.
> > There is a risk of this driver, used as-is, to collide with another
> > chip which has the same manufacturer ID with a different continuation
> > code.
> > 
> > 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
> > U-Boot sources) supports SPI NAND and chips of varying sizes, but my
> > implementation only permits me to test with a single 128Mb flash chip.
> > The driver itself does some checking on the bitlen in the routine
> > rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
> > I'm not sure if there is a better way to do this. Additionally, I have
> > to bit-shift the address written to the SFC as I suspect the value is
> > meant to be left justified, but I never tested it further.
> > 
> > Additionally, it might be worth mentioning but I noticed the Rockchip
> > BROM will only boot the TPL/SPL off of the SFC if I write it to address
> > 0x10000. This is not documented and different than the address looked
> > at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
> > like the SD card driver I can confirm that if DMA is enabled at the SPL
> > stage A-TF seems to fail silently, then when Linux loads it hangs.
> > There is an ifdef to force FIFO mode only in the SPL stage.
> > 
> > Tested: Read (works)
> > 	Write (works if you write to an erased sector)
> > 	Erase (works)
> > 	SPL Read (works if you edit the u-boot,spl-boot-order)
> > 
> > Chris Morgan (5):
> >    spi: rockchip_sfc: add support for Rockchip SFC
> >    rockchip: px30: Add support for using SFC
> >    rockchip: px30: add the serial flash controller
> >    mtd: spi-nor-ids: Add XTX XT25F128B
> >    rockchip: px30: add support for SFC for Odroid Go Advance
> > 
> >   arch/arm/dts/px30.dtsi                     |  38 ++
> >   arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
> >   arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
> >   arch/arm/mach-rockchip/px30/px30.c         |  64 ++
> >   drivers/mtd/spi/Kconfig                    |   6 +
> >   drivers/mtd/spi/spi-nor-ids.c              |   8 +
> >   drivers/spi/Kconfig                        |   8 +
> >   drivers/spi/Makefile                       |   1 +
> >   drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
> >   9 files changed, 926 insertions(+), 1 deletion(-)
> >   create mode 100644 drivers/spi/rockchip_sfc.c
> > 
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-01 16:54   ` Chris Morgan
@ 2021-06-02  1:27     ` Kever Yang
  2021-06-04 13:42       ` 林鼎强
  0 siblings, 1 reply; 13+ messages in thread
From: Kever Yang @ 2021-06-02  1:27 UTC (permalink / raw)
  To: Chris Morgan
  Cc: u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰, 林鼎强

Hi Chris,

On 2021/6/2 上午12:54, Chris Morgan wrote:
> On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
>> Add Yifeng from rockchip.
>>
>> Hi Chris,
>>
>>      First of all, I think you should remain the origin author info in the
>> signed-off.
> Okay, I can do that. Please note that since I submitted this I was
> asked to redo the upstream linux proposed driver to use the spi-mem
> framework. I think for now honestly I'd like to abandon this patch
> and resubmit a little later with one that is more or less the same
> (using the spi-mem framework) as the Linux driver.


This sounds better, then we can wait for driver with new framework.

Thanks,

- Kever

>
> https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/
>
>>
>> Hi Yifeng,
>>
>>      Please help to review this driver.
>>
>>
>> Thanks,
>>
>> - Kever
>>
>> On 2021/5/26 上午5:49, Chris Morgan wrote:
>>> From: Chris Morgan <macromorgan@hotmail.com>
>>>
>>> Requesting comments for a proposed patchset for adding the Rockchip
>>> serial flash controller to u-boot. The goal of these patches is to
>>> enable it for the Odroid Go Advance so that it may eventually boot
>>> exclusively from the SFC on mainline U-boot (I have tested this and
>>> it works).
>>>
>>> The specific help I need with this patch is:
>>>
>>> 1) I don't know the best way to upstream the XTX25F128B flash chip.
>>> This chip uses a continuation code for the manufacturer ID, however I
>>> cannot seem to find any way to actually read the continuation code.
>>> There is a risk of this driver, used as-is, to collide with another
>>> chip which has the same manufacturer ID with a different continuation
>>> code.
>>>
>>> 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
>>> U-Boot sources) supports SPI NAND and chips of varying sizes, but my
>>> implementation only permits me to test with a single 128Mb flash chip.
>>> The driver itself does some checking on the bitlen in the routine
>>> rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
>>> I'm not sure if there is a better way to do this. Additionally, I have
>>> to bit-shift the address written to the SFC as I suspect the value is
>>> meant to be left justified, but I never tested it further.
>>>
>>> Additionally, it might be worth mentioning but I noticed the Rockchip
>>> BROM will only boot the TPL/SPL off of the SFC if I write it to address
>>> 0x10000. This is not documented and different than the address looked
>>> at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
>>> like the SD card driver I can confirm that if DMA is enabled at the SPL
>>> stage A-TF seems to fail silently, then when Linux loads it hangs.
>>> There is an ifdef to force FIFO mode only in the SPL stage.
>>>
>>> Tested: Read (works)
>>> 	Write (works if you write to an erased sector)
>>> 	Erase (works)
>>> 	SPL Read (works if you edit the u-boot,spl-boot-order)
>>>
>>> Chris Morgan (5):
>>>     spi: rockchip_sfc: add support for Rockchip SFC
>>>     rockchip: px30: Add support for using SFC
>>>     rockchip: px30: add the serial flash controller
>>>     mtd: spi-nor-ids: Add XTX XT25F128B
>>>     rockchip: px30: add support for SFC for Odroid Go Advance
>>>
>>>    arch/arm/dts/px30.dtsi                     |  38 ++
>>>    arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
>>>    arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
>>>    arch/arm/mach-rockchip/px30/px30.c         |  64 ++
>>>    drivers/mtd/spi/Kconfig                    |   6 +
>>>    drivers/mtd/spi/spi-nor-ids.c              |   8 +
>>>    drivers/spi/Kconfig                        |   8 +
>>>    drivers/spi/Makefile                       |   1 +
>>>    drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
>>>    9 files changed, 926 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/spi/rockchip_sfc.c
>>>
>>
>



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-02  1:27     ` Kever Yang
@ 2021-06-04 13:42       ` 林鼎强
  2021-06-04 14:40         ` Chris Morgan
  0 siblings, 1 reply; 13+ messages in thread
From: 林鼎强 @ 2021-06-04 13:42 UTC (permalink / raw)
  To: 杨凯, Chris Morgan
  Cc: u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰

[-- Attachment #1: Type: text/plain, Size: 5448 bytes --]


Hi Chris:

It's my honor to read about spi-rockchip-sfc driver from you, and your code has made a big difference to me.

Recently, we happen to be willing to submit the spi-mem rk sfc drivers, and we have tried some of them
in the internal process. Compared with the RK internal code, I have the following thoughts on your code:
1) Only support spi-nor, not support spi-nand
2) Only support rx_dual, tx_quad, not support tx_dual, tx_quad
3) Some of the code may be further simplified, such as "rockchip_sfc_register_all" 
4) Some of the logic may be further simplified, such as "rockchip_sfc_init" 
5) Doesn't support SFC ver4 ver5 althought witch is compatibled with lower version

In order to support all these features, I adjust the drivers on the basis of your code witch is attach to these mail, these
drivers have been test in linux 5.10 rk3568 board, and I'm still doing more strict tests.

So I suggest that we complete it together, or we may consider transferring it to me for submission If I have the honor.

I'm still unfamiliar with the community culture. I hope I didn't offend you. If I have, I'll say sorry in advance. 
Best wishes.



jon.lin@rock-chips.com
 
From: Kever Yang
Date: 2021-06-02 09:27
To: Chris Morgan
CC: u-boot; heiko.stuebner; vigneshr; jagan; sjg; Chris Morgan; 赵仪峰; 林鼎强
Subject: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
Hi Chris,
 
On 2021/6/2 上午12:54, Chris Morgan wrote:
> On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
>> Add Yifeng from rockchip.
>>
>> Hi Chris,
>>
>>      First of all, I think you should remain the origin author info in the
>> signed-off.
> Okay, I can do that. Please note that since I submitted this I was
> asked to redo the upstream linux proposed driver to use the spi-mem
> framework. I think for now honestly I'd like to abandon this patch
> and resubmit a little later with one that is more or less the same
> (using the spi-mem framework) as the Linux driver.
 
 
This sounds better, then we can wait for driver with new framework.
 
Thanks,
 
- Kever
 
>
> https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/
>
>>
>> Hi Yifeng,
>>
>>      Please help to review this driver.
>>
>>
>> Thanks,
>>
>> - Kever
>>
>> On 2021/5/26 上午5:49, Chris Morgan wrote:
>>> From: Chris Morgan <macromorgan@hotmail.com>
>>>
>>> Requesting comments for a proposed patchset for adding the Rockchip
>>> serial flash controller to u-boot. The goal of these patches is to
>>> enable it for the Odroid Go Advance so that it may eventually boot
>>> exclusively from the SFC on mainline U-boot (I have tested this and
>>> it works).
>>>
>>> The specific help I need with this patch is:
>>>
>>> 1) I don't know the best way to upstream the XTX25F128B flash chip.
>>> This chip uses a continuation code for the manufacturer ID, however I
>>> cannot seem to find any way to actually read the continuation code.
>>> There is a risk of this driver, used as-is, to collide with another
>>> chip which has the same manufacturer ID with a different continuation
>>> code.
>>>
>>> 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
>>> U-Boot sources) supports SPI NAND and chips of varying sizes, but my
>>> implementation only permits me to test with a single 128Mb flash chip.
>>> The driver itself does some checking on the bitlen in the routine
>>> rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
>>> I'm not sure if there is a better way to do this. Additionally, I have
>>> to bit-shift the address written to the SFC as I suspect the value is
>>> meant to be left justified, but I never tested it further.
>>>
>>> Additionally, it might be worth mentioning but I noticed the Rockchip
>>> BROM will only boot the TPL/SPL off of the SFC if I write it to address
>>> 0x10000. This is not documented and different than the address looked
>>> at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
>>> like the SD card driver I can confirm that if DMA is enabled at the SPL
>>> stage A-TF seems to fail silently, then when Linux loads it hangs.
>>> There is an ifdef to force FIFO mode only in the SPL stage.
>>>
>>> Tested: Read (works)
>>> Write (works if you write to an erased sector)
>>> Erase (works)
>>> SPL Read (works if you edit the u-boot,spl-boot-order)
>>>
>>> Chris Morgan (5):
>>>     spi: rockchip_sfc: add support for Rockchip SFC
>>>     rockchip: px30: Add support for using SFC
>>>     rockchip: px30: add the serial flash controller
>>>     mtd: spi-nor-ids: Add XTX XT25F128B
>>>     rockchip: px30: add support for SFC for Odroid Go Advance
>>>
>>>    arch/arm/dts/px30.dtsi                     |  38 ++
>>>    arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
>>>    arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
>>>    arch/arm/mach-rockchip/px30/px30.c         |  64 ++
>>>    drivers/mtd/spi/Kconfig                    |   6 +
>>>    drivers/mtd/spi/spi-nor-ids.c              |   8 +
>>>    drivers/spi/Kconfig                        |   8 +
>>>    drivers/spi/Makefile                       |   1 +
>>>    drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
>>>    9 files changed, 926 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/spi/rockchip_sfc.c
>>>
>>
>
 
 
 

[-- Attachment #2: spi-rockchip-sfc_modified_20210604.c --]
[-- Type: application/octet-stream, Size: 16869 bytes --]

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Rockchip Serial Flash Controller Driver
 *
 * Copyright (c) 2017-2021, Rockchip Inc.
 * Author: Shawn Lin <shawn.lin@rock-chips.com>
 *	   Chris Morgan <macroalpha82@gmail.com>
 *	   Jon Lin <Jon.lin@rock-chips.com>
 */

#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/spi/spi-mem.h>

/* System control */
#define SFC_CTRL			0x0
#define  SFC_CTRL_PHASE_SEL_NEGETIVE	BIT(1)
#define  SFC_CTRL_CMD_BITS_SHIFT	8
#define  SFC_CTRL_ADDR_BITS_SHIFT	10
#define  SFC_CTRL_DATA_BITS_SHIFT	12

/* Interrupt mask */
#define SFC_IMR				0x4
#define  SFC_IMR_RX_FULL		BIT(0)
#define  SFC_IMR_RX_UFLOW		BIT(1)
#define  SFC_IMR_TX_OFLOW		BIT(2)
#define  SFC_IMR_TX_EMPTY		BIT(3)
#define  SFC_IMR_TRAN_FINISH		BIT(4)
#define  SFC_IMR_BUS_ERR		BIT(5)
#define  SFC_IMR_NSPI_ERR		BIT(6)
#define  SFC_IMR_DMA			BIT(7)

/* Interrupt clear */
#define SFC_ICLR			0x8
#define  SFC_ICLR_RX_FULL		BIT(0)
#define  SFC_ICLR_RX_UFLOW		BIT(1)
#define  SFC_ICLR_TX_OFLOW		BIT(2)
#define  SFC_ICLR_TX_EMPTY		BIT(3)
#define  SFC_ICLR_TRAN_FINISH		BIT(4)
#define  SFC_ICLR_BUS_ERR		BIT(5)
#define  SFC_ICLR_NSPI_ERR		BIT(6)
#define  SFC_ICLR_DMA			BIT(7)

/* FIFO threshold level */
#define SFC_FTLR			0xc
#define  SFC_FTLR_TX_SHIFT		0
#define  SFC_FTLR_TX_MASK		0x1f
#define  SFC_FTLR_RX_SHIFT		8
#define  SFC_FTLR_RX_MASK		0x1f

/* Reset FSM and FIFO */
#define SFC_RCVR			0x10
#define  SFC_RCVR_RESET			BIT(0)

/* Enhanced mode */
#define SFC_AX				0x14

/* Address Bit number */
#define SFC_ABIT			0x18

/* Interrupt status */
#define SFC_ISR				0x1c
#define  SFC_ISR_RX_FULL_SHIFT		BIT(0)
#define  SFC_ISR_RX_UFLOW_SHIFT		BIT(1)
#define  SFC_ISR_TX_OFLOW_SHIFT		BIT(2)
#define  SFC_ISR_TX_EMPTY_SHIFT		BIT(3)
#define  SFC_ISR_TX_FINISH_SHIFT	BIT(4)
#define  SFC_ISR_BUS_ERR_SHIFT		BIT(5)
#define  SFC_ISR_NSPI_ERR_SHIFT		BIT(6)
#define  SFC_ISR_DMA_SHIFT		BIT(7)

/* FIFO status */
#define SFC_FSR				0x20
#define  SFC_FSR_TX_IS_FULL		BIT(0)
#define  SFC_FSR_TX_IS_EMPTY		BIT(1)
#define  SFC_FSR_RX_IS_EMPTY		BIT(2)
#define  SFC_FSR_RX_IS_FULL		BIT(3)
#define  SFC_FSR_TXLV_MASK		GENMASK(12, 8)
#define  SFC_FSR_TXLV_SHIFT		8
#define  SFC_FSR_RXLV_MASK		GENMASK(20, 16)
#define  SFC_FSR_RXLV_SHIFT		16

/* FSM status */
#define SFC_SR				0x24
#define  SFC_SR_IS_IDLE			0x0
#define  SFC_SR_IS_BUSY			0x1

/* Raw interrupt status */
#define SFC_RISR			0x28
#define  SFC_RISR_RX_FULL		BIT(0)
#define  SFC_RISR_RX_UNDERFLOW		BIT(1)
#define  SFC_RISR_TX_OVERFLOW		BIT(2)
#define  SFC_RISR_TX_EMPTY		BIT(3)
#define  SFC_RISR_TRAN_FINISH		BIT(4)
#define  SFC_RISR_BUS_ERR		BIT(5)
#define  SFC_RISR_NSPI_ERR		BIT(6)
#define  SFC_RISR_DMA			BIT(7)

/* Version */
#define SFC_VER				0x2C
#define  SFC_VER_3			0x3
#define  SFC_VER_4			0x4
#define  SFC_VER_5			0x5

/* Master trigger */
#define SFC_DMA_TRIGGER			0x80

/* Src or Dst addr for master */
#define SFC_DMA_ADDR			0x84

/* Length Control Register Extention 32GB */
#define SFC_LEN_CTRL			0x88
#define SFC_LEN_CTRL_TRB_SEL		1
#define SFC_LEN_EXT			0x8C

/* Command */
#define SFC_CMD				0x100
#define  SFC_CMD_IDX_SHIFT		0
#define  SFC_CMD_DUMMY_SHIFT		8
#define  SFC_CMD_DIR_SHIFT		12
#define  SFC_CMD_DIR_RD			0
#define  SFC_CMD_DIR_WR			1
#define  SFC_CMD_ADDR_SHIFT		14
#define  SFC_CMD_ADDR_0BITS		0
#define  SFC_CMD_ADDR_24BITS		1
#define  SFC_CMD_ADDR_32BITS		2
#define  SFC_CMD_ADDR_XBITS		3
#define  SFC_CMD_TRAN_BYTES_SHIFT	16
#define  SFC_CMD_CS_SHIFT		30

/* Address */
#define SFC_ADDR			0x104

/* Data */
#define SFC_DATA			0x108

/* The controller and documentation reports that it supports up to 4 CS
 * devices (0-3), however I have only been able to test a single CS (CS 0)
 * due to the configuration of my device.
 */
#define SFC_MAX_CHIPSELECT_NUM		4

/* The SFC can transfer max 16KB - 1 at one time
 * we set it to 15.5KB here for alignment.
 */
#define SFC_MAX_IOSIZE_VER3		(512 * 31)

#define SFC_MAX_IOSIZE_VER4		(0xFFFFFFFF)

/* DMA is only enabled for large data transmission */
#define SFC_DMA_TRANS_THRETHOLD		(0x40)

/* Maximum clock values from datasheet suggest keeping clock value under
 * 150MHz. No minimum or average value is suggested, but the U-boot BSP driver
 * has a minimum of 10MHz and a default of 80MHz which seems reasonable.
 */
#define SFC_MIN_SPEED_HZ		(10 * 1000 * 1000)
#define SFC_DEFAULT_SPEED_HZ		(80 * 1000 * 1000)
#define SFC_MAX_SPEED_HZ		(150 * 1000 * 1000)

struct rockchip_sfc {
	struct device *dev;
	void __iomem *regbase;
	struct clk *hclk;
	struct clk *clk;
	u32 frequency;
	/* virtual mapped addr for dma_buffer */
	void *buffer;
	dma_addr_t dma_buffer;
	struct completion cp;
	bool use_dma;
	u32 max_iosize;
};

static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
{
	int err;
	u32 status;

	writel_relaxed(SFC_RCVR_RESET, sfc->regbase + SFC_RCVR);

	err = readl_poll_timeout(sfc->regbase + SFC_RCVR, status,
				 !(status & SFC_RCVR_RESET), 20,
				 jiffies_to_usecs(HZ));
	if (err)
		dev_err(sfc->dev, "SFC reset never finished\n");

	/* Still need to clear the masked interrupt from RISR */
	writel_relaxed(0xFFFFFFFF, sfc->regbase + SFC_ICLR);

	dev_dbg(sfc->dev, "reset\n");

	return err;
}

static u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc)
{
	return  (u16)(readl(sfc->regbase + SFC_VER) & 0xffff);
}

static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc)
{
	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4)
		return SFC_MAX_IOSIZE_VER4;
	else
		return SFC_MAX_IOSIZE_VER3;
}

static int rockchip_sfc_init(struct rockchip_sfc *sfc)
{
	writel(0, sfc->regbase + SFC_CTRL);
	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4)
		writel(SFC_LEN_CTRL_TRB_SEL, sfc->regbase + SFC_LEN_CTRL);

	return 0;
}

static inline int rockchip_sfc_get_fifo_level(struct rockchip_sfc *sfc, int wr)
{
	u32 fsr = readl_relaxed(sfc->regbase + SFC_FSR);
	int level;

	if (wr)
		level = (fsr & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT;
	else
		level = (fsr & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT;

	return level;
}

static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr, u32 timeout)
{
	unsigned long deadline = jiffies + timeout;
	int level;

	while (!(level = rockchip_sfc_get_fifo_level(sfc, wr))) {
		if (time_after_eq(jiffies, deadline)) {
			dev_warn(sfc->dev, "%s fifo timeout\n", wr ? "write" : "read");
			return -ETIMEDOUT;
		}
		udelay(1);
	}

	return level;
}

static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
				   struct spi_mem *mem,
				   const struct spi_mem_op *op,
				   u32 len)
{
	u32 ctrl = 0, cmd = 0;

	/* set CMD */
	cmd = op->cmd.opcode;
	ctrl |= ((op->cmd.buswidth >> 1) << SFC_CTRL_CMD_BITS_SHIFT);

	/* set ADDR */
	if (op->addr.nbytes) {
		if (op->addr.nbytes == 4) {
			cmd |= SFC_CMD_ADDR_32BITS << SFC_CMD_ADDR_SHIFT;
		} else if (op->addr.nbytes == 3) {
			cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT;
		} else {
			cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT;
			writel_relaxed(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT);
		}

		ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT);
	}

	/* set DUMMY */
	if (op->dummy.nbytes) {
		if (op->dummy.buswidth == 4)
			cmd |= op->dummy.nbytes * 2 << SFC_CMD_DUMMY_SHIFT;
		else if (op->dummy.buswidth == 2)
			cmd |= op->dummy.nbytes * 4 << SFC_CMD_DUMMY_SHIFT;
		else
			cmd |= op->dummy.nbytes * 8 << SFC_CMD_DUMMY_SHIFT;
	}

	/* set DATA */
	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) /* Clear it if no data to transfer */
		writel(len, sfc->regbase + SFC_LEN_EXT);
	else
		cmd |= len << SFC_CMD_TRAN_BYTES_SHIFT;
	if (len) {
		if (op->data.dir == SPI_MEM_DATA_OUT)
			cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT;

		ctrl |= ((op->data.buswidth >> 1) << SFC_CTRL_DATA_BITS_SHIFT);
	}
	if (!len && op->addr.nbytes)
		cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT;

	/* set the Controller */
	ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE;
	cmd |= mem->spi->chip_select << SFC_CMD_CS_SHIFT;

	dev_dbg(sfc->dev, "addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n",
		op->addr.nbytes, op->addr.buswidth,
		op->dummy.nbytes, op->dummy.buswidth);
	dev_dbg(sfc->dev, "ctrl=%x cmd=%x addr=%llx len=%x\n",
		ctrl, cmd, op->addr.val, len);

	writel(ctrl, sfc->regbase + SFC_CTRL);
	writel(cmd, sfc->regbase + SFC_CMD);
	if (op->addr.nbytes)
		writel(op->addr.val, sfc->regbase + SFC_ADDR);

	return 0;
}

static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int len)
{
	u8 bytes = len & 0x3;
	u32 dwords;
	int tx_level;
	u32 write_words;
	u32 tmp = 0;

	dwords = len >> 2;
	while (dwords) {
		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, HZ);
		if (tx_level < 0)
			return tx_level;
		write_words = min_t(u32, tx_level, dwords);
		iowrite32_rep(sfc->regbase + SFC_DATA, buf, write_words);
		buf += write_words << 2;
		dwords -= write_words;
	}

	/* write the rest non word aligned bytes */
	if (bytes) {
		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, HZ);
		if (tx_level < 0)
			return tx_level;
		memcpy(&tmp, buf, bytes);
		writel(tmp, sfc->regbase + SFC_DATA);
	}

	return len;
}

static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len)
{
	u8 bytes = len & 0x3;
	u32 dwords;
	u8 read_words;
	int rx_level;
	int tmp;

	/* word aligned access only */
	dwords = len >> 2;
	while (dwords) {
		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, HZ);
		if (rx_level < 0)
			return rx_level;
		read_words = min_t(u32, rx_level, dwords);
		ioread32_rep(sfc->regbase + SFC_DATA, buf, read_words);
		buf += read_words << 2;
		dwords -= read_words;
	}

	/* read the rest non word aligned bytes */
	if (bytes) {
		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, HZ);
		if (rx_level < 0)
			return rx_level;
		tmp = readl_relaxed(sfc->regbase + SFC_DATA);
		memcpy(buf, &tmp, bytes);
	}

	return len;
}

static int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t dma_buf, size_t len)
{
	u32 reg;
	int err = 0;

	init_completion(&sfc->cp);

	writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR);

	/* Enable transfer complete interrupt */
	reg = readl(sfc->regbase + SFC_IMR);
	reg &= ~SFC_IMR_DMA;
	writel(reg, sfc->regbase + SFC_IMR);
	writel((u32)dma_buf, sfc->regbase + SFC_DMA_ADDR);
	writel(0x1, sfc->regbase + SFC_DMA_TRIGGER);

	/* Wait for the interrupt. */
	if (!wait_for_completion_timeout(&sfc->cp, msecs_to_jiffies(2000))) {
		dev_err(sfc->dev, "DMA wait for transfer finish timeout\n");
		err = -ETIMEDOUT;
	}

	writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR);
	/* Disable transfer finish interrupt */
	reg = readl(sfc->regbase + SFC_IMR);
	reg |= SFC_IMR_DMA;
	writel(reg, sfc->regbase + SFC_IMR);

	return len;
}

static int rockchip_sfc_xfer_data_poll(struct rockchip_sfc *sfc, const struct spi_mem_op *op, u32 len)
{
	dev_dbg(sfc->dev, "xfer_poll len=%x\n", len);

	if (op->data.dir == SPI_MEM_DATA_OUT)
		return rockchip_sfc_write_fifo(sfc, op->data.buf.out, len);
	else
		return rockchip_sfc_read_fifo(sfc, op->data.buf.in, len);
}

static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, const struct spi_mem_op *op, u32 len)
{
	int ret;

	dev_dbg(sfc->dev, "xfer_dma len=%x\n", len);

	if (op->data.dir == SPI_MEM_DATA_OUT) {
		memcpy_toio(sfc->buffer, op->data.buf.out, len);
		ret = rockchip_sfc_fifo_transfer_dma(sfc, sfc->dma_buffer, len);
	} else {
		ret = rockchip_sfc_fifo_transfer_dma(sfc, sfc->dma_buffer, len);
		memcpy_fromio(op->data.buf.in, sfc->buffer, len);
	}

	return ret;
}

static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us)
{
	int ret = 0;
	u32 status;

	ret = readl_poll_timeout(sfc->regbase + SFC_SR, status,
				 !(status & SFC_SR_IS_BUSY),
				 20, timeout_us);
	if (ret) {
		dev_err(sfc->dev, "wait sfc idle timeout\n");
		rockchip_sfc_reset(sfc);

		ret = -EIO;
	}

	return ret;
}

static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
	struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
	u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize);
	int ret;

	if (mem->spi->max_speed_hz != sfc->frequency) {
		if (clk_set_rate(sfc->clk, mem->spi->max_speed_hz))
			return ret;
		dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n",
			sfc->frequency, clk_get_rate(sfc->clk));
	}

	rockchip_sfc_xfer_setup(sfc, mem, op, len);
	if (len) {
		if (likely(sfc->use_dma) && !(len & 0x3) && len >= SFC_DMA_TRANS_THRETHOLD)
			ret = rockchip_sfc_xfer_data_dma(sfc, op, len);
		else
			ret = rockchip_sfc_xfer_data_poll(sfc, op, len);

		if (ret != len) {
			dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir);

			return -EIO;
		}
	}

	return rockchip_sfc_xfer_done(sfc, 100000);
}

static const char *rockchip_sfc_get_name(struct spi_mem *mem)
{
	return devm_kasprintf(&mem->spi->dev, GFP_KERNEL, "%s.%d", dev_name(&mem->spi->dev), mem->spi->chip_select);
}

static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = {
	.exec_op = rockchip_sfc_exec_mem_op,
	.get_name = rockchip_sfc_get_name,
};

static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
{
	struct rockchip_sfc *sfc = dev_id;
	u32 reg;

	reg = readl(sfc->regbase + SFC_RISR);

	/* Clear interrupt */
	writel_relaxed(reg, sfc->regbase + SFC_ICLR);

	if (reg & SFC_RISR_DMA)
		complete(&sfc->cp);

	return IRQ_HANDLED;
}

static int rockchip_sfc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct spi_master *master;
	struct resource *res;
	struct rockchip_sfc *sfc;
	int ret;

	master = spi_alloc_master(&pdev->dev, sizeof(*sfc));
	if (!master) {
		dev_err(&pdev->dev, "spi_alloc_master failed\n");
		return -ENOMEM;
	}

	master->mem_ops = &rockchip_sfc_mem_ops;
	master->dev.of_node = pdev->dev.of_node;
	master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL;
	master->min_speed_hz = SFC_MIN_SPEED_HZ;
	master->max_speed_hz = SFC_MAX_SPEED_HZ;
	master->num_chipselect = SFC_MAX_CHIPSELECT_NUM;

	sfc = spi_master_get_devdata(master);
	sfc->dev = dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	sfc->regbase = devm_ioremap_resource(dev, res);
	if (IS_ERR(sfc->regbase))
		return PTR_ERR(sfc->regbase);

	sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc");
	if (IS_ERR(sfc->clk)) {
		dev_err(&pdev->dev, "Failed to get sfc interface clk\n");
		return PTR_ERR(sfc->clk);
	}

	sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc");
	if (IS_ERR(sfc->hclk)) {
		dev_err(&pdev->dev, "Failed to get sfc ahb clk\n");
		return PTR_ERR(sfc->hclk);
	}

	sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
					      "rockchip,sfc-no-dma");

	if (sfc->use_dma) {
		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
		if (ret) {
			dev_warn(dev, "Unable to set dma mask\n");
			return ret;
		}

		sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3,
						  &sfc->dma_buffer,
						  GFP_KERNEL);
		if (!sfc->buffer)
			return -ENOMEM;
	}

	ret = clk_prepare_enable(sfc->hclk);
	if (ret) {
		dev_err(&pdev->dev, "Failed to enable ahb clk\n");
		goto err_hclk;
	}

	ret = clk_prepare_enable(sfc->clk);
	if (ret) {
		dev_err(&pdev->dev, "Failed to enable interface clk\n");
		goto err_clk;
	}

	/* Find the irq */
	ret = platform_get_irq(pdev, 0);
	if (ret < 0) {
		dev_err(dev, "Failed to get the irq\n");
		goto err_irq;
	}

	ret = devm_request_irq(dev, ret, rockchip_sfc_irq_handler,
			       0, pdev->name, sfc);
	if (ret) {
		dev_err(dev, "Failed to request irq\n");
		goto err_irq;
	}

	ret = rockchip_sfc_init(sfc);
	if (ret)
		goto err_irq;

	sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);

	ret = devm_spi_register_master(dev, master);
	if (ret)
		goto err_irq;

	return 0;

err_irq:
	clk_disable_unprepare(sfc->clk);
err_clk:
	clk_disable_unprepare(sfc->hclk);
err_hclk:
	return ret;
}

static int rockchip_sfc_remove(struct platform_device *pdev)
{
	struct rockchip_sfc *sfc = platform_get_drvdata(pdev);

	clk_disable_unprepare(sfc->clk);
	clk_disable_unprepare(sfc->hclk);
	return 0;
}

static const struct of_device_id rockchip_sfc_dt_ids[] = {
	{ .compatible = "rockchip,px30-sfc"},
	{ .compatible = "rockchip,rk3036-sfc"},
	{ .compatible = "rockchip,rk3308-sfc"},
	{ .compatible = "rockchip,rk3326-sfc"},
	{ .compatible = "rockchip,rk3568-sfc"},
	{ .compatible = "rockchip,rv1126-sfc"},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids);

static struct platform_driver rockchip_sfc_driver = {
	.driver = {
		.name	= "rockchip-sfc",
		.of_match_table = rockchip_sfc_dt_ids,
	},
	.probe	= rockchip_sfc_probe,
	.remove	= rockchip_sfc_remove,
};
module_platform_driver(rockchip_sfc_driver);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Rockchip Serial Flash Controller Driver");
MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");

[-- Attachment #3: spi-rockchip-sfc.c --]
[-- Type: application/octet-stream, Size: 21684 bytes --]

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Rockchip Serial Flash Controller Driver
 *
 * Copyright (c) 2017, Rockchip Inc.
 * Author: Shawn Lin <shawn.lin@rock-chips.com>
 */

#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/spi/spi-mem.h>

/* System control */
#define SFC_CTRL			0x0
#define  SFC_CTRL_COMMON_BITS_1		0x0
#define  SFC_CTRL_COMMON_BITS_2		0x1
#define  SFC_CTRL_COMMON_BITS_4		0x2
#define  SFC_CTRL_DATA_BITS_SHIFT	12
#define  SFC_CTRL_ADDR_BITS_SHIFT	10
#define  SFC_CTRL_CMD_BITS_SHIFT	8
#define  SFC_CTRL_PHASE_SEL_NEGETIVE	BIT(1)

/* Interrupt mask */
#define SFC_IMR				0x4
#define  SFC_IMR_RX_FULL		BIT(0)
#define  SFC_IMR_RX_UFLOW		BIT(1)
#define  SFC_IMR_TX_OFLOW		BIT(2)
#define  SFC_IMR_TX_EMPTY		BIT(3)
#define  SFC_IMR_TRAN_FINISH		BIT(4)
#define  SFC_IMR_BUS_ERR		BIT(5)
#define  SFC_IMR_NSPI_ERR		BIT(6)
#define  SFC_IMR_DMA			BIT(7)

/* Interrupt clear */
#define SFC_ICLR			0x8
#define  SFC_ICLR_RX_FULL		BIT(0)
#define  SFC_ICLR_RX_UFLOW		BIT(1)
#define  SFC_ICLR_TX_OFLOW		BIT(2)
#define  SFC_ICLR_TX_EMPTY		BIT(3)
#define  SFC_ICLR_TRAN_FINISH		BIT(4)
#define  SFC_ICLR_BUS_ERR		BIT(5)
#define  SFC_ICLR_NSPI_ERR		BIT(6)
#define  SFC_ICLR_DMA			BIT(7)

/* FIFO threshold level */
#define SFC_FTLR			0xc
#define  SFC_FTLR_TX_SHIFT		0
#define  SFC_FTLR_TX_MASK		0x1f
#define  SFC_FTLR_RX_SHIFT		8
#define  SFC_FTLR_RX_MASK		0x1f

/* Reset FSM and FIFO */
#define SFC_RCVR			0x10
#define  SFC_RCVR_RESET			BIT(0)

/* Enhanced mode */
#define SFC_AX				0x14

/* Address Bit number */
#define SFC_ABIT			0x18

/* Interrupt status */
#define SFC_ISR				0x1c
#define  SFC_ISR_RX_FULL_SHIFT		BIT(0)
#define  SFC_ISR_RX_UFLOW_SHIFT		BIT(1)
#define  SFC_ISR_TX_OFLOW_SHIFT		BIT(2)
#define  SFC_ISR_TX_EMPTY_SHIFT		BIT(3)
#define  SFC_ISR_TX_FINISH_SHIFT	BIT(4)
#define  SFC_ISR_BUS_ERR_SHIFT		BIT(5)
#define  SFC_ISR_NSPI_ERR_SHIFT		BIT(6)
#define  SFC_ISR_DMA_SHIFT		BIT(7)

/* FIFO status */
#define SFC_FSR				0x20
#define  SFC_FSR_TX_IS_FULL		BIT(0)
#define  SFC_FSR_TX_IS_EMPTY		BIT(1)
#define  SFC_FSR_RX_IS_EMPTY		BIT(2)
#define  SFC_FSR_RX_IS_FULL		BIT(3)
#define  SFC_FSR_TXLV_MASK		GENMASK(12, 8)
#define  SFC_FSR_TXLV_SHIFT		8
#define  SFC_FSR_RXLV_MASK		GENMASK(20, 16)
#define  SFC_FSR_RXLV_SHIFT		16

/* FSM status */
#define SFC_SR				0x24
#define  SFC_SR_IS_IDLE			0x0
#define  SFC_SR_IS_BUSY			0x1

/* Raw interrupt status */
#define SFC_RISR			0x28
#define  SFC_RISR_RX_FULL		BIT(0)
#define  SFC_RISR_RX_UNDERFLOW		BIT(1)
#define  SFC_RISR_TX_OVERFLOW		BIT(2)
#define  SFC_RISR_TX_EMPTY		BIT(3)
#define  SFC_RISR_TRAN_FINISH		BIT(4)
#define  SFC_RISR_BUS_ERR		BIT(5)
#define  SFC_RISR_NSPI_ERR		BIT(6)
#define  SFC_RISR_DMA			BIT(7)

/* Master trigger */
#define SFC_DMA_TRIGGER			0x80

/* Src or Dst addr for master */
#define SFC_DMA_ADDR			0x84

/* Command */
#define SFC_CMD				0x100
#define  SFC_CMD_IDX_SHIFT		0
#define  SFC_CMD_DUMMY_SHIFT		8
#define  SFC_CMD_DIR_RD			0
#define  SFC_CMD_DIR_WR			1
#define  SFC_CMD_DIR_SHIFT		12
#define  SFC_CMD_ADDR_ZERO		(0x0 << 14)
#define  SFC_CMD_ADDR_24BITS		(0x1 << 14)
#define  SFC_CMD_ADDR_32BITS		(0x2 << 14)
#define  SFC_CMD_ADDR_FRS		(0x3 << 14)
#define  SFC_CMD_TRAN_BYTES_SHIFT	16
#define  SFC_CMD_CS_SHIFT		30

/* Address */
#define SFC_ADDR			0x104

/* Data */
#define SFC_DATA			0x108

/* The controller and documentation reports that it supports up to 4 CS
 * devices (0-3), however I have only been able to test a single CS (CS 0)
 * due to the configuration of my device.
 */
#define SFC_MAX_CHIPSELECT_NUM		4

/* The SFC can transfer max 16KB - 1 at one time
 * we set it to 15.5KB here for alignment.
 */
#define SFC_MAX_TRANS_BYTES		(512 * 31)

/* Maximum clock values from datasheet suggest keeping clock value under
 * 150MHz. No minimum or average value is suggested, but the U-boot BSP driver
 * has a minimum of 10MHz and a default of 80MHz which seems reasonable.
 */
#define SFC_MIN_SPEED_HZ		(10 * 1000 * 1000)
#define SFC_DEFAULT_SPEED_HZ		(80 * 1000 * 1000)
#define SFC_MAX_SPEED_HZ		(150 * 1000 * 1000)

#define SFC_CMD_DUMMY(x) \
	((x) << SFC_CMD_DUMMY_SHIFT)

enum rockchip_sfc_iftype {
	IF_TYPE_STD,
	IF_TYPE_DUAL,
	IF_TYPE_QUAD,
};

struct rockchip_sfc;
struct rockchip_sfc_chip_priv {
	u8 cs;
	u32 clk_rate;
	struct rockchip_sfc *sfc;
};

struct rockchip_sfc {
	struct device *dev;
	void __iomem *regbase;
	struct clk *hclk;
	struct clk *clk;
	/* virtual mapped addr for dma_buffer */
	void *buffer;
	dma_addr_t dma_buffer;
	struct completion cp;
	struct rockchip_sfc_chip_priv flash[SFC_MAX_CHIPSELECT_NUM];
	u8 num_chip;
	bool use_dma;
};

static int rockchip_sfc_get_if_type(const struct spi_mem_op *op,
				    struct rockchip_sfc *sfc)
{
	if (op->data.buswidth == 2)
		return IF_TYPE_DUAL;
	else if (op->data.buswidth == 4)
		return IF_TYPE_QUAD;
	else if (op->data.buswidth == 1)
		return IF_TYPE_STD;

	dev_err(sfc->dev, "unsupported SPI read mode\n");

	return -EINVAL;
}

static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
{
	int err;
	u32 status;

	writel_relaxed(SFC_RCVR_RESET, sfc->regbase + SFC_RCVR);

	err = readl_poll_timeout(sfc->regbase + SFC_RCVR, status,
				 !(status & SFC_RCVR_RESET), 20,
				 jiffies_to_usecs(HZ));
	if (err)
		dev_err(sfc->dev, "SFC reset never finished\n");

	/* Still need to clear the masked interrupt from RISR */
	writel_relaxed(SFC_ICLR_RX_FULL | SFC_ICLR_RX_UFLOW |
		       SFC_ICLR_TX_OFLOW | SFC_ICLR_TX_EMPTY |
		       SFC_ICLR_TRAN_FINISH | SFC_ICLR_BUS_ERR |
		       SFC_ICLR_NSPI_ERR | SFC_ICLR_DMA,
		       sfc->regbase + SFC_ICLR);

	dev_dbg(sfc->dev, "reset\n");

	return err;
}

static int rockchip_sfc_init(struct rockchip_sfc *sfc)
{
	int err;

	err = clk_set_rate(sfc->clk, SFC_DEFAULT_SPEED_HZ);
	if (err)
		return err;

	err = rockchip_sfc_reset(sfc);
	if (err)
		return err;

	/* Mask all eight interrupts */
	writel_relaxed(0xff, sfc->regbase + SFC_IMR);

	writel_relaxed(SFC_CTRL_PHASE_SEL_NEGETIVE, sfc->regbase + SFC_CTRL);

	return 0;
}

static inline int rockchip_sfc_get_fifo_level(struct rockchip_sfc *sfc, int wr)
{
	u32 fsr = readl_relaxed(sfc->regbase + SFC_FSR);
	int level;

	if (wr)
		level = (fsr & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT;
	else
		level = (fsr & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT;

	return level;
}

static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr, u32 timeout)
{
	unsigned long deadline = jiffies + timeout;
	int level;

	while (!(level = rockchip_sfc_get_fifo_level(sfc, wr))) {
		if (time_after_eq(jiffies, deadline)) {
			dev_warn(sfc->dev, "%s fifo timeout\n", wr ? "write" : "read");
			return -ETIMEDOUT;
		}
		udelay(1);
	}

	return level;
}

/* The SFC_CTRL register is a global control register,
 * when the controller is in busy state(SFC_SR),
 * SFC_CTRL cannot be set.
 */
static void rockchip_sfc_wait_idle(struct rockchip_sfc *sfc, u32 timeout_us)
{
	u32 status;
	int ret;

	ret = readl_poll_timeout(sfc->regbase + SFC_SR, status,
				 !(status & SFC_SR_IS_BUSY),
				 20, timeout_us);
	if (ret) {
		dev_err(sfc->dev, "wait sfc idle timeout\n");
		rockchip_sfc_reset(sfc);
	}
}

static void rockchip_sfc_setup_ctrl(struct rockchip_sfc *sfc)
{
	u32 reg;

	reg = IF_TYPE_STD << SFC_CTRL_DATA_BITS_SHIFT;
	reg |= IF_TYPE_STD << SFC_CTRL_ADDR_BITS_SHIFT;
	reg |= IF_TYPE_STD << SFC_CTRL_CMD_BITS_SHIFT;
	reg |= SFC_CTRL_PHASE_SEL_NEGETIVE;

	rockchip_sfc_wait_idle(sfc, 10000);

	writel_relaxed(reg, sfc->regbase + SFC_CTRL);
}

static int rockchip_sfc_op_reg(struct rockchip_sfc_chip_priv *priv,
			       u8 opcode, int len, u8 optype)
{
	struct rockchip_sfc *sfc = priv->sfc;
	u32 reg;

	rockchip_sfc_setup_ctrl(sfc);

	reg = opcode << SFC_CMD_IDX_SHIFT;
	reg |= len << SFC_CMD_TRAN_BYTES_SHIFT;
	reg |= priv->cs << SFC_CMD_CS_SHIFT;
	reg |= optype << SFC_CMD_DIR_SHIFT;
	writel_relaxed(reg, sfc->regbase + SFC_CMD);

	return 0;
}

static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int len)
{
	u8 bytes = len & 0x3;
	u32 dwords;
	int tx_level;
	u32 write_words;
	u32 tmp = 0;

	dwords = len >> 2;
	while (dwords) {
		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, HZ);
		if (tx_level < 0)
			return tx_level;
		write_words = min_t(u32, tx_level, dwords);
		iowrite32_rep(sfc->regbase + SFC_DATA, buf, write_words);
		buf += write_words << 2;
		dwords -= write_words;
		}

	/* write the rest non word aligned bytes */
	if (bytes) {
		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, HZ);
		if (tx_level < 0)
			return tx_level;
		memcpy(&tmp, buf, bytes);
		writel_relaxed(tmp, sfc->regbase + SFC_DATA);
	}

	return len;
}

static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len)
{
	u8 bytes = len & 0x3;
	u32 dwords;
	u8 read_words;
	int rx_level;
	int tmp;

	/* word aligned access only */
	dwords = len >> 2;
	while (dwords) {
		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, HZ);
		if (rx_level < 0)
			return rx_level;
		read_words = min_t(u32, rx_level, dwords);
		ioread32_rep(sfc->regbase + SFC_DATA, buf, read_words);
		buf += read_words << 2;
		dwords -= read_words;
		}

	/* read the rest non word aligned bytes */
	if (bytes) {
		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, HZ);
		if (rx_level < 0)
			return rx_level;
		tmp = readl_relaxed(sfc->regbase + SFC_DATA);
		memcpy(buf, &tmp, bytes);
	}

	return len;
}

static int rockchip_sfc_read_reg(struct rockchip_sfc_chip_priv *priv,
				 const struct spi_mem_op *op)
{
	struct rockchip_sfc *sfc = priv->sfc;
	int ret;
	int trans;
	size_t n_rx = op->data.nbytes;
	u8 opcode = op->cmd.opcode;
	u8 *rxbuf = op->data.buf.in;

	trans = min_t(int, n_rx, SFC_MAX_TRANS_BYTES);
	ret = rockchip_sfc_op_reg(priv, opcode, trans, SFC_CMD_DIR_RD);
	if (ret)
		return ret;

	ret = rockchip_sfc_read_fifo(sfc, rxbuf, trans);
	if (ret < 0)
		return ret;

	return 0;
}

static int rockchip_sfc_write_reg(struct rockchip_sfc_chip_priv *priv,
				  const struct spi_mem_op *op)
{
	struct rockchip_sfc *sfc = priv->sfc;
	int ret;
	size_t n_tx = op->data.nbytes;
	u8 opcode = op->cmd.opcode;
	const u8 *txbuf = op->data.buf.out;

	ret = rockchip_sfc_op_reg(priv, opcode, n_tx, SFC_CMD_DIR_WR);
	if (ret)
		return ret;
	ret = rockchip_sfc_write_fifo(sfc, txbuf, n_tx);
	if (ret < 0)
		return ret;

	return 0;
}

static int rockchip_sfc_setup_transfer(struct rockchip_sfc_chip_priv *priv,
				       const struct spi_mem_op *op,
				       loff_t from_to, size_t len, u8 op_type)
{
	struct rockchip_sfc *sfc = priv->sfc;
	u8 if_type = IF_TYPE_STD;
	u8 addr_width = op->addr.nbytes;
	u8 read_dummy_bits = op->dummy.nbytes << 3;
	u32 reg;

	if (op_type == SFC_CMD_DIR_RD)
		if_type = rockchip_sfc_get_if_type(op, sfc);

	rockchip_sfc_wait_idle(sfc, 10000);

	writel_relaxed((if_type << SFC_CTRL_DATA_BITS_SHIFT) |
		       (IF_TYPE_STD << SFC_CTRL_ADDR_BITS_SHIFT) |
		       (IF_TYPE_STD << SFC_CTRL_CMD_BITS_SHIFT) |
		       SFC_CTRL_PHASE_SEL_NEGETIVE,
		       sfc->regbase + SFC_CTRL);

	reg = op->cmd.opcode << SFC_CMD_IDX_SHIFT;

	reg |= op_type << SFC_CMD_DIR_SHIFT;
	reg |= (addr_width == 4) ?
		SFC_CMD_ADDR_32BITS : SFC_CMD_ADDR_24BITS;

	reg |= priv->cs << SFC_CMD_CS_SHIFT;
	reg |= len << SFC_CMD_TRAN_BYTES_SHIFT;

	if (op_type == SFC_CMD_DIR_RD)
		reg |= SFC_CMD_DUMMY(read_dummy_bits);

	writel_relaxed(reg, sfc->regbase + SFC_CMD);
	writel_relaxed(from_to, sfc->regbase + SFC_ADDR);

	return 0;
}

static int rockchip_sfc_do_dma_transfer(struct rockchip_sfc_chip_priv *priv,
					const struct spi_mem_op *op, loff_t from_to,
					dma_addr_t dma_buf, size_t len, u8 op_type)
{
	struct rockchip_sfc *sfc = priv->sfc;
	u32 reg;
	int err = 0;

	init_completion(&sfc->cp);

	writel_relaxed(SFC_ICLR_RX_FULL | SFC_ICLR_RX_UFLOW |
		       SFC_ICLR_TX_OFLOW | SFC_ICLR_TX_EMPTY |
		       SFC_ICLR_TRAN_FINISH | SFC_ICLR_BUS_ERR |
		       SFC_ICLR_NSPI_ERR | SFC_ICLR_DMA,
		       sfc->regbase + SFC_ICLR);

	/* Enable transfer complete interrupt */
	reg = readl_relaxed(sfc->regbase + SFC_IMR);
	reg &= ~SFC_IMR_TRAN_FINISH;
	writel_relaxed(reg, sfc->regbase + SFC_IMR);

	err = rockchip_sfc_setup_transfer(priv, op, from_to, len, op_type);
	if (err < 0)
		return err;

	writel_relaxed(dma_buf, sfc->regbase + SFC_DMA_ADDR);

	/*
	 * Start dma but note that the sfc->dma_buffer is derived from
	 * dmam_alloc_coherent so we don't actually need any sync operations
	 * for coherent dma memory.
	 */
	writel(0x1, sfc->regbase + SFC_DMA_TRIGGER);

	/* Wait for the interrupt. */
	if (!wait_for_completion_timeout(&sfc->cp, msecs_to_jiffies(2000))) {
		dev_err(sfc->dev, "DMA wait for transfer finish timeout\n");
		err = -ETIMEDOUT;
	}

	writel_relaxed(SFC_ICLR_RX_FULL | SFC_ICLR_RX_UFLOW |
		       SFC_ICLR_TX_OFLOW | SFC_ICLR_TX_EMPTY |
		       SFC_ICLR_TRAN_FINISH | SFC_ICLR_BUS_ERR |
		       SFC_ICLR_NSPI_ERR | SFC_ICLR_DMA,
		       sfc->regbase + SFC_ICLR);
	/* Disable transfer finish interrupt */
	reg = readl_relaxed(sfc->regbase + SFC_IMR);
	reg |= SFC_IMR_TRAN_FINISH;
	writel_relaxed(reg, sfc->regbase + SFC_IMR);

	if (err) {
		rockchip_sfc_reset(sfc);
		return err;
	}

	return 0;
}

static inline int rockchip_sfc_pio_write(struct rockchip_sfc *sfc, u_char *buf,
					 size_t len)
{
	return rockchip_sfc_write_fifo(sfc, buf, len);
}

static inline int rockchip_sfc_pio_read(struct rockchip_sfc *sfc, u_char *buf,
					size_t len)
{
	return rockchip_sfc_read_fifo(sfc, buf, len);
}

static int rockchip_sfc_pio_transfer(struct rockchip_sfc_chip_priv *priv,
				     const struct spi_mem_op *op, loff_t from_to, size_t len,
				     u_char *buf, u8 op_type)
{
	struct rockchip_sfc *sfc = priv->sfc;
	size_t trans;
	int ret;

	trans = min_t(size_t, SFC_MAX_TRANS_BYTES, len);
	ret = rockchip_sfc_setup_transfer(priv, op, from_to, trans, op_type);
	if (ret < 0)
		return ret;

	if (op_type == SFC_CMD_DIR_WR)
		ret = rockchip_sfc_pio_write(sfc, buf, trans);
	else
		ret = rockchip_sfc_pio_read(sfc, buf, trans);

	return ret;
}

static int rockchip_sfc_dma_transfer(struct rockchip_sfc_chip_priv *priv,
				     const struct spi_mem_op *op, loff_t from_to, size_t len,
				     u_char *buf, u8 op_type)
{
	struct rockchip_sfc *sfc = priv->sfc;
	size_t trans;
	int ret;

	trans = min_t(size_t, SFC_MAX_TRANS_BYTES, len);

	if (op_type == SFC_CMD_DIR_WR)
		memcpy(sfc->buffer, buf, trans);

	ret = rockchip_sfc_do_dma_transfer(priv, op, from_to, sfc->dma_buffer,
					   trans, op_type);
	if (ret) {
		dev_warn(sfc->dev, "DMA timeout\n");
		return ret;
	}

	if (op_type == SFC_CMD_DIR_RD)
		memcpy(buf, sfc->buffer, trans);

	return trans;
}

static ssize_t rockchip_sfc_do_rd_wr(struct rockchip_sfc_chip_priv *priv,
				     const struct spi_mem_op *op, loff_t from_to, size_t len,
				     u_char *buf, u32 op_type)
{
	struct rockchip_sfc *sfc = priv->sfc;

	/* DMA can only handle word aligned transfer chunks */
	if (likely(sfc->use_dma) && !(len & 0x3))
		return rockchip_sfc_dma_transfer(priv, op, from_to, len, buf, op_type);
	else
		return rockchip_sfc_pio_transfer(priv, op, from_to, len, buf, op_type);
}

static ssize_t rockchip_sfc_read(struct rockchip_sfc_chip_priv *priv,
				 const struct spi_mem_op *op)
{
	loff_t from = op->addr.val;
	size_t len = op->data.nbytes;
	u_char *read_buf = op->data.buf.in;

	return rockchip_sfc_do_rd_wr(priv, op, from, len, read_buf, SFC_CMD_DIR_RD);
}

static ssize_t rockchip_sfc_write(struct rockchip_sfc_chip_priv *priv,
				  const struct spi_mem_op *op)
{
	loff_t to = op->addr.val;
	size_t len = op->data.nbytes;
	const u_char *write_buf = op->data.buf.out;

	return rockchip_sfc_do_rd_wr(priv, op, to, len, (u_char *)write_buf, SFC_CMD_DIR_WR);
}

static int rockchip_sfc_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
{
	struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
	struct rockchip_sfc_chip_priv *priv = &sfc->flash[mem->spi->chip_select];

	if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
		if (!op->addr.nbytes)
			return rockchip_sfc_read_reg(priv, op);

		return rockchip_sfc_read(priv, op);
	}

	if (!op->addr.nbytes || !op->data.buf.out)
		return rockchip_sfc_write_reg(priv, op);

	return rockchip_sfc_write(priv, op);
}

static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
	struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
	struct rockchip_sfc_chip_priv *priv = &sfc->flash[mem->spi->chip_select];
	int ret;

	ret = clk_set_rate(sfc->clk, priv->clk_rate);
	if (ret)
		return ret;

	ret = rockchip_sfc_mem_process(mem, op);
	if (ret < 0) {
		dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
		return ret;
	}

	return 0;
}

static const char *rockchip_sfc_get_name(struct spi_mem *mem)
{
	struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
	struct device *dev = sfc->dev;

	return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), mem->spi->chip_select);
}

static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = {
	.exec_op = rockchip_sfc_exec_mem_op,
	.get_name = rockchip_sfc_get_name,
};

static int rockchip_sfc_register(struct device_node *np,
				 struct rockchip_sfc *sfc)
{
	struct device *dev = sfc->dev;
	int ret;

	ret = of_property_read_u8(np, "reg", &sfc->flash[sfc->num_chip].cs);
	if (ret) {
		dev_err(dev, "No reg property for %s\n",
			np->full_name);
		return ret;
	}

	ret = of_property_read_u32(np, "spi-max-frequency",
				   &sfc->flash[sfc->num_chip].clk_rate);
	if (ret) {
		dev_err(dev, "No spi-max-frequency property for %s\n",
			np->full_name);
		return ret;
	}

	sfc->flash[sfc->num_chip].sfc = sfc;
	sfc->num_chip++;
	return 0;
}

static int rockchip_sfc_register_all(struct rockchip_sfc *sfc)
{
	struct device *dev = sfc->dev;
	struct device_node *np;
	int ret;

	for_each_available_child_of_node(dev->of_node, np) {
		ret = rockchip_sfc_register(np, sfc);
		if (ret)
			dev_err(dev, "Failed to register all chips\n");
			return ret;

		if (sfc->num_chip >= SFC_MAX_CHIPSELECT_NUM) {
			dev_warn(dev, "Exceeds the max cs limitation\n");
			break;
		}
	}

	return 0;
}

static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
{
	struct rockchip_sfc *sfc = dev_id;
	u32 reg;

	reg = readl(sfc->regbase + SFC_RISR);

	/* Clear interrupt */
	writel_relaxed(reg, sfc->regbase + SFC_ICLR);

	if (reg & SFC_RISR_TRAN_FINISH)
		complete(&sfc->cp);

	return IRQ_HANDLED;
}

static int rockchip_sfc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct spi_master *master;
	struct resource *res;
	struct rockchip_sfc *sfc;
	int ret;

	master = spi_alloc_master(&pdev->dev, sizeof(*sfc));
	if (!master) {
		dev_err(&pdev->dev, "spi_alloc_master failed\n");
		return -ENOMEM;
	}

	master->mem_ops = &rockchip_sfc_mem_ops;
	master->dev.of_node = pdev->dev.of_node;
	master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
	master->min_speed_hz = SFC_MIN_SPEED_HZ;
	master->max_speed_hz = SFC_MAX_SPEED_HZ;

	sfc = spi_master_get_devdata(master);
	sfc->dev = dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	sfc->regbase = devm_ioremap_resource(dev, res);
	if (IS_ERR(sfc->regbase))
		return PTR_ERR(sfc->regbase);

	sfc->clk = devm_clk_get(&pdev->dev, "sfc");
	if (IS_ERR(sfc->clk)) {
		dev_err(&pdev->dev, "Failed to get sfc interface clk\n");
		return PTR_ERR(sfc->clk);
	}

	sfc->hclk = devm_clk_get(&pdev->dev, "ahb");
	if (IS_ERR(sfc->hclk)) {
		dev_err(&pdev->dev, "Failed to get sfc ahb clk\n");
		return PTR_ERR(sfc->hclk);
	}

	sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
					      "rockchip,sfc-no-dma");

	if (sfc->use_dma) {
		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
		if (ret) {
			dev_warn(dev, "Unable to set dma mask\n");
			return ret;
		}

		sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_TRANS_BYTES,
						  &sfc->dma_buffer,
						  GFP_KERNEL);
		if (!sfc->buffer)
			return -ENOMEM;
	}

	ret = clk_prepare_enable(sfc->hclk);
	if (ret) {
		dev_err(&pdev->dev, "Failed to enable ahb clk\n");
		goto err_hclk;
	}

	ret = clk_prepare_enable(sfc->clk);
	if (ret) {
		dev_err(&pdev->dev, "Failed to enable interface clk\n");
		goto err_clk;
	}

	/* Find the irq */
	ret = platform_get_irq(pdev, 0);
	if (ret < 0) {
		dev_err(dev, "Failed to get the irq\n");
		goto err_irq;
	}

	ret = devm_request_irq(dev, ret, rockchip_sfc_irq_handler,
			       0, pdev->name, sfc);
	if (ret) {
		dev_err(dev, "Failed to request irq\n");
		goto err_irq;
	}

	sfc->num_chip = 0;
	ret = rockchip_sfc_init(sfc);
	if (ret)
		goto err_irq;

	ret = rockchip_sfc_register_all(sfc);
	if (ret)
		goto err_irq;

	ret = devm_spi_register_master(dev, master);
	if (ret)
		goto err_irq;

	return 0;

err_irq:
	clk_disable_unprepare(sfc->clk);
err_clk:
	clk_disable_unprepare(sfc->hclk);
err_hclk:
	return ret;
}

static int rockchip_sfc_remove(struct platform_device *pdev)
{
	struct rockchip_sfc *sfc = platform_get_drvdata(pdev);

	clk_disable_unprepare(sfc->clk);
	clk_disable_unprepare(sfc->hclk);
	return 0;
}

static const struct of_device_id rockchip_sfc_dt_ids[] = {
	{ .compatible = "rockchip,rk3036-sfc"},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids);

static struct platform_driver rockchip_sfc_driver = {
	.driver = {
		.name	= "rockchip-sfc",
		.of_match_table = rockchip_sfc_dt_ids,
	},
	.probe	= rockchip_sfc_probe,
	.remove	= rockchip_sfc_remove,
};
module_platform_driver(rockchip_sfc_driver);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Rockchip Serial Flash Controller Driver");
MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-04 13:42       ` 林鼎强
@ 2021-06-04 14:40         ` Chris Morgan
  2021-06-05  7:37           ` Jon Lin
  0 siblings, 1 reply; 13+ messages in thread
From: Chris Morgan @ 2021-06-04 14:40 UTC (permalink / raw)
  To: 林鼎强
  Cc: 杨凯,
	u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰

On Fri, Jun 04, 2021 at 09:42:18PM +0800, 林鼎强 wrote:
> 
> Hi Chris:
> 
> It's my honor to read about spi-rockchip-sfc driver from you, and your code has made a big difference to me.
> 
> Recently, we happen to be willing to submit the spi-mem rk sfc drivers, and we have tried some of them
> in the internal process. Compared with the RK internal code, I have the following thoughts on your code:
> 1) Only support spi-nor, not support spi-nand
> 2) Only support rx_dual, tx_quad, not support tx_dual, tx_quad
> 3) Some of the code may be further simplified, such as "rockchip_sfc_register_all" 
> 4) Some of the logic may be further simplified, such as "rockchip_sfc_init" 
> 5) Doesn't support SFC ver4 ver5 althought witch is compatibled with lower version
> 
> In order to support all these features, I adjust the drivers on the basis of your code witch is attach to these mail, these
> drivers have been test in linux 5.10 rk3568 board, and I'm still doing more strict tests.
> 
> So I suggest that we complete it together, or we may consider transferring it to me for submission If I have the honor.
> 
> I'm still unfamiliar with the community culture. I hope I didn't offend you. If I have, I'll say sorry in advance. 
> Best wishes.

I am absolutely fine with you taking this on, and will be happy to help
you in any way I can. I only started working on support for this
because I wanted it supported in both Linux and U-Boot mainline, and
didn't see any progress being made (so I thought I would do it myself).
Basically, my goal all along has been to ensure the Odroid Go Advance
is fully supported in mainline Linux (and U-boot), and that requires
we get the audio (done), SFC (in progress), crypto, battery, charger,
and everything else (done) supported.

I trust you are better able to develop/test this than I am, as I only
have access to some technical documents and a single PX30 based device
to test this on.

Please CC me when you are ready to submit upstream to Linux and U-boot
and I will happily test it on my hardware. If you don't have a U-boot
driver in progress let me know and I can start working on one.

Thank you.

> 
> 
> 
> jon.lin@rock-chips.com
>  
> From: Kever Yang
> Date: 2021-06-02 09:27
> To: Chris Morgan
> CC: u-boot; heiko.stuebner; vigneshr; jagan; sjg; Chris Morgan; 赵仪峰; 林鼎强
> Subject: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
> Hi Chris,
>  
> On 2021/6/2 上午12:54, Chris Morgan wrote:
> > On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
> >> Add Yifeng from rockchip.
> >>
> >> Hi Chris,
> >>
> >>      First of all, I think you should remain the origin author info in the
> >> signed-off.
> > Okay, I can do that. Please note that since I submitted this I was
> > asked to redo the upstream linux proposed driver to use the spi-mem
> > framework. I think for now honestly I'd like to abandon this patch
> > and resubmit a little later with one that is more or less the same
> > (using the spi-mem framework) as the Linux driver.
>  
>  
> This sounds better, then we can wait for driver with new framework.
>  
> Thanks,
>  
> - Kever
>  
> >
> > https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/
> >
> >>
> >> Hi Yifeng,
> >>
> >>      Please help to review this driver.
> >>
> >>
> >> Thanks,
> >>
> >> - Kever
> >>
> >> On 2021/5/26 上午5:49, Chris Morgan wrote:
> >>> From: Chris Morgan <macromorgan@hotmail.com>
> >>>
> >>> Requesting comments for a proposed patchset for adding the Rockchip
> >>> serial flash controller to u-boot. The goal of these patches is to
> >>> enable it for the Odroid Go Advance so that it may eventually boot
> >>> exclusively from the SFC on mainline U-boot (I have tested this and
> >>> it works).
> >>>
> >>> The specific help I need with this patch is:
> >>>
> >>> 1) I don't know the best way to upstream the XTX25F128B flash chip.
> >>> This chip uses a continuation code for the manufacturer ID, however I
> >>> cannot seem to find any way to actually read the continuation code.
> >>> There is a risk of this driver, used as-is, to collide with another
> >>> chip which has the same manufacturer ID with a different continuation
> >>> code.
> >>>
> >>> 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
> >>> U-Boot sources) supports SPI NAND and chips of varying sizes, but my
> >>> implementation only permits me to test with a single 128Mb flash chip.
> >>> The driver itself does some checking on the bitlen in the routine
> >>> rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
> >>> I'm not sure if there is a better way to do this. Additionally, I have
> >>> to bit-shift the address written to the SFC as I suspect the value is
> >>> meant to be left justified, but I never tested it further.
> >>>
> >>> Additionally, it might be worth mentioning but I noticed the Rockchip
> >>> BROM will only boot the TPL/SPL off of the SFC if I write it to address
> >>> 0x10000. This is not documented and different than the address looked
> >>> at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
> >>> like the SD card driver I can confirm that if DMA is enabled at the SPL
> >>> stage A-TF seems to fail silently, then when Linux loads it hangs.
> >>> There is an ifdef to force FIFO mode only in the SPL stage.
> >>>
> >>> Tested: Read (works)
> >>> Write (works if you write to an erased sector)
> >>> Erase (works)
> >>> SPL Read (works if you edit the u-boot,spl-boot-order)
> >>>
> >>> Chris Morgan (5):
> >>>     spi: rockchip_sfc: add support for Rockchip SFC
> >>>     rockchip: px30: Add support for using SFC
> >>>     rockchip: px30: add the serial flash controller
> >>>     mtd: spi-nor-ids: Add XTX XT25F128B
> >>>     rockchip: px30: add support for SFC for Odroid Go Advance
> >>>
> >>>    arch/arm/dts/px30.dtsi                     |  38 ++
> >>>    arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
> >>>    arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
> >>>    arch/arm/mach-rockchip/px30/px30.c         |  64 ++
> >>>    drivers/mtd/spi/Kconfig                    |   6 +
> >>>    drivers/mtd/spi/spi-nor-ids.c              |   8 +
> >>>    drivers/spi/Kconfig                        |   8 +
> >>>    drivers/spi/Makefile                       |   1 +
> >>>    drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
> >>>    9 files changed, 926 insertions(+), 1 deletion(-)
> >>>    create mode 100644 drivers/spi/rockchip_sfc.c
> >>>
> >>
> >
>  
>  
>  




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-04 14:40         ` Chris Morgan
@ 2021-06-05  7:37           ` Jon Lin
  2021-06-07 15:34             ` Chris Morgan
  0 siblings, 1 reply; 13+ messages in thread
From: Jon Lin @ 2021-06-05  7:37 UTC (permalink / raw)
  To: Chris Morgan
  Cc: 杨凯,
	u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰


On 6/4/21 10:40 PM, Chris Morgan wrote:
> On Fri, Jun 04, 2021 at 09:42:18PM +0800, 林鼎强 wrote:
>> Hi Chris:
>>
>> It's my honor to read about spi-rockchip-sfc driver from you, and your code has made a big difference to me.
>>
>> Recently, we happen to be willing to submit the spi-mem rk sfc drivers, and we have tried some of them
>> in the internal process. Compared with the RK internal code, I have the following thoughts on your code:
>> 1) Only support spi-nor, not support spi-nand
>> 2) Only support rx_dual, tx_quad, not support tx_dual, tx_quad
>> 3) Some of the code may be further simplified, such as "rockchip_sfc_register_all"
>> 4) Some of the logic may be further simplified, such as "rockchip_sfc_init"
>> 5) Doesn't support SFC ver4 ver5 althought witch is compatibled with lower version
>>
>> In order to support all these features, I adjust the drivers on the basis of your code witch is attach to these mail, these
>> drivers have been test in linux 5.10 rk3568 board, and I'm still doing more strict tests.
>>
>> So I suggest that we complete it together, or we may consider transferring it to me for submission If I have the honor.
>>
>> I'm still unfamiliar with the community culture. I hope I didn't offend you. If I have, I'll say sorry in advance.
>> Best wishes.
> I am absolutely fine with you taking this on, and will be happy to help
> you in any way I can. I only started working on support for this
> because I wanted it supported in both Linux and U-Boot mainline, and
> didn't see any progress being made (so I thought I would do it myself).
> Basically, my goal all along has been to ensure the Odroid Go Advance
> is fully supported in mainline Linux (and U-boot), and that requires
> we get the audio (done), SFC (in progress), crypto, battery, charger,
> and everything else (done) supported.
>
> I trust you are better able to develop/test this than I am, as I only
> have access to some technical documents and a single PX30 based device
> to test this on.
>
> Please CC me when you are ready to submit upstream to Linux and U-boot
> and I will happily test it on my hardware. If you don't have a U-boot
> driver in progress let me know and I can start working on one.
>
> Thank you.


I'm glad to receive your reply and your understanding so soon. I'll talk 
about my plan directly. If there is no obvious objection,I'll go on with it.

Firstly, I will submit the support for the my first version of Linux 
drivers next week which is base on your series submission.

After browsing your submission, there will be the following changes:
1) [RFC,v4,1/8] change with the "Rob Herring" comment
2) [RFC,v4,2/8] update driver
3) All dt patches, make a little change to compatible with RK SDK

[RFC,v4,8/8] arm64: dts: rockchip: Enable SFC for Odroid Go Advance
[RFC,v4,7/8] arm64: dts: rockchip: Add SFC to RK3308
[RFC,v4,6/8] arm: dts: rockchip: Add SFC to RV1108
[RFC,v4,5/8] arm: dts: rockchip: Add SFC to RK3036
[RFC,v4,4/8] clk: rockchip: Add support for hclk_sfc on rk3036
[RFC,v4,3/8] arm64: dts: rockchip: Add SFC to PX30
[RFC,v4,2/8] spi: rockchip-sfc: add rockchip serial flash controller
[RFC,v4,1/8] dt-bindings: rockchip-sfc: Bindings for Rockchip serial 
flash controller

Secondly, Keep devolop uboot drivers base on your serieas submission 
https://patchwork.ozlabs.org/project/uboot/list//?series=245724
submit the code under uboot as soon as possible.

Finally I'll keep focus on the new comments about all these linux 
patches,then fix it until they are merged.

Best wishes.


>>
>>
>> jon.lin@rock-chips.com
>>   
>> From: Kever Yang
>> Date: 2021-06-02 09:27
>> To: Chris Morgan
>> CC: u-boot; heiko.stuebner; vigneshr; jagan; sjg; Chris Morgan; 赵仪峰; 林鼎强
>> Subject: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
>> Hi Chris,
>>   
>> On 2021/6/2 上午12:54, Chris Morgan wrote:
>>> On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
>>>> Add Yifeng from rockchip.
>>>>
>>>> Hi Chris,
>>>>
>>>>       First of all, I think you should remain the origin author info in the
>>>> signed-off.
>>> Okay, I can do that. Please note that since I submitted this I was
>>> asked to redo the upstream linux proposed driver to use the spi-mem
>>> framework. I think for now honestly I'd like to abandon this patch
>>> and resubmit a little later with one that is more or less the same
>>> (using the spi-mem framework) as the Linux driver.
>>   
>>   
>> This sounds better, then we can wait for driver with new framework.
>>   
>> Thanks,
>>   
>> - Kever
>>   
>>> https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/
>>>
>>>> Hi Yifeng,
>>>>
>>>>       Please help to review this driver.
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> - Kever
>>>>
>>>> On 2021/5/26 上午5:49, Chris Morgan wrote:
>>>>> From: Chris Morgan <macromorgan@hotmail.com>
>>>>>
>>>>> Requesting comments for a proposed patchset for adding the Rockchip
>>>>> serial flash controller to u-boot. The goal of these patches is to
>>>>> enable it for the Odroid Go Advance so that it may eventually boot
>>>>> exclusively from the SFC on mainline U-boot (I have tested this and
>>>>> it works).
>>>>>
>>>>> The specific help I need with this patch is:
>>>>>
>>>>> 1) I don't know the best way to upstream the XTX25F128B flash chip.
>>>>> This chip uses a continuation code for the manufacturer ID, however I
>>>>> cannot seem to find any way to actually read the continuation code.
>>>>> There is a risk of this driver, used as-is, to collide with another
>>>>> chip which has the same manufacturer ID with a different continuation
>>>>> code.
>>>>>
>>>>> 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
>>>>> U-Boot sources) supports SPI NAND and chips of varying sizes, but my
>>>>> implementation only permits me to test with a single 128Mb flash chip.
>>>>> The driver itself does some checking on the bitlen in the routine
>>>>> rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
>>>>> I'm not sure if there is a better way to do this. Additionally, I have
>>>>> to bit-shift the address written to the SFC as I suspect the value is
>>>>> meant to be left justified, but I never tested it further.
>>>>>
>>>>> Additionally, it might be worth mentioning but I noticed the Rockchip
>>>>> BROM will only boot the TPL/SPL off of the SFC if I write it to address
>>>>> 0x10000. This is not documented and different than the address looked
>>>>> at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
>>>>> like the SD card driver I can confirm that if DMA is enabled at the SPL
>>>>> stage A-TF seems to fail silently, then when Linux loads it hangs.
>>>>> There is an ifdef to force FIFO mode only in the SPL stage.
>>>>>
>>>>> Tested: Read (works)
>>>>> Write (works if you write to an erased sector)
>>>>> Erase (works)
>>>>> SPL Read (works if you edit the u-boot,spl-boot-order)
>>>>>
>>>>> Chris Morgan (5):
>>>>>      spi: rockchip_sfc: add support for Rockchip SFC
>>>>>      rockchip: px30: Add support for using SFC
>>>>>      rockchip: px30: add the serial flash controller
>>>>>      mtd: spi-nor-ids: Add XTX XT25F128B
>>>>>      rockchip: px30: add support for SFC for Odroid Go Advance
>>>>>
>>>>>     arch/arm/dts/px30.dtsi                     |  38 ++
>>>>>     arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
>>>>>     arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
>>>>>     arch/arm/mach-rockchip/px30/px30.c         |  64 ++
>>>>>     drivers/mtd/spi/Kconfig                    |   6 +
>>>>>     drivers/mtd/spi/spi-nor-ids.c              |   8 +
>>>>>     drivers/spi/Kconfig                        |   8 +
>>>>>     drivers/spi/Makefile                       |   1 +
>>>>>     drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
>>>>>     9 files changed, 926 insertions(+), 1 deletion(-)
>>>>>     create mode 100644 drivers/spi/rockchip_sfc.c
>>>>>
>>   
>>   
>>   
>
>
>
>
>



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
  2021-06-05  7:37           ` Jon Lin
@ 2021-06-07 15:34             ` Chris Morgan
  0 siblings, 0 replies; 13+ messages in thread
From: Chris Morgan @ 2021-06-07 15:34 UTC (permalink / raw)
  To: Jon Lin
  Cc: 杨凯,
	u-boot, heiko.stuebner, vigneshr, jagan, sjg, Chris Morgan,
	赵仪峰

On Sat, Jun 05, 2021 at 03:37:01PM +0800, Jon Lin wrote:
> 
> On 6/4/21 10:40 PM, Chris Morgan wrote:
> > On Fri, Jun 04, 2021 at 09:42:18PM +0800, 林鼎强 wrote:
> > > Hi Chris:
> > > 
> > > It's my honor to read about spi-rockchip-sfc driver from you, and your code has made a big difference to me.
> > > 
> > > Recently, we happen to be willing to submit the spi-mem rk sfc drivers, and we have tried some of them
> > > in the internal process. Compared with the RK internal code, I have the following thoughts on your code:
> > > 1) Only support spi-nor, not support spi-nand
> > > 2) Only support rx_dual, tx_quad, not support tx_dual, tx_quad
> > > 3) Some of the code may be further simplified, such as "rockchip_sfc_register_all"
> > > 4) Some of the logic may be further simplified, such as "rockchip_sfc_init"
> > > 5) Doesn't support SFC ver4 ver5 althought witch is compatibled with lower version
> > > 
> > > In order to support all these features, I adjust the drivers on the basis of your code witch is attach to these mail, these
> > > drivers have been test in linux 5.10 rk3568 board, and I'm still doing more strict tests.
> > > 
> > > So I suggest that we complete it together, or we may consider transferring it to me for submission If I have the honor.
> > > 
> > > I'm still unfamiliar with the community culture. I hope I didn't offend you. If I have, I'll say sorry in advance.
> > > Best wishes.
> > I am absolutely fine with you taking this on, and will be happy to help
> > you in any way I can. I only started working on support for this
> > because I wanted it supported in both Linux and U-Boot mainline, and
> > didn't see any progress being made (so I thought I would do it myself).
> > Basically, my goal all along has been to ensure the Odroid Go Advance
> > is fully supported in mainline Linux (and U-boot), and that requires
> > we get the audio (done), SFC (in progress), crypto, battery, charger,
> > and everything else (done) supported.
> > 
> > I trust you are better able to develop/test this than I am, as I only
> > have access to some technical documents and a single PX30 based device
> > to test this on.
> > 
> > Please CC me when you are ready to submit upstream to Linux and U-boot
> > and I will happily test it on my hardware. If you don't have a U-boot
> > driver in progress let me know and I can start working on one.
> > 
> > Thank you.
> 
> 
> I'm glad to receive your reply and your understanding so soon. I'll talk
> about my plan directly. If there is no obvious objection,I'll go on with it.
> 
> Firstly, I will submit the support for the my first version of Linux drivers
> next week which is base on your series submission.
> 
> After browsing your submission, there will be the following changes:
> 1) [RFC,v4,1/8] change with the "Rob Herring" comment
> 2) [RFC,v4,2/8] update driver
> 3) All dt patches, make a little change to compatible with RK SDK
> 
> [RFC,v4,8/8] arm64: dts: rockchip: Enable SFC for Odroid Go Advance
> [RFC,v4,7/8] arm64: dts: rockchip: Add SFC to RK3308
> [RFC,v4,6/8] arm: dts: rockchip: Add SFC to RV1108
> [RFC,v4,5/8] arm: dts: rockchip: Add SFC to RK3036
> [RFC,v4,4/8] clk: rockchip: Add support for hclk_sfc on rk3036
> [RFC,v4,3/8] arm64: dts: rockchip: Add SFC to PX30
> [RFC,v4,2/8] spi: rockchip-sfc: add rockchip serial flash controller
> [RFC,v4,1/8] dt-bindings: rockchip-sfc: Bindings for Rockchip serial flash
> controller
> 
> Secondly, Keep devolop uboot drivers base on your serieas submission
> https://patchwork.ozlabs.org/project/uboot/list//?series=245724
> submit the code under uboot as soon as possible.

I'm actually abandoning that series of commits, in favor of one more closely
related to the linux driver you're putting in place. I'd like to use the
spi-mem framework for U-boot as well.  I will pursue it instead and try to
have something ready soon. I'm not entirely clear though from this message
if you are planning on doing that as well or are asking me to pursue it.
I'm entirely okay with you pursuing it, but until you tell me you are I will
keep working on it so as to hopefully get something ready for the next pull
window.

> 
> Finally I'll keep focus on the new comments about all these linux
> patches,then fix it until they are merged.
> 
> Best wishes.

Thank you. As you make changes I will test them and provide my tested-by tag.
For now I only have an rk3326 to test them on, but I will do my best to be
thorough.

> 
> 
> > > 
> > > 
> > > jon.lin@rock-chips.com
> > > From: Kever Yang
> > > Date: 2021-06-02 09:27
> > > To: Chris Morgan
> > > CC: u-boot; heiko.stuebner; vigneshr; jagan; sjg; Chris Morgan; 赵仪峰; 林鼎强
> > > Subject: Re: [RFC 0/5] rockchip_sfc: add support for Rockchip SFC
> > > Hi Chris,
> > > On 2021/6/2 上午12:54, Chris Morgan wrote:
> > > > On Tue, Jun 01, 2021 at 08:22:09PM +0800, Kever Yang wrote:
> > > > > Add Yifeng from rockchip.
> > > > > 
> > > > > Hi Chris,
> > > > > 
> > > > >       First of all, I think you should remain the origin author info in the
> > > > > signed-off.
> > > > Okay, I can do that. Please note that since I submitted this I was
> > > > asked to redo the upstream linux proposed driver to use the spi-mem
> > > > framework. I think for now honestly I'd like to abandon this patch
> > > > and resubmit a little later with one that is more or less the same
> > > > (using the spi-mem framework) as the Linux driver.
> > > This sounds better, then we can wait for driver with new framework.
> > > Thanks,
> > > - Kever
> > > > https://patchwork.ozlabs.org/project/linux-mtd/patch/20210528170020.26219-2-macroalpha82@gmail.com/
> > > > 
> > > > > Hi Yifeng,
> > > > > 
> > > > >       Please help to review this driver.
> > > > > 
> > > > > 
> > > > > Thanks,
> > > > > 
> > > > > - Kever
> > > > > 
> > > > > On 2021/5/26 上午5:49, Chris Morgan wrote:
> > > > > > From: Chris Morgan <macromorgan@hotmail.com>
> > > > > > 
> > > > > > Requesting comments for a proposed patchset for adding the Rockchip
> > > > > > serial flash controller to u-boot. The goal of these patches is to
> > > > > > enable it for the Odroid Go Advance so that it may eventually boot
> > > > > > exclusively from the SFC on mainline U-boot (I have tested this and
> > > > > > it works).
> > > > > > 
> > > > > > The specific help I need with this patch is:
> > > > > > 
> > > > > > 1) I don't know the best way to upstream the XTX25F128B flash chip.
> > > > > > This chip uses a continuation code for the manufacturer ID, however I
> > > > > > cannot seem to find any way to actually read the continuation code.
> > > > > > There is a risk of this driver, used as-is, to collide with another
> > > > > > chip which has the same manufacturer ID with a different continuation
> > > > > > code.
> > > > > > 
> > > > > > 2) The Rockchip SFC driver itself (as it is mostly as-is from the BSP
> > > > > > U-Boot sources) supports SPI NAND and chips of varying sizes, but my
> > > > > > implementation only permits me to test with a single 128Mb flash chip.
> > > > > > The driver itself does some checking on the bitlen in the routine
> > > > > > rockchip_sfc_xfer() which is what is called for the dm_spi_ops.xfer.
> > > > > > I'm not sure if there is a better way to do this. Additionally, I have
> > > > > > to bit-shift the address written to the SFC as I suspect the value is
> > > > > > meant to be left justified, but I never tested it further.
> > > > > > 
> > > > > > Additionally, it might be worth mentioning but I noticed the Rockchip
> > > > > > BROM will only boot the TPL/SPL off of the SFC if I write it to address
> > > > > > 0x10000. This is not documented and different than the address looked
> > > > > > at for SD card booting (512 * 64 = 0x8000 for SD Card booting). Also,
> > > > > > like the SD card driver I can confirm that if DMA is enabled at the SPL
> > > > > > stage A-TF seems to fail silently, then when Linux loads it hangs.
> > > > > > There is an ifdef to force FIFO mode only in the SPL stage.
> > > > > > 
> > > > > > Tested: Read (works)
> > > > > > Write (works if you write to an erased sector)
> > > > > > Erase (works)
> > > > > > SPL Read (works if you edit the u-boot,spl-boot-order)
> > > > > > 
> > > > > > Chris Morgan (5):
> > > > > >      spi: rockchip_sfc: add support for Rockchip SFC
> > > > > >      rockchip: px30: Add support for using SFC
> > > > > >      rockchip: px30: add the serial flash controller
> > > > > >      mtd: spi-nor-ids: Add XTX XT25F128B
> > > > > >      rockchip: px30: add support for SFC for Odroid Go Advance
> > > > > > 
> > > > > >     arch/arm/dts/px30.dtsi                     |  38 ++
> > > > > >     arch/arm/dts/rk3326-odroid-go2-u-boot.dtsi |  10 +-
> > > > > >     arch/arm/dts/rk3326-odroid-go2.dts         |  22 +
> > > > > >     arch/arm/mach-rockchip/px30/px30.c         |  64 ++
> > > > > >     drivers/mtd/spi/Kconfig                    |   6 +
> > > > > >     drivers/mtd/spi/spi-nor-ids.c              |   8 +
> > > > > >     drivers/spi/Kconfig                        |   8 +
> > > > > >     drivers/spi/Makefile                       |   1 +
> > > > > >     drivers/spi/rockchip_sfc.c                 | 652 +++++++++++++++++++++
> > > > > >     9 files changed, 926 insertions(+), 1 deletion(-)
> > > > > >     create mode 100644 drivers/spi/rockchip_sfc.c
> > > > > > 
> > 
> > 
> > 
> > 
> > 
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-06-07 15:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-25 21:49 [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Chris Morgan
2021-05-25 21:49 ` [PATCH 1/5] spi: " Chris Morgan
2021-05-25 21:49 ` [PATCH 2/5] rockchip: px30: Add support for using SFC Chris Morgan
2021-05-25 21:49 ` [PATCH 3/5] rockchip: px30: add the serial flash controller Chris Morgan
2021-05-25 21:49 ` [PATCH 4/5] mtd: spi-nor-ids: Add XTX XT25F128B Chris Morgan
2021-05-25 21:49 ` [PATCH 5/5] rockchip: px30: add support for SFC for Odroid Go Advance Chris Morgan
2021-06-01 12:22 ` [RFC 0/5] rockchip_sfc: add support for Rockchip SFC Kever Yang
2021-06-01 16:54   ` Chris Morgan
2021-06-02  1:27     ` Kever Yang
2021-06-04 13:42       ` 林鼎强
2021-06-04 14:40         ` Chris Morgan
2021-06-05  7:37           ` Jon Lin
2021-06-07 15:34             ` Chris Morgan

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.