public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] mtd: spinand: Add continuous read mode support
@ 2023-11-09 11:24 JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 1/5] Add clk wizard and mxic host controller driver JaimeLiao
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:24 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

v3:
  add method for chcking controller limitation

v2:
  correct typos
  change error handle when continuous read error

JaimeLiao (5):
  Add clk wizard and mxic host controller driver
  mtd: spinand: Add support continuous read mode
  mtd: spinand: Add continuous read state
  mtd: spinand: Add support continuous read operation
  mtd: spinand: macronix: Add continuous read support for Macronix Flash

 arch/arm/boot/dts/xilinx/zynq-7000.dtsi       |   4 +-
 .../dts/xilinx/zynq-mxic-picozed.spi-nand.dts | 141 ++++++
 .../zynq-mxic-picozed.spi-nand_manual.dts     | 141 ++++++
 .../dts/xilinx/zynq-mxic-picozed.spi-nor.dts  | 142 ++++++
 drivers/clk/Kconfig                           |   1 +
 drivers/clk/zynq/Kconfig                      |   6 +
 drivers/clk/zynq/Makefile                     |   1 +
 drivers/clk/zynq/clk-wizard.c                 | 409 ++++++++++++++++++
 drivers/mtd/nand/spi/core.c                   | 135 ++++++
 drivers/mtd/nand/spi/macronix.c               |  14 +-
 drivers/spi/spi-mxic.c                        |  84 ++--
 include/linux/mtd/spinand.h                   |   4 +
 12 files changed, 1031 insertions(+), 51 deletions(-)
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
 create mode 100644 drivers/clk/zynq/Kconfig
 create mode 100644 drivers/clk/zynq/clk-wizard.c

-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 1/5] Add clk wizard and mxic host controller driver
  2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
@ 2023-11-09 11:24 ` JaimeLiao
  2023-11-09 14:13   ` Miquel Raynal
  2023-11-09 11:24 ` [PATCH v3 2/5] mtd: spinand: Add support continuous read mode JaimeLiao
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:24 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 arch/arm/boot/dts/xilinx/zynq-7000.dtsi       |   4 +-
 .../dts/xilinx/zynq-mxic-picozed.spi-nand.dts | 141 ++++++
 .../zynq-mxic-picozed.spi-nand_manual.dts     | 141 ++++++
 .../dts/xilinx/zynq-mxic-picozed.spi-nor.dts  | 142 ++++++
 drivers/clk/Kconfig                           |   1 +
 drivers/clk/zynq/Kconfig                      |   6 +
 drivers/clk/zynq/Makefile                     |   1 +
 drivers/clk/zynq/clk-wizard.c                 | 409 ++++++++++++++++++
 drivers/spi/spi-mxic.c                        |  84 ++--
 9 files changed, 885 insertions(+), 44 deletions(-)
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
 create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
 create mode 100644 drivers/clk/zynq/Kconfig
 create mode 100644 drivers/clk/zynq/clk-wizard.c

diff --git a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
index a7db3f3009f2..45c207b62396 100644
--- a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
@@ -289,7 +289,7 @@
 
 		sdhci0: mmc@e0100000 {
 			compatible = "arasan,sdhci-8.9a";
-			status = "disabled";
+			status = "okay";
 			clock-names = "clk_xin", "clk_ahb";
 			clocks = <&clkc 21>, <&clkc 32>;
 			interrupt-parent = <&intc>;
@@ -316,7 +316,7 @@
 			clkc: clkc@100 {
 				#clock-cells = <1>;
 				compatible = "xlnx,ps7-clkc";
-				fclk-enable = <0>;
+				fclk-enable = <0xf>;
 				clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
 						"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
 						"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
new file mode 100644
index 000000000000..a34223b70199
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
@@ -0,0 +1,141 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+	model = "Zynq MXIC PicoZed Development Board";
+	compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+	aliases {
+		ethernet0 = &gem0;
+		serial0 = &uart1;
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x30000000>;
+	};
+
+	chosen {
+		bootargs = "";
+		stdout-path = "serial0:115200n8";
+	};
+
+	clkwzd_in: clkwzd_in {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133300000>;
+	};
+};
+
+&amba {
+	sdhci@e0100000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x15 0x1 0x20>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x18 0x4>;
+			reg = <0xe0100000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	sdhci@e0101000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x16 0x1 0x21>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x2f 0x4>;
+			reg = <0xe0101000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	clkwizard: clkwizard@43c20000 {
+		compatible = "xlnx,clk-wizard-5.1";
+		reg = <0x43c20000 0x10000>;
+		clocks = <&clkc 0xf>, <&clkc 0xf>;
+		clock-names = "aclk", "clk_in1";
+		#clock-cells = <1>;
+		xlnx,clk-wizard-num-outputs = <2>;
+		phandle = <0x12>;
+	};
+
+/* v11 */
+/*
+	clkwizard: clkwizard@43c20000 {
+		#clock-cells = <1>;
+		reg = <0x43c20000 0x1000>;
+		compatible = "xlnx,clocking-wizard";
+		xlnx,speed-grade = <1>;
+		xlnx,nr-outputs = <6>;
+		clock-names = "clk_in1", "s_axi_aclk";
+		clocks = <&clkc 18>, <&clkc 18>;
+	};
+*/
+
+	spi@43c30000 {
+		compatible = "mxicy,mx25f0a-spi";
+		reg = <0x43c30000 0x10000>, <0xa0000000 0x4000000>;
+		reg-names = "regs", "dirmap";
+		clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+		clock-names = "send_clk", "send_dly_clk", "ps_clk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		flash@0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			#nand-use-soft-ecc-engine;
+			#nand-ecc-algo = "bch";
+			#nand-ecc-strength = <8>;
+			#nand-ecc-step-size = <512>;
+			spi-max-frequency = <25000000>;
+			spi-tx-bus-width = <4>;
+			spi-rx-bus-width = <4>;
+			#address-cells = <0x1>;
+			#size-cells = <0x1>;
+		};
+	};
+	
+/*
+	nand: mxic-nfc@43c30000 {
+		compatible = "mxic,multi-itfc-v009-nand-controller";
+		reg = <0x43c30000 0x10000>;
+		clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+		clock-names = "send", "send_dly", "ps";
+		interrupt-parent = <&intc>;
+		interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand@0 {
+			reg = <0>;
+			label = "main-storage";
+
+			nand-use-soft-ecc-engine;
+			nand-ecc-algo = "bch";
+			nand-ecc-algo = "hamming";
+			nand-ecc-strength = <8>;
+			nand-ecc-step-size = <512>;
+		};
+ 
+	};
+*/
+};
+
+&clkc {
+	ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+	status = "okay";
+	phy-mode = "rgmii-id";
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
new file mode 100644
index 000000000000..7b68c03deb65
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
@@ -0,0 +1,141 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+	model = "Zynq MXIC PicoZed Development Board";
+	compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+	aliases {
+		ethernet0 = &gem0;
+		serial0 = &uart1;
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x30000000>;
+	};
+
+	chosen {
+		bootargs = "";
+		stdout-path = "serial0:115200n8";
+	};
+
+	clkwzd_in: clkwzd_in {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133300000>;
+	};
+};
+
+&amba {
+	sdhci@e0100000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x15 0x1 0x20>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x18 0x4>;
+			reg = <0xe0100000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	sdhci@e0101000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x16 0x1 0x21>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x2f 0x4>;
+			reg = <0xe0101000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	clkwizard: clkwizard@43c20000 {
+		compatible = "xlnx,clk-wizard-5.1";
+		reg = <0x43c20000 0x10000>;
+		clocks = <&clkc 0xf>, <&clkc 0xf>;
+		clock-names = "aclk", "clk_in1";
+		#clock-cells = <1>;
+		xlnx,clk-wizard-num-outputs = <2>;
+		phandle = <0x12>;
+	};
+
+/* v11 */
+/*
+	clkwizard: clkwizard@43c20000 {
+		#clock-cells = <1>;
+		reg = <0x43c20000 0x1000>;
+		compatible = "xlnx,clocking-wizard";
+		xlnx,speed-grade = <1>;
+		xlnx,nr-outputs = <6>;
+		clock-names = "clk_in1", "s_axi_aclk";
+		clocks = <&clkc 18>, <&clkc 18>;
+	};
+*/
+
+	spi@43c30000 {
+		compatible = "mxicy,mx25f0a-spi";
+		reg = <0x43c30000 0x10000>;
+		reg-names = "regs";
+		clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+		clock-names = "send_clk", "send_dly_clk", "ps_clk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		flash@0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			#nand-use-soft-ecc-engine;
+			#nand-ecc-algo = "bch";
+			#nand-ecc-strength = <8>;
+			#nand-ecc-step-size = <512>;
+			spi-max-frequency = <25000000>;
+			spi-tx-bus-width = <1>;
+			spi-rx-bus-width = <1>;
+			#address-cells = <0x1>;
+			#size-cells = <0x1>;
+		};
+	};
+	
+/*
+	nand: mxic-nfc@43c30000 {
+		compatible = "mxic,multi-itfc-v009-nand-controller";
+		reg = <0x43c30000 0x10000>;
+		clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+		clock-names = "send", "send_dly", "ps";
+		interrupt-parent = <&intc>;
+		interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand@0 {
+			reg = <0>;
+			label = "main-storage";
+
+			nand-use-soft-ecc-engine;
+			nand-ecc-algo = "bch";
+			nand-ecc-algo = "hamming";
+			nand-ecc-strength = <8>;
+			nand-ecc-step-size = <512>;
+		};
+ 
+	};
+*/
+};
+
+&clkc {
+	ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+	status = "okay";
+	phy-mode = "rgmii-id";
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
new file mode 100644
index 000000000000..ee700c43218f
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
@@ -0,0 +1,142 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+	model = "Zynq MXIC PicoZed Development Board";
+	compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+	aliases {
+		ethernet0 = &gem0;
+		serial0 = &uart1;
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x30000000>;
+	};
+
+	chosen {
+		bootargs = "";
+		stdout-path = "serial0:115200n8";
+	};
+
+	clkwzd_in: clkwzd_in {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133300000>;
+	};
+};
+
+&amba {
+	sdhci@e0100000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x15 0x1 0x20>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x18 0x4>;
+			reg = <0xe0100000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	sdhci@e0101000 {
+			compatible = "arasan,sdhci-8.9a";
+			status = "okay";
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <0x1 0x16 0x1 0x21>;
+			interrupt-parent = <0x3>;
+			interrupts = <0x0 0x2f 0x4>;
+			reg = <0xe0101000 0x1000>;
+			xlnx,has-cd = <0x1>;
+			xlnx,has-power = <0x0>;
+			xlnx,has-wp = <0x0>;
+	};
+
+	clkwizard: clkwizard@43c20000 {
+		compatible = "xlnx,clk-wizard-5.1";
+		reg = <0x43c20000 0x10000>;
+		clocks = <&clkc 0xf>, <&clkc 0xf>;
+		clock-names = "aclk", "clk_in1";
+		#clock-cells = <1>;
+		xlnx,clk-wizard-num-outputs = <2>;
+		phandle = <0x12>;
+	};
+
+/* v11 */
+/*
+	clkwizard: clkwizard@43c20000 {
+		#clock-cells = <1>;
+		reg = <0x43c20000 0x1000>;
+		compatible = "xlnx,clocking-wizard";
+		xlnx,speed-grade = <1>;
+		xlnx,nr-outputs = <6>;
+		clock-names = "clk_in1", "s_axi_aclk";
+		clocks = <&clkc 18>, <&clkc 18>;
+	};
+*/
+
+	spi@43c30000 {
+		compatible = "mxicy,mx25f0a-spi";
+		reg = <0x43c30000 0x10000>, <0xa0000000 0x4000000>;
+		reg-names = "regs", "dirmap";
+		clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+		clock-names = "send_clk", "send_dly_clk", "ps_clk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		flash@0 {
+			#compatible = "spi-nand";
+			compatible = "jedec,spi-nor";
+			reg = <0>;
+			#nand-use-soft-ecc-engine;
+			#nand-ecc-algo = "bch";
+			#nand-ecc-strength = <8>;
+			#nand-ecc-step-size = <512>;
+			spi-max-frequency = <25000000>;
+			spi-tx-bus-width = <8>;
+			spi-rx-bus-width = <8>;
+			#address-cells = <0x1>;
+			#size-cells = <0x1>;
+		};
+	};
+	
+/*
+	nand: mxic-nfc@43c30000 {
+		compatible = "mxic,multi-itfc-v009-nand-controller";
+		reg = <0x43c30000 0x10000>;
+		clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+		clock-names = "send", "send_dly", "ps";
+		interrupt-parent = <&intc>;
+		interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand@0 {
+			reg = <0>;
+			label = "main-storage";
+
+			nand-use-soft-ecc-engine;
+			nand-ecc-algo = "bch";
+			nand-ecc-algo = "hamming";
+			nand-ecc-strength = <8>;
+			nand-ecc-step-size = <512>;
+		};
+ 
+	};
+*/
+};
+
+&clkc {
+	ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+	status = "okay";
+	phy-mode = "rgmii-id";
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c30d0d396f7a..f16464abacf5 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -510,6 +510,7 @@ source "drivers/clk/visconti/Kconfig"
 source "drivers/clk/x86/Kconfig"
 source "drivers/clk/xilinx/Kconfig"
 source "drivers/clk/zynqmp/Kconfig"
+source "drivers/clk/zynq/Kconfig"
 
 # Kunit test cases
 config CLK_KUNIT_TEST
diff --git a/drivers/clk/zynq/Kconfig b/drivers/clk/zynq/Kconfig
new file mode 100644
index 000000000000..240ff17daa8f
--- /dev/null
+++ b/drivers/clk/zynq/Kconfig
@@ -0,0 +1,6 @@
+config CLK_ZYNQ_CLK_WIZARD
+        tristate "Xilinx clocking wizard driver"
+        depends on ARCH_ZYNQ || COMPILE_TEST
+        help
+          Enable the driver for Xilinx clocking wizard IP.
+
diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile
index a5bb696de943..b1a1628048fb 100644
--- a/drivers/clk/zynq/Makefile
+++ b/drivers/clk/zynq/Makefile
@@ -2,3 +2,4 @@
 # Zynq clock specific Makefile
 
 obj-y	+= clkc.o pll.o
+obj-$(CONFIG_CLK_ZYNQ_CLK_WIZARD)      += clk-wizard.o
diff --git a/drivers/clk/zynq/clk-wizard.c b/drivers/clk/zynq/clk-wizard.c
new file mode 100644
index 000000000000..3b217f8a8ffa
--- /dev/null
+++ b/drivers/clk/zynq/clk-wizard.c
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq Clocking Wizard driver
+ *
+ *  Copyright (C) 2018 Macronix
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define SRR			0x0
+
+#define SR			0x4
+#define SR_LOCKED		BIT(0)
+
+#define CCR(x)			(0x200 + ((x) * 4))
+
+#define FBOUT_CFG		CCR(0)
+#define FBOUT_DIV(x)		(x)
+#define FBOUT_GET_DIV(x)	((x) & GENMASK(7, 0))
+#define FBOUT_MUL(x)		((x) << 8)
+#define FBOUT_GET_MUL(x)	(((x) & GENMASK(15, 8)) >> 8)
+#define FBOUT_FRAC(x)		((x) << 16)
+#define FBOUT_GET_FRAC(x)	(((x) & GENMASK(25, 16)) >> 16)
+#define FBOUT_FRAC_EN		BIT(26)
+
+#define FBOUT_PHASE		CCR(1)
+
+#define OUT_CFG(x)		CCR(2 + ((x) * 3))
+#define OUT_DIV(x)		(x)
+#define OUT_GET_DIV(x)		((x) & GENMASK(7, 0))
+#define OUT_FRAC(x)		((x) << 8)
+#define OUT_GET_FRAC(x)		(((x) & GENMASK(17, 8)) >> 8)
+#define OUT_FRAC_EN		BIT(18)
+
+#define OUT_PHASE(x)		CCR(3 + ((x) * 3))
+#define OUT_DUTY(x)		CCR(4 + ((x) * 3))
+
+#define CTRL			CCR(23)
+#define CTRL_SEN		BIT(2)
+#define CTRL_SADDR		BIT(1)
+#define CTRL_LOAD		BIT(0)
+
+struct clkwzd;
+
+struct clkwzd_fbout {
+	struct clk_hw base;
+	struct clkwzd *wzd;
+};
+
+static inline struct clkwzd_fbout *to_clkwzd_fbout(struct clk_hw *hw)
+{
+	return container_of(hw, struct clkwzd_fbout, base);
+}
+
+struct clkwzd_out {
+	struct clk_hw base;
+	struct clkwzd *wzd;
+	unsigned int id;
+};
+
+static inline struct clkwzd_out *to_clkwzd_out(struct clk_hw *hw)
+{
+	return container_of(hw, struct clkwzd_out, base);
+}
+
+#define CLKWZD_MAX_OUTPUT	7
+
+struct clkwzd {
+	struct mutex lock;
+	struct clk *aclk;
+	struct clk *clk_in1;
+	void __iomem *regs;
+	struct clkwzd_out out[CLKWZD_MAX_OUTPUT];
+	struct clkwzd_fbout fbout;
+	struct clk_hw_onecell_data *onecell;
+};
+
+
+static int clkwzd_is_locked(struct clkwzd *wzd)
+{
+	bool prepared;
+
+	mutex_lock(&wzd->lock);
+	prepared = readl(wzd->regs + SR) & SR_LOCKED;
+	mutex_unlock(&wzd->lock);
+
+	return prepared;
+}
+
+static int clkwzd_apply_conf(struct clkwzd *wzd)
+{
+	int ret;
+	u32 val;
+
+	mutex_lock(&wzd->lock);
+	ret = readl_poll_timeout(wzd->regs + SR, val, val & SR_LOCKED, 1, 100);
+	if (!ret) {
+		writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, wzd->regs + CTRL);
+		writel(CTRL_SADDR, wzd->regs + CTRL);
+		ret = readl_poll_timeout(wzd->regs + SR, val, val & SR_LOCKED,
+					 1, 100);
+	}
+	mutex_unlock(&wzd->lock);
+
+	return 0;
+}
+
+static int clkwzd_fbout_is_prepared(struct clk_hw *hw)
+{
+	struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+	return clkwzd_is_locked(fbout->wzd);
+}
+
+static int clkwzd_fbout_prepare(struct clk_hw *hw)
+{
+	struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+	return clkwzd_apply_conf(fbout->wzd);
+}
+
+static unsigned long clkwzd_fbout_recalc_rate(struct clk_hw *hw,
+					      unsigned long parent_rate)
+{
+	struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+	unsigned long rate;
+	u32 cfg;
+
+	cfg = readl(fbout->wzd->regs + FBOUT_CFG);
+	if (cfg & FBOUT_FRAC_EN)
+		rate = DIV_ROUND_DOWN_ULL((u64)parent_rate *
+					  ((FBOUT_GET_MUL(cfg) * 1000) +
+					   FBOUT_GET_FRAC(cfg)),
+					  1000);
+	else
+		rate = parent_rate * FBOUT_GET_MUL(cfg);
+
+	rate /= FBOUT_GET_DIV(cfg);
+
+	return rate;
+}
+
+static int clkwzd_fbout_set_phase(struct clk_hw *hw, int degrees)
+{
+	struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+	writel(degrees * 1000, fbout->wzd->regs + FBOUT_PHASE);
+
+	return 0;
+}
+
+static int clkwzd_fbout_get_phase(struct clk_hw *hw)
+{
+	struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+	return readl(fbout->wzd->regs + FBOUT_PHASE) / 1000;
+}
+
+const struct clk_ops fbout_ops = {
+	.is_prepared = clkwzd_fbout_is_prepared,
+	.prepare = clkwzd_fbout_prepare,
+	.recalc_rate = clkwzd_fbout_recalc_rate,
+	.set_phase = clkwzd_fbout_set_phase,
+	.get_phase = clkwzd_fbout_get_phase,
+};
+
+static int clkwzd_out_is_prepared(struct clk_hw *hw)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+
+	return clkwzd_is_locked(out->wzd);
+}
+
+static int clkwzd_out_prepare(struct clk_hw *hw)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+
+	return clkwzd_apply_conf(out->wzd);
+}
+
+static unsigned long clkwzd_out_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+	unsigned long rate;
+	u32 cfg;
+
+	cfg = readl(out->wzd->regs + OUT_CFG(out->id));
+	if (cfg & OUT_FRAC_EN)
+		rate = DIV_ROUND_DOWN_ULL((u64)parent_rate * 1000,
+					  ((OUT_GET_DIV(cfg) * 1000) +
+					   OUT_GET_FRAC(cfg)));
+	else
+		rate = parent_rate / OUT_GET_DIV(cfg);
+
+	return rate;
+}
+
+static int clkwzd_out_set_rate(struct clk_hw *hw,
+			       unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+	u64 div;
+	u32 cfg;
+
+	div = DIV_ROUND_DOWN_ULL((u64)parent_rate * 1000, rate);
+	if (div < 1000 || div > 255999)
+		return -EINVAL;
+
+	cfg = OUT_DIV((u32)div / 1000);
+
+	if ((u32)div % 1000)
+		cfg |= OUT_FRAC_EN | OUT_FRAC((u32)div % 1000);
+
+	writel(cfg, out->wzd->regs + OUT_CFG(out->id));
+
+	/* Set duty cycle to 50%. */
+	writel(50000, out->wzd->regs + OUT_DUTY(out->id));
+
+	return 0;
+}
+
+static long clkwzd_out_round_rate(struct clk_hw *hw,
+				  unsigned long rate,
+				  unsigned long *parent_rate)
+{
+	u64 div;
+
+	div = DIV_ROUND_CLOSEST_ULL((u64)(*parent_rate) * 1000, rate);
+	if (div < 1000)
+		return *parent_rate;
+
+	if (div > 255999)
+		div = 255999;
+
+	return DIV_ROUND_DOWN_ULL((u64)(*parent_rate) * 1000, (u32)div);
+}
+
+static int clkwzd_out_set_phase(struct clk_hw *hw, int degrees)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+
+	writel(degrees * 1000, out->wzd->regs + OUT_PHASE(out->id));
+
+	return 0;
+}
+
+static int clkwzd_out_get_phase(struct clk_hw *hw)
+{
+	struct clkwzd_out *out = to_clkwzd_out(hw);
+
+	return readl(out->wzd->regs + OUT_PHASE(out->id)) / 1000;
+}
+
+static const struct clk_ops out_ops = {
+	.is_prepared = clkwzd_out_is_prepared,
+	.prepare = clkwzd_out_prepare,
+	.recalc_rate = clkwzd_out_recalc_rate,
+	.round_rate = clkwzd_out_round_rate,
+	.set_rate = clkwzd_out_set_rate,
+	.set_phase = clkwzd_out_set_phase,
+	.get_phase = clkwzd_out_get_phase,
+};
+
+static int zynq_clkwzd_probe(struct platform_device *pdev)
+{
+	struct clk_init_data fboutinit = { };
+	const char *clk_in_name;
+	struct resource *res;
+	struct clkwzd *wzd;
+	u32 i, noutputs = 0;
+	int ret;
+
+	wzd = devm_kzalloc(&pdev->dev, sizeof(*wzd), GFP_KERNEL);
+	if (!wzd)
+		return -ENOMEM;
+
+	wzd->aclk = devm_clk_get(&pdev->dev, "aclk");
+	if (IS_ERR(wzd->aclk))
+		return PTR_ERR(wzd->aclk);
+
+	wzd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
+	if (IS_ERR(wzd->clk_in1))
+		return PTR_ERR(wzd->clk_in1);
+
+	of_property_read_u32(pdev->dev.of_node, "xlnx,clk-wizard-num-outputs",
+			     &noutputs);
+	if (!noutputs || noutputs >= CLKWZD_MAX_OUTPUT)
+		return -EINVAL;
+
+	wzd->onecell = devm_kzalloc(&pdev->dev,
+				    sizeof(*wzd->onecell) +
+				    (sizeof(*wzd->onecell->hws) * noutputs),
+				    GFP_KERNEL);
+	if (!wzd->onecell)
+		return -ENOMEM;
+
+	clk_in_name = __clk_get_name(wzd->clk_in1);
+	if (!clk_in_name)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wzd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(wzd->regs))
+		return PTR_ERR(wzd->regs);
+
+	mutex_init(&wzd->lock);
+
+	wzd->fbout.wzd = wzd;
+	fboutinit.ops = &fbout_ops;
+	fboutinit.flags = CLK_SET_RATE_GATE;
+	fboutinit.num_parents = 1;
+	fboutinit.parent_names = &clk_in_name;
+	fboutinit.flags = CLK_SET_RATE_GATE;
+
+	fboutinit.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-fbout",
+					dev_name(&pdev->dev));
+	if (!fboutinit.name)
+		return -ENOMEM;
+
+	ret = clk_prepare_enable(wzd->aclk);
+	if (ret)
+		return ret;
+
+	wzd->fbout.base.init = &fboutinit;
+	ret = devm_clk_hw_register(&pdev->dev, &wzd->fbout.base);
+	if (ret)
+		goto err_disable_aclk;
+
+	for (i = 0; i < noutputs; i++) {
+		struct clk_init_data outinit = { };
+
+		wzd->out[i].id = i;
+		wzd->out[i].wzd = wzd;
+		outinit.ops = &out_ops;
+		outinit.num_parents = 1;
+		outinit.parent_names = &fboutinit.name;
+		outinit.flags = CLK_SET_RATE_GATE;
+		wzd->out[i].base.init = &outinit;
+		outinit.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					      "%s-out%d",
+					      dev_name(&pdev->dev), i);
+		if (!outinit.name) {
+			ret = -ENOMEM;
+			goto err_disable_aclk;
+		}
+
+		ret = devm_clk_hw_register(&pdev->dev, &wzd->out[i].base);
+		if (ret)
+			goto err_disable_aclk;
+
+		wzd->onecell->hws[i] = &wzd->out[i].base;
+	}
+
+	wzd->onecell->num = noutputs;
+	ret = devm_of_clk_add_hw_provider(&pdev->dev,
+					  of_clk_hw_onecell_get,
+					  wzd->onecell);
+	if (ret)
+		goto err_disable_aclk;
+
+	platform_set_drvdata(pdev, wzd);
+
+	return 0;
+
+err_disable_aclk:
+	clk_disable_unprepare(wzd->aclk);
+
+	return ret;
+}
+
+static int zynq_clkwzd_remove(struct platform_device *pdev)
+{
+	struct clkwzd *wzd = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(wzd->aclk);
+
+	return 0;
+}
+
+static const struct of_device_id zynq_clkwzd_of_ids[] = {
+	{ .compatible = "xlnx,clk-wizard-5.1" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, zynq_clkwzd_of_ids);
+
+static struct platform_driver zynq_clkwzd_driver = {
+	.probe = zynq_clkwzd_probe,
+	.remove = zynq_clkwzd_remove,
+	.driver = {
+		.name = "zynq-clk-wizard",
+		.of_match_table = zynq_clkwzd_of_ids,
+	},
+};
+module_platform_driver(zynq_clkwzd_driver);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
+MODULE_DESCRIPTION("Xilinx Clocking Wizard driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 60c9f3048ac9..28c324d7200a 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -323,7 +323,7 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
 		       (op->addr.dtr ? OP_ADDR_DDR : 0);
 
 	if (op->dummy.nbytes)
-		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
+		cfg |= OP_DUMMY_CYC((op->dummy.nbytes) * (op->data.buswidth));
 
 	/* Direct mapping data.nbytes field is not populated */
 	if (data_len) {
@@ -390,7 +390,7 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
 					u64 offs, size_t len, void *buf)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
 	int ret;
 	u32 sts;
 
@@ -434,7 +434,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 					 u64 offs, size_t len,
 					 const void *buf)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
 	u32 sts;
 	int ret;
 
@@ -481,9 +481,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
 		return false;
 
-	if (op->data.nbytes && op->dummy.nbytes &&
-	    op->data.buswidth != op->dummy.buswidth)
-		return false;
+	//if (op->data.nbytes && op->dummy.nbytes &&
+	//    op->data.buswidth != op->dummy.buswidth)
+	//	return false;
 
 	if (op->addr.nbytes > 7)
 		return false;
@@ -493,7 +493,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 
 static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
 
 	if (!mxic->linear.map)
 		return -EINVAL;
@@ -510,7 +510,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
 static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 				const struct spi_mem_op *op)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(mem->spi->controller);
+	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
 	int i, ret;
 	u8 addr[8], cmd[2];
 
@@ -543,7 +543,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 	if (ret)
 		goto out;
 
-	ret = mxic_spi_data_xfer(mxic, NULL, NULL, op->dummy.nbytes);
+	ret = mxic_spi_data_xfer(mxic, NULL, NULL, (op->dummy.nbytes) * (op->data.buswidth));
 	if (ret)
 		goto out;
 
@@ -565,9 +565,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
 	.supports_op = mxic_spi_mem_supports_op,
 	.exec_op = mxic_spi_mem_exec_op,
-	.dirmap_create = mxic_spi_mem_dirmap_create,
-	.dirmap_read = mxic_spi_mem_dirmap_read,
-	.dirmap_write = mxic_spi_mem_dirmap_write,
+	//.dirmap_create = mxic_spi_mem_dirmap_create,
+	//.dirmap_read = mxic_spi_mem_dirmap_read,
+	//.dirmap_write = mxic_spi_mem_dirmap_write,
 };
 
 static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
@@ -577,7 +577,7 @@ static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
 
 static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(spi->controller);
+	struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
 
 	if (!lvl) {
 		writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
@@ -592,11 +592,11 @@ static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
 	}
 }
 
-static int mxic_spi_transfer_one(struct spi_controller *host,
+static int mxic_spi_transfer_one(struct spi_master *master,
 				 struct spi_device *spi,
 				 struct spi_transfer *t)
 {
-	struct mxic_spi *mxic = spi_controller_get_devdata(host);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 	unsigned int busw = OP_BUSW_1;
 	int ret;
 
@@ -632,7 +632,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host,
 	if (ret)
 		return ret;
 
-	spi_finalize_current_transfer(host);
+	spi_finalize_current_transfer(master);
 
 	return 0;
 }
@@ -713,8 +713,8 @@ static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
 
 static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
 {
-	struct spi_controller *host = dev_get_drvdata(dev);
-	struct mxic_spi *mxic = spi_controller_get_devdata(host);
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 
 	mxic_spi_clk_disable(mxic);
 	clk_disable_unprepare(mxic->ps_clk);
@@ -724,8 +724,8 @@ static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
 
 static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
 {
-	struct spi_controller *host = dev_get_drvdata(dev);
-	struct mxic_spi *mxic = spi_controller_get_devdata(host);
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 	int ret;
 
 	ret = clk_prepare_enable(mxic->ps_clk);
@@ -744,21 +744,21 @@ static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
 
 static int mxic_spi_probe(struct platform_device *pdev)
 {
-	struct spi_controller *host;
+	struct spi_master *master;
 	struct resource *res;
 	struct mxic_spi *mxic;
 	int ret;
 
-	host = devm_spi_alloc_host(&pdev->dev, sizeof(struct mxic_spi));
-	if (!host)
+	master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
+	if (!master)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, host);
+	platform_set_drvdata(pdev, master);
 
-	mxic = spi_controller_get_devdata(host);
+	mxic = spi_master_get_devdata(master);
 	mxic->dev = &pdev->dev;
 
-	host->dev.of_node = pdev->dev.of_node;
+	master->dev.of_node = pdev->dev.of_node;
 
 	mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
 	if (IS_ERR(mxic->ps_clk))
@@ -786,19 +786,19 @@ static int mxic_spi_probe(struct platform_device *pdev)
 	}
 
 	pm_runtime_enable(&pdev->dev);
-	host->auto_runtime_pm = true;
+	master->auto_runtime_pm = true;
 
-	host->num_chipselect = 1;
-	host->mem_ops = &mxic_spi_mem_ops;
-	host->mem_caps = &mxic_spi_mem_caps;
+	master->num_chipselect = 1;
+	master->mem_ops = &mxic_spi_mem_ops;
+	master->mem_caps = &mxic_spi_mem_caps;
 
-	host->set_cs = mxic_spi_set_cs;
-	host->transfer_one = mxic_spi_transfer_one;
-	host->bits_per_word_mask = SPI_BPW_MASK(8);
-	host->mode_bits = SPI_CPOL | SPI_CPHA |
-			  SPI_RX_DUAL | SPI_TX_DUAL |
-			  SPI_RX_QUAD | SPI_TX_QUAD |
-			  SPI_RX_OCTAL | SPI_TX_OCTAL;
+	master->set_cs = mxic_spi_set_cs;
+	master->transfer_one = mxic_spi_transfer_one;
+	master->bits_per_word_mask = SPI_BPW_MASK(8);
+	master->mode_bits = SPI_CPOL | SPI_CPHA |
+			SPI_RX_DUAL | SPI_TX_DUAL |
+			SPI_RX_QUAD | SPI_TX_QUAD |
+			SPI_RX_OCTAL | SPI_TX_OCTAL;
 
 	mxic_spi_hw_init(mxic);
 
@@ -808,9 +808,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = spi_register_controller(host);
+	ret = spi_register_master(master);
 	if (ret) {
-		dev_err(&pdev->dev, "spi_register_controller failed\n");
+		dev_err(&pdev->dev, "spi_register_master failed\n");
 		pm_runtime_disable(&pdev->dev);
 		mxic_spi_mem_ecc_remove(mxic);
 	}
@@ -820,12 +820,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
 
 static void mxic_spi_remove(struct platform_device *pdev)
 {
-	struct spi_controller *host = platform_get_drvdata(pdev);
-	struct mxic_spi *mxic = spi_controller_get_devdata(host);
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 
 	pm_runtime_disable(&pdev->dev);
 	mxic_spi_mem_ecc_remove(mxic);
-	spi_unregister_controller(host);
+	spi_unregister_master(master);
 }
 
 static const struct of_device_id mxic_spi_of_ids[] = {
-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 2/5] mtd: spinand: Add support continuous read mode
  2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 1/5] Add clk wizard and mxic host controller driver JaimeLiao
@ 2023-11-09 11:24 ` JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 3/5] mtd: spinand: Add continuous read state JaimeLiao
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:24 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

The patch supports setting the "CONT" bit of the configuration
register and create spinand_continuous_read_enable/disable functions.

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 drivers/mtd/nand/spi/core.c | 11 +++++++++++
 include/linux/mtd/spinand.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 849ccfedbc72..cfc295f5e31b 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -193,6 +193,17 @@ static int spinand_init_quad_enable(struct spinand_device *spinand)
 			       enable ? CFG_QUAD_ENABLE : 0);
 }
 
+static int spinand_continuous_read_enable(struct spinand_device *spinand)
+{
+	return spinand_upd_cfg(spinand, CFG_CONT_READ_ENABLE,
+			       CFG_CONT_READ_ENABLE);
+}
+
+static int spinand_continuous_read_disable(struct spinand_device *spinand)
+{
+	return spinand_upd_cfg(spinand, CFG_CONT_READ_ENABLE, 0);
+}
+
 static int spinand_ecc_enable(struct spinand_device *spinand,
 			      bool enable)
 {
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index badb4c1ac079..bb9288ffd898 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -154,6 +154,7 @@
 #define REG_CFG			0xb0
 #define CFG_OTP_ENABLE		BIT(6)
 #define CFG_ECC_ENABLE		BIT(4)
+#define CFG_CONT_READ_ENABLE	BIT(2)
 #define CFG_QUAD_ENABLE		BIT(0)
 
 /* status register */
-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 3/5] mtd: spinand: Add continuous read state
  2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 1/5] Add clk wizard and mxic host controller driver JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 2/5] mtd: spinand: Add support continuous read mode JaimeLiao
@ 2023-11-09 11:24 ` JaimeLiao
  2023-11-09 11:24 ` [PATCH v3 4/5] mtd: spinand: Add support continuous read operation JaimeLiao
  2023-11-09 11:25 ` [PATCH v3 5/5] mtd: spinand: macronix: Add continuous read support for Macronix Flash JaimeLiao
  4 siblings, 0 replies; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:24 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

Add continuous read state and initialize state to
default false.

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 drivers/mtd/nand/spi/core.c | 8 ++++++++
 include/linux/mtd/spinand.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index cfc295f5e31b..33ad401d3a34 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -193,6 +193,11 @@ static int spinand_init_quad_enable(struct spinand_device *spinand)
 			       enable ? CFG_QUAD_ENABLE : 0);
 }
 
+static void spinand_init_continuous_read(struct spinand_device *spinand)
+{
+	spinand->use_continuous_read = false;
+}
+
 static int spinand_continuous_read_enable(struct spinand_device *spinand)
 {
 	return spinand_upd_cfg(spinand, CFG_CONT_READ_ENABLE,
@@ -1307,6 +1312,9 @@ static int spinand_init(struct spinand_device *spinand)
 		goto err_cleanup_ecc_engine;
 	}
 
+	/* Init continuous read */
+	spinand_init_continuous_read(spinand);
+
 	return 0;
 
 err_cleanup_ecc_engine:
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index bb9288ffd898..263420b2338e 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -422,6 +422,7 @@ struct spinand_dirmap {
  *		because the spi-mem interface explicitly requests that buffers
  *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
  *		the stack
+ * @use_continuous_read: record the continuous read status
  * @manufacturer: SPI NAND manufacturer information
  * @priv: manufacturer private data
  */
@@ -450,6 +451,7 @@ struct spinand_device {
 	u8 *databuf;
 	u8 *oobbuf;
 	u8 *scratchbuf;
+	bool use_continuous_read;
 	const struct spinand_manufacturer *manufacturer;
 	void *priv;
 };
-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 4/5] mtd: spinand: Add support continuous read operation
  2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
                   ` (2 preceding siblings ...)
  2023-11-09 11:24 ` [PATCH v3 3/5] mtd: spinand: Add continuous read state JaimeLiao
@ 2023-11-09 11:24 ` JaimeLiao
  2023-11-09 11:25 ` [PATCH v3 5/5] mtd: spinand: macronix: Add continuous read support for Macronix Flash JaimeLiao
  4 siblings, 0 replies; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:24 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

The continuous read operation includes three phases:
Firstly, starting with the page read command and the 1st
page data will be read into the cache after the read latency tRD.
Secondly, Issuing the Read From Cache commands
(03h/0Bh/3Bh/6Bh/BBh/EBh) to read out the data from cache continuously.
After all the data is read out, the host should pull CS# high
to terminate this continuous read operation and wait tRST for the NAND
device resets read operation.

To prevent read data length bigger than controller limitation,
create a temperate operation for checking controller limitation
and read data length.

Exit continuous read mode and back to original read page method
if data length bigger than controller limitation.

Continuous reads have a positive impact when reading more than
one page and the column address is don't care in this operation,
a full page data will be read out for each page.

The performance of continuous read mode is as follows. Set the
flash to QUAD mode and run 25MHz direct mapping mode on the SPI
bus and use the MTD test module to show the performance of
continuous reads.

As below is the test result on two cases.
We could reduce time on continuous read when multiple page read.

===============Continuous======================
mtd_speedtest: MTD device: 0    count: 100
mtd_speedtest: MTD device size 268435456, eraseblock size 131072,
               page size 2048, count of eraseblocks 2048, pages per
               eraseblock 64, OOB size 64
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 100 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 1298 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 11053 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 1291 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 3240 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 1289 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 2909 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 45229 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 62135 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 60093 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 61244 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 61538 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 61835 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 60663 KiB/s
mtd_speedtest: finished
=================================================

===============Normal============================
mtd_speedtest: MTD device: 0    count: 100
mtd_speedtest: MTD device size 268435456, eraseblock size 131072,
	       page size 2048, count of eraseblocks 2048, pages per
	       eraseblock 64, OOB size 128
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 100 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 4467 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 2278 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 4447 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 2204 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 4479 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 2274 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 44982 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 33766 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 66876 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 67518 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 67792 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 67964 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 68101 KiB/s
mtd_speedtest: finished
=================================================

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 drivers/mtd/nand/spi/core.c | 116 ++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h |   1 +
 2 files changed, 117 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 33ad401d3a34..537302ea8281 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -386,6 +386,10 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 	if (req->datalen) {
 		buf = spinand->databuf;
 		nbytes = nanddev_page_size(nand);
+		if (spinand->use_continuous_read) {
+			buf = req->databuf.in;
+			nbytes = req->datalen;
+		}
 		column = 0;
 	}
 
@@ -415,6 +419,9 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 		buf += ret;
 	}
 
+	if (spinand->use_continuous_read)
+		goto finish;
+
 	if (req->datalen)
 		memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
 		       req->datalen);
@@ -430,6 +437,7 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 			       req->ooblen);
 	}
 
+finish:
 	return 0;
 }
 
@@ -646,6 +654,92 @@ static int spinand_write_page(struct spinand_device *spinand,
 	return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
 }
 
+static int spinand_mtd_continuous_read(struct mtd_info *mtd, loff_t from,
+				       struct mtd_oob_ops *ops,
+				       struct nand_io_iter *iter)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	int ret = 0;
+
+	/*
+	 * Prevent data length bigger than controller limitation, create
+	 * a temperate operation for checking.
+	 */
+	struct spi_mem_op op = SPINAND_READID_OP(0, 0, spinand->scratchbuf, ops->len);
+	ret = spi_mem_adjust_op_size(spinand->spimem, &op);
+	if (ret) {
+		return ret;
+	}
+
+	if (op.data.nbytes != ops->len) {
+		pr_debug("%s: data length bigger than controller limitation\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	if (from & (nanddev_page_size(nand) - 1)) {
+		pr_debug("%s: unaligned address\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	/*
+	 * Continuous read mode could reduce some operation in On-die ECC free
+	 * flash when read page sequentially.
+	 */
+	iter->req.type = NAND_PAGE_READ;
+	iter->req.mode = MTD_OPS_RAW;
+	iter->req.dataoffs = nanddev_offs_to_pos(nand, from, &iter->req.pos);
+	iter->req.databuf.in = ops->datbuf;
+	iter->req.datalen = ops->len;
+
+	ret = spinand_continuous_read_enable(spinand);
+	if (ret)
+		return ret;
+
+	spinand->use_continuous_read = true;
+
+	ret = spinand_select_target(spinand, iter->req.pos.target);
+	if (ret)
+		return ret;
+
+	/*
+	 * The continuous read operation including: firstly, starting with the
+	 * page read command and the 1 st page data will be read into the cache
+	 * after the read latency tRD. Secondly, Issuing the Read From Cache
+	 * commands (03h/0Bh/3Bh/6Bh/BBh/EBh) to read out the data from cache
+	 * continuously.
+	 *
+	 * The cache is divided into two halves, while one half of the cache is
+	 * outputting the data, the other half will be loaded for the new data;
+	 * therefore, the host can read out the data continuously from page to
+	 * page. Multiple of Read From Cache commands can be issued in one
+	 * continuous read operation, each Read From Cache command is required
+	 * to read multiple 4-byte data exactly; otherwise, the data output will
+	 * be out of sequence from one Read From Cache command to another Read
+	 * From Cache command.
+	 *
+	 * After all the data is read out, the host should pull CS# high to
+	 * terminate this continuous read operation and wait a 6us of tRST for
+	 * the NAND device resets read operation. The data output for each page
+	 * will always start from byte 0 and a full page data should be read out
+	 * for each page.
+	 */
+	ret = spinand_read_page(spinand, &iter->req);
+	if (ret)
+		goto continuous_read_error;
+
+	ret = spinand_reset_op(spinand);
+	if (ret)
+		goto continuous_read_error;
+
+continuous_read_error:
+	spinand->use_continuous_read = false;
+	ops->retlen = iter->req.datalen;
+
+	ret = spinand_continuous_read_disable(spinand);
+	return ret;
+}
+
 static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
 			    struct mtd_oob_ops *ops)
 {
@@ -665,6 +759,28 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
 
 	old_stats = mtd->ecc_stats;
 
+	/*
+	 * If the device support continuous read mode and read length larger
+	 * than one page size will enter the continuous read mode. This mode
+	 * helps avoid issuing a page read command and read from cache command
+	 * again, and improves read performance for continuous addresses.
+	 */
+	if ((spinand->flags & SPINAND_HAS_CONT_READ_BIT) &&
+	    (ops->len > nanddev_page_size(nand))) {
+		ret = spinand_mtd_continuous_read(mtd, from, ops, &iter);
+
+		mutex_unlock(&spinand->lock);
+
+		if (ret == -ENOTSUPP)
+			goto read_each_page;
+
+		if (ecc_failed && !ret)
+			ret = -EBADMSG;
+
+		return ret ? ret : max_bitflips;
+	}
+
+read_each_page:
 	nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) {
 		if (disable_ecc)
 			iter.req.mode = MTD_OPS_RAW;
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 263420b2338e..4b8fe27eb6b8 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -313,6 +313,7 @@ struct spinand_ecc_info {
 
 #define SPINAND_HAS_QE_BIT		BIT(0)
 #define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
+#define SPINAND_HAS_CONT_READ_BIT	BIT(2)
 
 /**
  * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH v3 5/5]  mtd: spinand: macronix: Add continuous read support for Macronix Flash
  2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
                   ` (3 preceding siblings ...)
  2023-11-09 11:24 ` [PATCH v3 4/5] mtd: spinand: Add support continuous read operation JaimeLiao
@ 2023-11-09 11:25 ` JaimeLiao
  4 siblings, 0 replies; 8+ messages in thread
From: JaimeLiao @ 2023-11-09 11:25 UTC (permalink / raw)
  To: linux-mtd, miquel.raynal, richard; +Cc: jaimeliao, jaimeliao.tw, angyanyu13

Add continuous read flag for those flash with continuous read
feature.

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 drivers/mtd/nand/spi/macronix.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 3dfc7e1e5241..69c9c9dfe672 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -127,7 +127,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35LF4GE4AD",
@@ -137,7 +137,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35LF1G24AD",
@@ -215,7 +215,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF2G14AC",
@@ -245,7 +245,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF2GE4AC",
@@ -255,7 +255,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF1G14AC",
@@ -285,7 +285,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF1GE4AC",
@@ -295,7 +295,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     SPINAND_HAS_QE_BIT | SPINAND_HAS_CONT_READ_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
 
-- 
2.17.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH v3 1/5] Add clk wizard and mxic host controller driver
  2023-11-09 11:24 ` [PATCH v3 1/5] Add clk wizard and mxic host controller driver JaimeLiao
@ 2023-11-09 14:13   ` Miquel Raynal
  2023-11-10  1:18     ` liao jaime
  0 siblings, 1 reply; 8+ messages in thread
From: Miquel Raynal @ 2023-11-09 14:13 UTC (permalink / raw)
  To: JaimeLiao; +Cc: linux-mtd, richard, jaimeliao, angyanyu13

Hi Jaime,

jaimeliao.tw@gmail.com wrote on Thu,  9 Nov 2023 19:24:56 +0800:

> Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>

You need to split this patch and create a dedicated series with it.

One patch for the clock wizard.
One patch (or more) for the DT changes.
Possibly a binding patch.

[...]

> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> index 60c9f3048ac9..28c324d7200a 100644
> --- a/drivers/spi/spi-mxic.c
> +++ b/drivers/spi/spi-mxic.c
> @@ -323,7 +323,7 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
>  		       (op->addr.dtr ? OP_ADDR_DDR : 0);
>  
>  	if (op->dummy.nbytes)
> -		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
> +		cfg |= OP_DUMMY_CYC((op->dummy.nbytes) * (op->data.buswidth));
>  
>  	/* Direct mapping data.nbytes field is not populated */
>  	if (data_len) {
> @@ -390,7 +390,7 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
>  static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
>  					u64 offs, size_t len, void *buf)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> +	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);

This and all changes below make no sense and should be dropped.

>  	int ret;
>  	u32 sts;
>  
> @@ -434,7 +434,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
>  					 u64 offs, size_t len,
>  					 const void *buf)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> +	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
>  	u32 sts;
>  	int ret;
>  
> @@ -481,9 +481,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
>  		return false;
>  
> -	if (op->data.nbytes && op->dummy.nbytes &&
> -	    op->data.buswidth != op->dummy.buswidth)
> -		return false;
> +	//if (op->data.nbytes && op->dummy.nbytes &&
> +	//    op->data.buswidth != op->dummy.buswidth)
> +	//	return false;
>  
>  	if (op->addr.nbytes > 7)
>  		return false;
> @@ -493,7 +493,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  
>  static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> +	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
>  
>  	if (!mxic->linear.map)
>  		return -EINVAL;
> @@ -510,7 +510,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
>  static int mxic_spi_mem_exec_op(struct spi_mem *mem,
>  				const struct spi_mem_op *op)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(mem->spi->controller);
> +	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
>  	int i, ret;
>  	u8 addr[8], cmd[2];
>  
> @@ -543,7 +543,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
>  	if (ret)
>  		goto out;
>  
> -	ret = mxic_spi_data_xfer(mxic, NULL, NULL, op->dummy.nbytes);
> +	ret = mxic_spi_data_xfer(mxic, NULL, NULL, (op->dummy.nbytes) * (op->data.buswidth));
>  	if (ret)
>  		goto out;
>  
> @@ -565,9 +565,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
>  static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
>  	.supports_op = mxic_spi_mem_supports_op,
>  	.exec_op = mxic_spi_mem_exec_op,
> -	.dirmap_create = mxic_spi_mem_dirmap_create,
> -	.dirmap_read = mxic_spi_mem_dirmap_read,
> -	.dirmap_write = mxic_spi_mem_dirmap_write,
> +	//.dirmap_create = mxic_spi_mem_dirmap_create,
> +	//.dirmap_read = mxic_spi_mem_dirmap_read,
> +	//.dirmap_write = mxic_spi_mem_dirmap_write,
>  };
>  
>  static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
> @@ -577,7 +577,7 @@ static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
>  
>  static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(spi->controller);
> +	struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
>  
>  	if (!lvl) {
>  		writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
> @@ -592,11 +592,11 @@ static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
>  	}
>  }
>  
> -static int mxic_spi_transfer_one(struct spi_controller *host,
> +static int mxic_spi_transfer_one(struct spi_master *master,
>  				 struct spi_device *spi,
>  				 struct spi_transfer *t)
>  {
> -	struct mxic_spi *mxic = spi_controller_get_devdata(host);
> +	struct mxic_spi *mxic = spi_master_get_devdata(master);
>  	unsigned int busw = OP_BUSW_1;
>  	int ret;
>  
> @@ -632,7 +632,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host,
>  	if (ret)
>  		return ret;
>  
> -	spi_finalize_current_transfer(host);
> +	spi_finalize_current_transfer(master);
>  
>  	return 0;
>  }
> @@ -713,8 +713,8 @@ static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
>  
>  static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
>  {
> -	struct spi_controller *host = dev_get_drvdata(dev);
> -	struct mxic_spi *mxic = spi_controller_get_devdata(host);
> +	struct spi_master *master = dev_get_drvdata(dev);
> +	struct mxic_spi *mxic = spi_master_get_devdata(master);
>  
>  	mxic_spi_clk_disable(mxic);
>  	clk_disable_unprepare(mxic->ps_clk);
> @@ -724,8 +724,8 @@ static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
>  
>  static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
>  {
> -	struct spi_controller *host = dev_get_drvdata(dev);
> -	struct mxic_spi *mxic = spi_controller_get_devdata(host);
> +	struct spi_master *master = dev_get_drvdata(dev);
> +	struct mxic_spi *mxic = spi_master_get_devdata(master);
>  	int ret;
>  
>  	ret = clk_prepare_enable(mxic->ps_clk);
> @@ -744,21 +744,21 @@ static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
>  
>  static int mxic_spi_probe(struct platform_device *pdev)
>  {
> -	struct spi_controller *host;
> +	struct spi_master *master;
>  	struct resource *res;
>  	struct mxic_spi *mxic;
>  	int ret;
>  
> -	host = devm_spi_alloc_host(&pdev->dev, sizeof(struct mxic_spi));
> -	if (!host)
> +	master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
> +	if (!master)
>  		return -ENOMEM;
>  
> -	platform_set_drvdata(pdev, host);
> +	platform_set_drvdata(pdev, master);
>  
> -	mxic = spi_controller_get_devdata(host);
> +	mxic = spi_master_get_devdata(master);
>  	mxic->dev = &pdev->dev;
>  
> -	host->dev.of_node = pdev->dev.of_node;
> +	master->dev.of_node = pdev->dev.of_node;
>  
>  	mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
>  	if (IS_ERR(mxic->ps_clk))
> @@ -786,19 +786,19 @@ static int mxic_spi_probe(struct platform_device *pdev)
>  	}
>  
>  	pm_runtime_enable(&pdev->dev);
> -	host->auto_runtime_pm = true;
> +	master->auto_runtime_pm = true;
>  
> -	host->num_chipselect = 1;
> -	host->mem_ops = &mxic_spi_mem_ops;
> -	host->mem_caps = &mxic_spi_mem_caps;
> +	master->num_chipselect = 1;
> +	master->mem_ops = &mxic_spi_mem_ops;
> +	master->mem_caps = &mxic_spi_mem_caps;
>  
> -	host->set_cs = mxic_spi_set_cs;
> -	host->transfer_one = mxic_spi_transfer_one;
> -	host->bits_per_word_mask = SPI_BPW_MASK(8);
> -	host->mode_bits = SPI_CPOL | SPI_CPHA |
> -			  SPI_RX_DUAL | SPI_TX_DUAL |
> -			  SPI_RX_QUAD | SPI_TX_QUAD |
> -			  SPI_RX_OCTAL | SPI_TX_OCTAL;
> +	master->set_cs = mxic_spi_set_cs;
> +	master->transfer_one = mxic_spi_transfer_one;
> +	master->bits_per_word_mask = SPI_BPW_MASK(8);
> +	master->mode_bits = SPI_CPOL | SPI_CPHA |
> +			SPI_RX_DUAL | SPI_TX_DUAL |
> +			SPI_RX_QUAD | SPI_TX_QUAD |
> +			SPI_RX_OCTAL | SPI_TX_OCTAL;
>  
>  	mxic_spi_hw_init(mxic);
>  
> @@ -808,9 +808,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	ret = spi_register_controller(host);
> +	ret = spi_register_master(master);
>  	if (ret) {
> -		dev_err(&pdev->dev, "spi_register_controller failed\n");
> +		dev_err(&pdev->dev, "spi_register_master failed\n");
>  		pm_runtime_disable(&pdev->dev);
>  		mxic_spi_mem_ecc_remove(mxic);
>  	}
> @@ -820,12 +820,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
>  
>  static void mxic_spi_remove(struct platform_device *pdev)
>  {
> -	struct spi_controller *host = platform_get_drvdata(pdev);
> -	struct mxic_spi *mxic = spi_controller_get_devdata(host);
> +	struct spi_master *master = platform_get_drvdata(pdev);
> +	struct mxic_spi *mxic = spi_master_get_devdata(master);
>  
>  	pm_runtime_disable(&pdev->dev);
>  	mxic_spi_mem_ecc_remove(mxic);
> -	spi_unregister_controller(host);
> +	spi_unregister_master(master);
>  }
>  
>  static const struct of_device_id mxic_spi_of_ids[] = {


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH v3 1/5] Add clk wizard and mxic host controller driver
  2023-11-09 14:13   ` Miquel Raynal
@ 2023-11-10  1:18     ` liao jaime
  0 siblings, 0 replies; 8+ messages in thread
From: liao jaime @ 2023-11-10  1:18 UTC (permalink / raw)
  To: Miquel Raynal; +Cc: linux-mtd, richard, jaimeliao, angyanyu13

Hi Miquel

Sorry for including a faulty patch in this patchwork.
I will remove it and send a new one.

Thanks
Jaime

>
> Hi Jaime,
>
> jaimeliao.tw@gmail.com wrote on Thu,  9 Nov 2023 19:24:56 +0800:
>
> > Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
>
> You need to split this patch and create a dedicated series with it.
>
> One patch for the clock wizard.
> One patch (or more) for the DT changes.
> Possibly a binding patch.
>
> [...]
>
> > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > index 60c9f3048ac9..28c324d7200a 100644
> > --- a/drivers/spi/spi-mxic.c
> > +++ b/drivers/spi/spi-mxic.c
> > @@ -323,7 +323,7 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
> >                      (op->addr.dtr ? OP_ADDR_DDR : 0);
> >
> >       if (op->dummy.nbytes)
> > -             cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
> > +             cfg |= OP_DUMMY_CYC((op->dummy.nbytes) * (op->data.buswidth));
> >
> >       /* Direct mapping data.nbytes field is not populated */
> >       if (data_len) {
> > @@ -390,7 +390,7 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
> >  static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
> >                                       u64 offs, size_t len, void *buf)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
>
> This and all changes below make no sense and should be dropped.
>
> >       int ret;
> >       u32 sts;
> >
> > @@ -434,7 +434,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> >                                        u64 offs, size_t len,
> >                                        const void *buf)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
> >       u32 sts;
> >       int ret;
> >
> > @@ -481,9 +481,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >           op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> >               return false;
> >
> > -     if (op->data.nbytes && op->dummy.nbytes &&
> > -         op->data.buswidth != op->dummy.buswidth)
> > -             return false;
> > +     //if (op->data.nbytes && op->dummy.nbytes &&
> > +     //    op->data.buswidth != op->dummy.buswidth)
> > +     //      return false;
> >
> >       if (op->addr.nbytes > 7)
> >               return false;
> > @@ -493,7 +493,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >
> >  static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
> >
> >       if (!mxic->linear.map)
> >               return -EINVAL;
> > @@ -510,7 +510,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
> >  static int mxic_spi_mem_exec_op(struct spi_mem *mem,
> >                               const struct spi_mem_op *op)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(mem->spi->controller);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
> >       int i, ret;
> >       u8 addr[8], cmd[2];
> >
> > @@ -543,7 +543,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
> >       if (ret)
> >               goto out;
> >
> > -     ret = mxic_spi_data_xfer(mxic, NULL, NULL, op->dummy.nbytes);
> > +     ret = mxic_spi_data_xfer(mxic, NULL, NULL, (op->dummy.nbytes) * (op->data.buswidth));
> >       if (ret)
> >               goto out;
> >
> > @@ -565,9 +565,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
> >  static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
> >       .supports_op = mxic_spi_mem_supports_op,
> >       .exec_op = mxic_spi_mem_exec_op,
> > -     .dirmap_create = mxic_spi_mem_dirmap_create,
> > -     .dirmap_read = mxic_spi_mem_dirmap_read,
> > -     .dirmap_write = mxic_spi_mem_dirmap_write,
> > +     //.dirmap_create = mxic_spi_mem_dirmap_create,
> > +     //.dirmap_read = mxic_spi_mem_dirmap_read,
> > +     //.dirmap_write = mxic_spi_mem_dirmap_write,
> >  };
> >
> >  static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
> > @@ -577,7 +577,7 @@ static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
> >
> >  static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(spi->controller);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
> >
> >       if (!lvl) {
> >               writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
> > @@ -592,11 +592,11 @@ static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
> >       }
> >  }
> >
> > -static int mxic_spi_transfer_one(struct spi_controller *host,
> > +static int mxic_spi_transfer_one(struct spi_master *master,
> >                                struct spi_device *spi,
> >                                struct spi_transfer *t)
> >  {
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(host);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(master);
> >       unsigned int busw = OP_BUSW_1;
> >       int ret;
> >
> > @@ -632,7 +632,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host,
> >       if (ret)
> >               return ret;
> >
> > -     spi_finalize_current_transfer(host);
> > +     spi_finalize_current_transfer(master);
> >
> >       return 0;
> >  }
> > @@ -713,8 +713,8 @@ static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
> >
> >  static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
> >  {
> > -     struct spi_controller *host = dev_get_drvdata(dev);
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(host);
> > +     struct spi_master *master = dev_get_drvdata(dev);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(master);
> >
> >       mxic_spi_clk_disable(mxic);
> >       clk_disable_unprepare(mxic->ps_clk);
> > @@ -724,8 +724,8 @@ static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
> >
> >  static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
> >  {
> > -     struct spi_controller *host = dev_get_drvdata(dev);
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(host);
> > +     struct spi_master *master = dev_get_drvdata(dev);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(master);
> >       int ret;
> >
> >       ret = clk_prepare_enable(mxic->ps_clk);
> > @@ -744,21 +744,21 @@ static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
> >
> >  static int mxic_spi_probe(struct platform_device *pdev)
> >  {
> > -     struct spi_controller *host;
> > +     struct spi_master *master;
> >       struct resource *res;
> >       struct mxic_spi *mxic;
> >       int ret;
> >
> > -     host = devm_spi_alloc_host(&pdev->dev, sizeof(struct mxic_spi));
> > -     if (!host)
> > +     master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
> > +     if (!master)
> >               return -ENOMEM;
> >
> > -     platform_set_drvdata(pdev, host);
> > +     platform_set_drvdata(pdev, master);
> >
> > -     mxic = spi_controller_get_devdata(host);
> > +     mxic = spi_master_get_devdata(master);
> >       mxic->dev = &pdev->dev;
> >
> > -     host->dev.of_node = pdev->dev.of_node;
> > +     master->dev.of_node = pdev->dev.of_node;
> >
> >       mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
> >       if (IS_ERR(mxic->ps_clk))
> > @@ -786,19 +786,19 @@ static int mxic_spi_probe(struct platform_device *pdev)
> >       }
> >
> >       pm_runtime_enable(&pdev->dev);
> > -     host->auto_runtime_pm = true;
> > +     master->auto_runtime_pm = true;
> >
> > -     host->num_chipselect = 1;
> > -     host->mem_ops = &mxic_spi_mem_ops;
> > -     host->mem_caps = &mxic_spi_mem_caps;
> > +     master->num_chipselect = 1;
> > +     master->mem_ops = &mxic_spi_mem_ops;
> > +     master->mem_caps = &mxic_spi_mem_caps;
> >
> > -     host->set_cs = mxic_spi_set_cs;
> > -     host->transfer_one = mxic_spi_transfer_one;
> > -     host->bits_per_word_mask = SPI_BPW_MASK(8);
> > -     host->mode_bits = SPI_CPOL | SPI_CPHA |
> > -                       SPI_RX_DUAL | SPI_TX_DUAL |
> > -                       SPI_RX_QUAD | SPI_TX_QUAD |
> > -                       SPI_RX_OCTAL | SPI_TX_OCTAL;
> > +     master->set_cs = mxic_spi_set_cs;
> > +     master->transfer_one = mxic_spi_transfer_one;
> > +     master->bits_per_word_mask = SPI_BPW_MASK(8);
> > +     master->mode_bits = SPI_CPOL | SPI_CPHA |
> > +                     SPI_RX_DUAL | SPI_TX_DUAL |
> > +                     SPI_RX_QUAD | SPI_TX_QUAD |
> > +                     SPI_RX_OCTAL | SPI_TX_OCTAL;
> >
> >       mxic_spi_hw_init(mxic);
> >
> > @@ -808,9 +808,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
> >               return ret;
> >       }
> >
> > -     ret = spi_register_controller(host);
> > +     ret = spi_register_master(master);
> >       if (ret) {
> > -             dev_err(&pdev->dev, "spi_register_controller failed\n");
> > +             dev_err(&pdev->dev, "spi_register_master failed\n");
> >               pm_runtime_disable(&pdev->dev);
> >               mxic_spi_mem_ecc_remove(mxic);
> >       }
> > @@ -820,12 +820,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
> >
> >  static void mxic_spi_remove(struct platform_device *pdev)
> >  {
> > -     struct spi_controller *host = platform_get_drvdata(pdev);
> > -     struct mxic_spi *mxic = spi_controller_get_devdata(host);
> > +     struct spi_master *master = platform_get_drvdata(pdev);
> > +     struct mxic_spi *mxic = spi_master_get_devdata(master);
> >
> >       pm_runtime_disable(&pdev->dev);
> >       mxic_spi_mem_ecc_remove(mxic);
> > -     spi_unregister_controller(host);
> > +     spi_unregister_master(master);
> >  }
> >
> >  static const struct of_device_id mxic_spi_of_ids[] = {
>
>
> Thanks,
> Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

end of thread, other threads:[~2023-11-10  1:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-09 11:24 [PATCH v3 0/5] mtd: spinand: Add continuous read mode support JaimeLiao
2023-11-09 11:24 ` [PATCH v3 1/5] Add clk wizard and mxic host controller driver JaimeLiao
2023-11-09 14:13   ` Miquel Raynal
2023-11-10  1:18     ` liao jaime
2023-11-09 11:24 ` [PATCH v3 2/5] mtd: spinand: Add support continuous read mode JaimeLiao
2023-11-09 11:24 ` [PATCH v3 3/5] mtd: spinand: Add continuous read state JaimeLiao
2023-11-09 11:24 ` [PATCH v3 4/5] mtd: spinand: Add support continuous read operation JaimeLiao
2023-11-09 11:25 ` [PATCH v3 5/5] mtd: spinand: macronix: Add continuous read support for Macronix Flash JaimeLiao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox