Devicetree
 help / color / mirror / Atom feed
* [PATCH 5/5] ARM: dts: dra7xx: Add stdout-path property
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla
In-Reply-To: <20170117040336.21700-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

Add stdout-path property in /chosen node so that earlycon can be
used by just adding earlycon in bootargs.

Tested-by: Vignesh R <vigneshr-l0cyMroinI0@public.gmane.org>
Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
---
 arch/arm/boot/dts/dra7-evm.dts          | 4 ++++
 arch/arm/boot/dts/dra72-evm-common.dtsi | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 132f2be10889..b3923c049edb 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -21,6 +21,10 @@
 		reg = <0x0 0x80000000 0x0 0x60000000>; /* 1536 MB */
 	};
 
+	chosen {
+		stdout-path = &uart1;
+	};
+
 	evm_3v3_sd: fixedregulator-sd {
 		compatible = "regulator-fixed";
 		regulator-name = "evm_3v3_sd";
diff --git a/arch/arm/boot/dts/dra72-evm-common.dtsi b/arch/arm/boot/dts/dra72-evm-common.dtsi
index e50fbeea96e0..45b62138cbde 100644
--- a/arch/arm/boot/dts/dra72-evm-common.dtsi
+++ b/arch/arm/boot/dts/dra72-evm-common.dtsi
@@ -18,6 +18,10 @@
 		display0 = &hdmi0;
 	};
 
+	chosen {
+		stdout-path = &uart1;
+	};
+
 	evm_12v0: fixedregulator-evm12v0 {
 		/* main supply */
 		compatible = "regulator-fixed";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 4/5] ARM: dts: am57xx: Add stdout-path property
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla
In-Reply-To: <20170117040336.21700-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

Add stdout-path property in /chosen node so that earlycon can be
used by just adding earlycon in bootargs.

Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
---
 arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi | 4 ++++
 arch/arm/boot/dts/am57xx-idk-common.dtsi        | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
index 78bee26361f1..3a95db7da71f 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
@@ -22,6 +22,10 @@
 		display0 = &hdmi0;
 	};
 
+	chosen {
+		stdout-path = &uart3;
+	};
+
 	memory@0 {
 		device_type = "memory";
 		reg = <0x0 0x80000000 0x0 0x80000000>;
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index 814a720d5c3d..0d341c545b01 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -14,6 +14,10 @@
 		rtc1 = &rtc;
 	};
 
+	chosen {
+		stdout-path = &uart3;
+	};
+
 	vmain: fixedregulator-vmain {
 		compatible = "regulator-fixed";
 		regulator-name = "VMAIN";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 3/5] ARM: dts: am43xx: Add stdout-path property
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla
In-Reply-To: <20170117040336.21700-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

Add stdout-path property in /chosen node so that earlycon can be
used by just adding earlycon in bootargs.

Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
---
 arch/arm/boot/dts/am437x-gp-evm.dts  | 4 ++++
 arch/arm/boot/dts/am437x-idk-evm.dts | 4 ++++
 arch/arm/boot/dts/am437x-sk-evm.dts  | 4 ++++
 arch/arm/boot/dts/am43x-epos-evm.dts | 4 ++++
 4 files changed, 16 insertions(+)

diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 957840cc7b78..a4f31739057f 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -23,6 +23,10 @@
 		display0 = &lcd0;
 	};
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	evm_v3_3d: fixedregulator-v3_3d {
 		compatible = "regulator-fixed";
 		regulator-name = "evm_v3_3d";
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
index b76a7c0264a5..c1f7f9336e64 100644
--- a/arch/arm/boot/dts/am437x-idk-evm.dts
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -18,6 +18,10 @@
 	model = "TI AM437x Industrial Development Kit";
 	compatible = "ti,am437x-idk-evm","ti,am4372","ti,am43";
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	v24_0d: fixed-regulator-v24_0d {
 		compatible = "regulator-fixed";
 		regulator-name = "V24_0D";
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 319d94205350..4dc54bee2f36 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -24,6 +24,10 @@
 		display0 = &lcd0;
 	};
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	/* fixed 32k external oscillator clock */
 	clk_32k_rtc: clk_32k_rtc {
 		#clock-cells = <0>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 9d35c3f07cad..9acd4ccdec4e 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -24,6 +24,10 @@
 		display0 = &lcd0;
 	};
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	vmmcsd_fixed: fixedregulator-sd {
 		compatible = "regulator-fixed";
 		regulator-name = "vmmcsd_fixed";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 2/5] ARM: dts: am33xx: Add stdout-path property
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla
In-Reply-To: <20170117040336.21700-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

Add stdout-path property in /chosen node so that earlycon can be
used by just adding earlycon in bootargs.

Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
---
 arch/arm/boot/dts/am335x-evm.dts   | 4 ++++
 arch/arm/boot/dts/am335x-evmsk.dts | 4 ++++
 arch/arm/boot/dts/am335x-icev2.dts | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index c2186ec2834b..1c37a7c1ea17 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -25,6 +25,10 @@
 		reg = <0x80000000 0x10000000>; /* 256 MB */
 	};
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	vbat: fixedregulator0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vbat";
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index e2548d1ce753..9e43c443738a 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -32,6 +32,10 @@
 		reg = <0x80000000 0x10000000>; /* 256 MB */
 	};
 
+	chosen {
+		stdout-path = &uart0;
+	};
+
 	vbat: fixedregulator0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vbat";
diff --git a/arch/arm/boot/dts/am335x-icev2.dts b/arch/arm/boot/dts/am335x-icev2.dts
index 1463df3b5b19..ff9417ce93c0 100644
--- a/arch/arm/boot/dts/am335x-icev2.dts
+++ b/arch/arm/boot/dts/am335x-icev2.dts
@@ -24,6 +24,10 @@
 		reg = <0x80000000 0x10000000>; /* 256 MB */
 	};
 
+	chosen {
+		stdout-path = &uart3;
+	};
+
 	vbat: fixedregulator0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vbat";
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 1/5] ARM: OMAP2+: omap_hwmod: Add support for earlycon
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla
In-Reply-To: <20170117040336.21700-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

Hwmod core tries to reset and idles each IP that is registered with hwmod.
In case of earlycon, that specific uart IP cannot be reset or keep it in
idle state else earlycon hangs once hwmod resets that uart IP. So add support
to not reset uart that is being used as earlycon only if CONFIG_SERIAL_EARLYCON
is enabled.

Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-omap2/omap_hwmod.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e8b988714a09..7b1ac69a2209 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -3249,6 +3249,39 @@ int __init omap_hwmod_setup_one(const char *oh_name)
 }
 
 /**
+ * omap_hwmod_setup_earlycon_flags - set up flags for early console
+ *
+ * Enable DEBUG_OMAPUART_FLAGS for uart hwmod that is being used as
+ * early concole so that hwmod core doesn't reset and keep it in idle
+ * that specific uart.
+ */
+#ifdef CONFIG_SERIAL_EARLYCON
+static void __init omap_hwmod_setup_earlycon_flags(void)
+{
+	struct device_node *np;
+	struct omap_hwmod *oh;
+	const char *uart;
+
+	np = of_find_node_by_path("/chosen");
+	if (!np)
+		np = of_find_node_by_path("/chosen@0");
+
+	if (np) {
+		uart = of_get_property(np, "stdout-path", NULL);
+		if (uart) {
+			np = of_find_node_by_path(uart);
+			if (np) {
+				uart = of_get_property(np, "ti,hwmods", NULL);
+				oh = omap_hwmod_lookup(uart);
+				if (oh)
+					oh->flags |= DEBUG_OMAPUART_FLAGS;
+			}
+		}
+	}
+}
+#endif
+
+/**
  * omap_hwmod_setup_all - set up all registered IP blocks
  *
  * Initialize and set up all IP blocks registered with the hwmod code.
@@ -3261,6 +3294,9 @@ static int __init omap_hwmod_setup_all(void)
 	_ensure_mpu_hwmod_is_setup(NULL);
 
 	omap_hwmod_for_each(_init, NULL);
+#ifdef CONFIG_SERIAL_EARLYCON
+	omap_hwmod_setup_earlycon_flags();
+#endif
 	omap_hwmod_for_each(_setup, NULL);
 
 	return 0;
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 0/5] ARM: OMAP2+: Add earlycon support
From: Lokesh Vutla @ 2017-01-17  4:03 UTC (permalink / raw)
  To: Tony Lindgren, Linux OMAP Mailing List
  Cc: Device Tree Mailing List, Rob Herring, Tero Kristo, Sekhar Nori,
	Vignesh R, Nishanth Menon, Lokesh Vutla

This series adds earlycon support for all am33xx, am43xx, am57xx, dra7xx
based TI platforms. With this series just passing "earlycon" in bootargs
is sufficient for early debug.

Tested with omap2plus_defconfig + CONFIG_SERIAL_8250.

Lokesh Vutla (5):
  ARM: OMAP2+: omap_hwmod: Add support for earlycon
  ARM: dts: am33xx: Add stdout-path property
  ARM: dts: am43xx: Add stdout-path property
  ARM: dts: am57xx: Add stdout-path property
  ARM: dts: dra7xx: Add stdout-path property

 arch/arm/boot/dts/am335x-evm.dts                |  4 +++
 arch/arm/boot/dts/am335x-evmsk.dts              |  4 +++
 arch/arm/boot/dts/am335x-icev2.dts              |  4 +++
 arch/arm/boot/dts/am437x-gp-evm.dts             |  4 +++
 arch/arm/boot/dts/am437x-idk-evm.dts            |  4 +++
 arch/arm/boot/dts/am437x-sk-evm.dts             |  4 +++
 arch/arm/boot/dts/am43x-epos-evm.dts            |  4 +++
 arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi |  4 +++
 arch/arm/boot/dts/am57xx-idk-common.dtsi        |  4 +++
 arch/arm/boot/dts/dra7-evm.dts                  |  4 +++
 arch/arm/boot/dts/dra72-evm-common.dtsi         |  4 +++
 arch/arm/mach-omap2/omap_hwmod.c                | 36 +++++++++++++++++++++++++
 12 files changed, 80 insertions(+)

-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 17/22] power: supply: add battery driver for AXP20X and AXP22X PMICs
From: Sebastian Reichel @ 2017-01-17  3:46 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: mark.rutland, devicetree, lars, linux-pm, linux-iio, linux,
	linux-kernel, wens, robh+dt, linux-arm-kernel, pmeerw, knaack.h,
	maxime.ripard, bonbons, lee.jones, thomas.petazzoni, jic23,
	icenowy
In-Reply-To: <20170102163723.7939-18-quentin.schulz@free-electrons.com>


[-- Attachment #1.1: Type: text/plain, Size: 2347 bytes --]

Hi Quentin,

Just a couple of small things in this patch.

On Mon, Jan 02, 2017 at 05:37:17PM +0100, Quentin Schulz wrote:
> [...]
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
> +				  &reg);
> +		if (ret)
> +			return ret;
> +
> +		if (reg & AXP20X_PWR_STATUS_BAT_CHARGING)
> +			chan = axp20x_batt->batt_chrg_i;
> +		else
> +			chan = axp20x_batt->batt_dischrg_i;
> +
> +		ret = iio_read_channel_processed(chan, &val->intval);
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * IIO framework gives mV but Power Supply framework gives µV.
> +		 */

Nit: Volt -> Ampere

> +		val->intval *= 1000;
> +		break;
>
> [...]
>
> +static int axp20x_power_probe(struct platform_device *pdev)
> +{
> +	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
> +	struct axp20x_batt_ps *axp20x_batt;
> +	struct power_supply_config psy_cfg = {};
> +
> +	axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
> +				   GFP_KERNEL);
> +	if (!axp20x_batt)
> +		return -ENOMEM;
> +
> +	axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");
> +	if (IS_ERR(axp20x_batt->batt_v)) {
> +		if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV)
> +			return -EPROBE_DEFER;
> +		return PTR_ERR(axp20x_batt->batt_v);
> +	}
> +
> +	axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,
> +							"batt_chrg_i");
> +	if (IS_ERR(axp20x_batt->batt_chrg_i)) {
> +		if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV)
> +			return -EPROBE_DEFER;
> +		return PTR_ERR(axp20x_batt->batt_chrg_i);
> +	}
> +
> +	axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,
> +							   "batt_dischrg_i");
> +	if (IS_ERR(axp20x_batt->batt_dischrg_i)) {
> +		if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV)
> +			return -EPROBE_DEFER;
> +		return PTR_ERR(axp20x_batt->batt_dischrg_i);
> +	}
> +
> +	axp20x_batt->regmap = axp20x->regmap;
> +	platform_set_drvdata(pdev, axp20x_batt);

Please use drv_get_regmap(pdev->dev.parent, NULL) instead (and drop
axp20x).

> +	psy_cfg.drv_data = axp20x_batt;
> +	psy_cfg.of_node = pdev->dev.of_node;
> +
> +	axp20x_batt->axp_id = (int)of_device_get_match_data(&pdev->dev);

use (uintptr_t) to avoid compiler warnings on systems with sizeof
int != sizeof ptr.

-- Sebastian

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v1 2/2] arm: dts: mt2701: add nor flash node
From: Thomas Petazzoni @ 2017-01-17  3:36 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Marek Vasut, Rob Herring, Mark Rutland, devicetree, Guochun Mao,
	Richard Weinberger, Russell King, linux-kernel, linux-mtd,
	Matthias Brugger, linux-mediatek, Cyrille Pitchen, Brian Norris,
	David Woodhouse, linux-arm-kernel
In-Reply-To: <20170116094032.6f471f11@bbrezillon>

Hello,

(Side note: you guys should learn about stripping irrelevant parts of
an e-mail when replying!)

On Mon, 16 Jan 2017 09:40:32 +0100, Boris Brezillon wrote:

> > Well this is OK I guess, but then you can also use "mediatek,mt8173-nor"
> > as the oldest supported compatible and be done with it, no ? It looks a
> > bit crappy though, I admit that ...
> 
> Let's stop bikeshedding and wait for DT maintainers feedback
> before taking a decision ;-).
> 
> Rob, Mark, any opinion?

I agree that a clarification would be good. There are really two
options:

 1. Have two compatible strings in the DT, the one that matches the
    exact SoC where the IP is found (first compatible string) and the
    one that matches some other SoC where the same IP is found (second
    compatible string). Originally, Linux only supports the second
    compatible string in its device driver, but if it happens that a
    difference is found between two IPs that we thought were the same,
    we can add support for the first compatible string in the driver,
    with a slightly different behavior.

 2. Have a single compatible string in the DT, matching the exact SoC
    where the IP is found. This involves adding immediately this
    compatible string in the corresponding driver.

I've not really been able to figure out which of the two options is the
most future-proof/appropriate.

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* Re: [PATCH 1/2] ARM64: dts: meson-gxm: Add R-Box Pro
From: Andreas Färber @ 2017-01-17  3:35 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Mark Rutland, devicetree, Kevin Hilman, Will Deacon, linux-kernel,
	Rob Herring, Catalin Marinas, Carlo Caione, linux-arm-kernel
In-Reply-To: <20170117030611.23827-2-afaerber@suse.de>

Am 17.01.2017 um 04:06 schrieb Andreas Färber:
> +	leds {
> +		compatible = "gpio-leds";
> +
> +		blue {
> +			label = "rbox-pro:blue:on";
> +			gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
> +			default-state = "on";
> +		};
> +
> +		red {
> +			label = "rbox-pro:red:standby";
> +			gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>;
> +			default-state = "off";
> +			retain-state-suspended;
> +			panic-indicator;
> +		};
> +	};

The original property names for these two were led and red. If anyone
has better label names than the above, please speak up. Ditto for
vega-s95. On the odroidc2 it's called alive but uses heartbeat there.

The vendor device tree had a third "mcu" GPIO in the sysled node,
GPIOAO_6, which leads to immediate power-off. I tried using
"gpio-poweroff" to configure this pin, but that driver fails to
initialize because some pm callback is already registered - I assume
from psci, which apparently succeeds to power-off the system, too. For
comparison, the S905 based Vega S95 Telos has no such mcu property. Any
thoughts?

Also, any ideas how best to switch from blue to red for suspend? Add
pinctrl properties above? systemd service doing echo from userspace? I
assume in Android the Amlogic sysled driver handles all that logic -
didn't find any suspend equivalent to gpio-poweroff.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v1 2/2] arm: dts: mt2701: add nor flash node
From: Thomas Petazzoni @ 2017-01-17  3:32 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mark Rutland, devicetree, Guochun Mao, Richard Weinberger,
	Russell King, linux-kernel, Marek Vasut, Rob Herring, linux-mtd,
	Matthias Brugger, linux-mediatek, Cyrille Pitchen, Brian Norris,
	David Woodhouse, linux-arm-kernel
In-Reply-To: <20170113175628.1793f433@bbrezillon>

Hello,

On Fri, 13 Jan 2017 17:56:28 +0100, Boris Brezillon wrote:

> because both compatible are referring to very specific IP version. It's
> not the same as
> 
> 	compatible = "mediatek,mt8173-nor", "mediatek,mt81xx-nor";

mt81xx-nor is a bogus compatible string, and DT binding maintainers
will not accept it. They don't want compatible strings with "wildcards".

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v3 3/3] reset: zx2967: add reset controller driver for ZTE's zx2967 family
From: Baoyou Xie @ 2017-01-17  3:22 UTC (permalink / raw)
  To: jun.nie, p.zabel, robh+dt, mark.rutland
  Cc: linux-arm-kernel, devicetree, linux-kernel, shawnguo, baoyou.xie,
	xie.baoyou, chen.chaokai, wang.qiang01
In-Reply-To: <1484623377-16208-1-git-send-email-baoyou.xie@linaro.org>

This patch adds reset controller driver for ZTE's zx2967 family.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 drivers/reset/Kconfig        |   6 +++
 drivers/reset/Makefile       |   1 +
 drivers/reset/reset-zx2967.c | 106 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)
 create mode 100644 drivers/reset/reset-zx2967.c

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 172dc96..f4cdfe9 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -86,6 +86,12 @@ config RESET_UNIPHIER
 	  Say Y if you want to control reset signals provided by System Control
 	  block, Media I/O block, Peripheral Block.
 
+config RESET_ZX2967
+	bool "ZTE ZX2967 Reset Driver"
+	depends on ARCH_ZX || COMPILE_TEST
+	help
+	  This enables the reset controller driver for ZTE's zx2967 family.
+
 config RESET_ZYNQ
 	bool "ZYNQ Reset Driver" if COMPILE_TEST
 	default ARCH_ZYNQ
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 13b346e..2cd3f6c 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_RESET_STM32) += reset-stm32.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
 obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
+obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
diff --git a/drivers/reset/reset-zx2967.c b/drivers/reset/reset-zx2967.c
new file mode 100644
index 0000000..5d82151
--- /dev/null
+++ b/drivers/reset/reset-zx2967.c
@@ -0,0 +1,106 @@
+/*
+ * ZTE's zx2967 family reset controller driver
+ *
+ * Copyright (C) 2017 ZTE Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct zx2967_reset {
+	void __iomem			*reg_base;
+	spinlock_t			lock;
+	struct reset_controller_dev	rcdev;
+};
+
+static int zx2967_reset_act(struct reset_controller_dev *rcdev,
+			    unsigned long id, bool assert)
+{
+	struct zx2967_reset *reset = NULL;
+	int bank = id / 32;
+	int offset = id % 32;
+	u32 reg;
+	unsigned long flags;
+
+	reset = container_of(rcdev, struct zx2967_reset, rcdev);
+
+	spin_lock_irqsave(&reset->lock, flags);
+
+	reg = readl_relaxed(reset->reg_base + (bank * 4));
+	if (assert)
+		reg &= ~BIT(offset);
+	else
+		reg |= BIT(offset);
+	writel_relaxed(reg, reset->reg_base + (bank * 4));
+
+	spin_unlock_irqrestore(&reset->lock, flags);
+
+	return 0;
+}
+
+static int zx2967_reset_assert(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	return zx2967_reset_act(rcdev, id, true);
+}
+
+static int zx2967_reset_deassert(struct reset_controller_dev *rcdev,
+				 unsigned long id)
+{
+	return zx2967_reset_act(rcdev, id, false);
+}
+
+static struct reset_control_ops zx2967_reset_ops = {
+	.assert		= zx2967_reset_assert,
+	.deassert	= zx2967_reset_deassert,
+};
+
+static int zx2967_reset_probe(struct platform_device *pdev)
+{
+	struct zx2967_reset *reset;
+	struct resource *res;
+
+	reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+	if (!reset)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reset->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reset->reg_base))
+		return PTR_ERR(reset->reg_base);
+
+	spin_lock_init(&reset->lock);
+
+	reset->rcdev.owner = THIS_MODULE;
+	reset->rcdev.nr_resets = resource_size(res) * 8;
+	reset->rcdev.ops = &zx2967_reset_ops;
+	reset->rcdev.of_node = pdev->dev.of_node;
+
+	return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+}
+
+static const struct of_device_id zx2967_reset_dt_ids[] = {
+	 { .compatible = "zte,zx296718-reset", },
+	 {},
+};
+MODULE_DEVICE_TABLE(of, zx2967_reset_dt_ids);
+
+static struct platform_driver zx2967_reset_driver = {
+	.probe	= zx2967_reset_probe,
+	.driver = {
+		.name		= "zx2967-reset",
+		.of_match_table	= zx2967_reset_dt_ids,
+	},
+};
+
+builtin_platform_driver(zx2967_reset_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE zx2967 Reset Controller Driver");
+MODULE_LICENSE("GPL");
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 2/3] MAINTAINERS: add zx2967 reset controller driver to ARM ZTE architecture
From: Baoyou Xie @ 2017-01-17  3:22 UTC (permalink / raw)
  To: jun.nie, p.zabel, robh+dt, mark.rutland
  Cc: devicetree, xie.baoyou, linux-kernel, chen.chaokai, wang.qiang01,
	baoyou.xie, shawnguo, linux-arm-kernel
In-Reply-To: <1484623377-16208-1-git-send-email-baoyou.xie@linaro.org>

Add the zx2967 reset controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e63063b..5fb9b62 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1987,9 +1987,11 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-zx/
 F:	drivers/clk/zte/
+F:	drivers/reset/reset-zx2967.c
 F:	drivers/soc/zte/
 F:	Documentation/devicetree/bindings/arm/zte.txt
 F:	Documentation/devicetree/bindings/clock/zx296702-clk.txt
+F:	Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
 F:	Documentation/devicetree/bindings/soc/zte/
 F:	include/dt-bindings/soc/zx*.h
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v3 1/3] dt: bindings: add documentation for zx2967 family reset controller
From: Baoyou Xie @ 2017-01-17  3:22 UTC (permalink / raw)
  To: jun.nie, p.zabel, robh+dt, mark.rutland
  Cc: devicetree, xie.baoyou, linux-kernel, chen.chaokai, wang.qiang01,
	baoyou.xie, shawnguo, linux-arm-kernel

This patch adds dt-binding documentation for zx2967 family
reset controller.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Reviewed-by: Shawn Guo <shawnguo@kernel.org>
---
 .../devicetree/bindings/reset/zte,zx2967-reset.txt   | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt

diff --git a/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
new file mode 100644
index 0000000..b015508
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
@@ -0,0 +1,20 @@
+ZTE zx2967 SoCs Reset Controller
+=======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: should be one of the following.
+	* zte,zx296718-reset
+- reg: physical base address of the controller and length of memory mapped
+	region.
+- #reset-cells: must be 1.
+
+example:
+
+	reset: reset-controller@1461060 {
+		compatible = "zte,zx296718-reset";
+		reg = <0x01461060 0x8>;
+		#reset-cells = <1>;
+	};
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/2] ARM64: dts: meson-gxm-rbox-pro: Enable Bluetooth
From: Andreas Färber @ 2017-01-17  3:06 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Mark Rutland, devicetree, Kevin Hilman, Will Deacon, linux-kernel,
	Rob Herring, Catalin Marinas, Carlo Caione, Andreas Färber,
	linux-arm-kernel
In-Reply-To: <20170117030611.23827-1-afaerber@suse.de>

Add an SDIO reset GPIO and enable the serial used by the AP6255
Bluetooth module. Based on work by Martin Blumenstingl.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
index 9f04fa4e5aec..6ea225f584bd 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
@@ -58,6 +58,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		serial1 = &uart_A;
 	};
 
 	chosen {
@@ -122,7 +123,8 @@
 
 	sdio_pwrseq: sdio-pwrseq {
 		compatible = "mmc-pwrseq-simple";
-		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
+				<&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
 		clocks = <&wifi32k>;
 		clock-names = "ext_clock";
 	};
@@ -238,3 +240,10 @@
 	pinctrl-0 = <&uart_ao_a_pins>;
 	pinctrl-names = "default";
 };
+
+&uart_A {
+	status = "okay";
+	pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+};
-- 
2.10.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 1/2] ARM64: dts: meson-gxm: Add R-Box Pro
From: Andreas Färber @ 2017-01-17  3:06 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Carlo Caione, Kevin Hilman, linux-arm-kernel, linux-kernel,
	Andreas Färber, Rob Herring, Mark Rutland, Catalin Marinas,
	Will Deacon, devicetree
In-Reply-To: <20170117030611.23827-1-afaerber@suse.de>

The R-Box Pro is a TV box derived from Amlogic q200 reference design.
It uses an AP6255 Wifi module. It features an LED tube that lights a
surrounding stripe and the top logo in blue or red or pink'ish - blue
is on by default, and red (i.e., pink) is configured as panic indicator.

This device is available in at least two models, with 2 GB vs. 3 GB RAM
as well as varying eMMC size. The intent is to handle this with a single
.dts that gets the actual RAM size from U-Boot.

The vendor prefix remains to be clarified, therefore no dedicated board
compatible string yet.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm64/boot/dts/amlogic/Makefile               |   1 +
 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts | 240 +++++++++++++++++++++
 2 files changed, 241 insertions(+)
 create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts

diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
index 0d7bfbf7d922..66bc809a5eae 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-nexbox-a95x.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-q200.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-q201.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb
 
 always		:= $(dtb-y)
 subdir-y	:= $(dts-dirs)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
new file mode 100644
index 000000000000..9f04fa4e5aec
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016-2017 Andreas Färber
+ *
+ * Based on nexbox-a1:
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxm.dtsi"
+
+/ {
+	compatible = "amlogic,s912", "amlogic,meson-gxm";
+	model = "R-Box Pro";
+
+	aliases {
+		serial0 = &uart_AO;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x0 0x0 0x80000000>; /* 2 GiB or 3 GiB */
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue {
+			label = "rbox-pro:blue:on";
+			gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		red {
+			label = "rbox-pro:red:standby";
+			gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+			retain-state-suspended;
+			panic-indicator;
+		};
+	};
+
+	vddio_boot: regulator-vddio-boot {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDIO_BOOT";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vddao_3v3: regulator-vddao-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDAO_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc_3v3: regulator-vcc-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VCC_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	emmc_pwrseq: emmc-pwrseq {
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
+	};
+
+	wifi32k: wifi32k {
+		compatible = "pwm-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+		clocks = <&wifi32k>;
+		clock-names = "ext_clock";
+	};
+};
+
+&ethmac {
+	status = "okay";
+
+	pinctrl-0 = <&eth_pins>;
+	pinctrl-names = "default";
+
+	/* Select external PHY by default */
+	phy-handle = <&external_phy>;
+
+	snps,reset-gpio = <&gpio GPIOZ_14 0>;
+	snps,reset-delays-us = <0 10000 1000000>;
+	snps,reset-active-low;
+
+	amlogic,tx-delay-ns = <2>;
+
+	/* External PHY is in RGMII */
+	phy-mode = "rgmii";
+};
+
+&external_mdio {
+	external_phy: ethernet-phy@0 {
+		compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22";
+		reg = <0>;
+		max-speed = <1000>;
+	};
+};
+
+&ir {
+	status = "okay";
+	pinctrl-0 = <&remote_input_ao_pins>;
+	pinctrl-names = "default";
+};
+
+&pwm_ef {
+	status = "okay";
+	pinctrl-0 = <&pwm_e_pins>;
+	pinctrl-names = "default";
+	clocks = <&clkc CLKID_FCLK_DIV4>;
+	clock-names = "clkin0";
+};
+
+/* Wireless SDIO Module */
+&sd_emmc_a {
+	status = "okay";
+	pinctrl-0 = <&sdio_pins>;
+	pinctrl-names = "default";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+
+	non-removable;
+	disable-wp;
+
+	mmc-pwrseq = <&sdio_pwrseq>;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+
+	brcmf: brcmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+	};
+};
+
+/* SD card */
+&sd_emmc_b {
+	status = "okay";
+	pinctrl-0 = <&sdcard_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+	disable-wp;
+
+	cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+	status = "okay";
+	pinctrl-0 = <&emmc_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <8>;
+	cap-sd-highspeed;
+	cap-mmc-highspeed;
+	max-frequency = <200000000>;
+	non-removable;
+	disable-wp;
+	mmc-ddr-1_8v;
+	mmc-hs200-1_8v;
+
+	mmc-pwrseq = <&emmc_pwrseq>;
+	vmmc-supply = <&vcc_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
+
+&uart_AO {
+	status = "okay";
+	pinctrl-0 = <&uart_ao_a_pins>;
+	pinctrl-names = "default";
+};
-- 
2.10.2

^ permalink raw reply related

* [PATCH 0/2] ARM64: meson-gxm: R-Box Pro enablement
From: Andreas Färber @ 2017-01-17  3:06 UTC (permalink / raw)
  To: linux-amlogic
  Cc: devicetree, Kevin Hilman, linux-kernel, Carlo Caione,
	Andreas Färber, linux-arm-kernel

Hello,

This mini-series adds initial support for the Amlogic S912 based
R-Box Pro TV boxes.

Patch 1 should apply today, patch 2 depends on Martin's Bluetooth series.

Wifi further depends on: https://patchwork.kernel.org/patch/9518447/
(and /etc/wifi/AP6255/nvram.txt as /lib/firmware/brcm/brcmfmac43455-sdio.txt)

Regards,
Andreas

Cc: devicetree@vger.kernel.org

Andreas Färber (2):
  ARM64: dts: meson-gxm: Add R-Box Pro
  ARM64: dts: meson-gxm-rbox-pro: Enable Bluetooth

 arch/arm64/boot/dts/amlogic/Makefile               |   1 +
 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts | 249 +++++++++++++++++++++
 2 files changed, 250 insertions(+)
 create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts

-- 
2.10.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 08/22] power: supply: add AC power supply driver for AXP20X and AXP22X PMICs
From: Sebastian Reichel @ 2017-01-17  3:00 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: mark.rutland, devicetree, lars, linux-pm, linux-iio, linux,
	linux-kernel, wens, robh+dt, linux-arm-kernel, pmeerw, knaack.h,
	maxime.ripard, bonbons, lee.jones, thomas.petazzoni, jic23,
	icenowy
In-Reply-To: <20170102163723.7939-9-quentin.schulz@free-electrons.com>


[-- Attachment #1.1: Type: text/plain, Size: 1695 bytes --]

Hi Quentin,

The driver looks mostly fine. I do have a two comments, though.

On Mon, Jan 02, 2017 at 05:37:08PM +0100, Quentin Schulz wrote:
> [...]
>
> +static int axp20x_ac_power_probe(struct platform_device *pdev)
> +{
> +	static const char * const axp20x_irq_names[] = { "ACIN_PLUGIN",
> +		"ACIN_REMOVAL", NULL };
>
> +	static const char * const *irq_names;
> +	const struct power_supply_desc *ac_power_desc;
> +	int i, irq, ret;
> +
> +	if (!of_device_is_available(pdev->dev.of_node))
> +		return -ENODEV;
> +
> +	if (!axp20x) {
> +		dev_err(&pdev->dev, "Parent drvdata not set\n");
> +		return -EINVAL;
> +	}

axp20x will no longer be needed after implementing below
comments.

> [...]
> +	irq_names = axp20x_irq_names;

Just rename axp20x_irq_names into irq_names, since its only used
here.

> [...]
>
> +	power->np = pdev->dev.of_node;

This can be dropped, it's not used at all.

> +	power->regmap = axp20x->regmap;

power->regmap = dev_get_regmap(pdev->dev.parent, NULL);

> [...]
> +	/* Request irqs after registering, as irqs may trigger immediately */
> +	for (i = 0; irq_names[i]; i++) {
> +		irq = platform_get_irq_byname(pdev, irq_names[i]);
> +		if (irq < 0) {
> +			dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
> +				 irq_names[i], irq);
> +			continue;
> +		}
> +		irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq);

The mapping should actually happen in the mfd driver, so that
the platform resource contains a valid irq.

> +		ret = devm_request_any_context_irq(&pdev->dev, irq,
> +						   axp20x_ac_power_irq, 0,
> +						   DRVNAME, power);
> +		if (ret < 0)
> +			dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n",
> +				 irq_names[i], ret);
> +	}

-- Sebastian

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v11 04/12] drm/mediatek: add shadow register support
From: CK Hu @ 2017-01-17  2:47 UTC (permalink / raw)
  To: YT Shen
  Cc: Mark Rutland, devicetree, srv_heupstream, emil.l.velikov,
	linux-kernel, dri-devel, Rob Herring, linux-mediatek,
	Matthias Brugger, yingjoe.chen, linux-arm-kernel
In-Reply-To: <1484117473-46644-5-git-send-email-yt.shen@mediatek.com>

Hi, YT:

On Wed, 2017-01-11 at 14:51 +0800, YT Shen wrote:
> We need to acquire mutex before using the resources,
> and need to release it after finished.
> So we don't need to write registers in the blanking period.
> 
> Signed-off-by: YT Shen <yt.shen@mediatek.com>

Acked-by: CK Hu <ck.hu@mediatek.com>

> ---
>  drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 75 ++++++++++++++++++++-------------
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.c  | 25 +++++++++++
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.h  |  2 +
>  drivers/gpu/drm/mediatek/mtk_drm_drv.h  |  1 +
>  4 files changed, 74 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> index 01a21dd..b9b82e5 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
> @@ -329,6 +329,42 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
>  	pm_runtime_put(drm->dev);
>  }
>  
> +static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
> +{
> +	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> +	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> +	struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
> +	unsigned int i;
> +
> +	/*
> +	 * TODO: instead of updating the registers here, we should prepare
> +	 * working registers in atomic_commit and let the hardware command
> +	 * queue update module registers on vblank.
> +	 */
> +	if (state->pending_config) {
> +		mtk_ddp_comp_config(ovl, state->pending_width,
> +				    state->pending_height,
> +				    state->pending_vrefresh, 0);
> +
> +		state->pending_config = false;
> +	}
> +
> +	if (mtk_crtc->pending_planes) {
> +		for (i = 0; i < OVL_LAYER_NR; i++) {
> +			struct drm_plane *plane = &mtk_crtc->planes[i];
> +			struct mtk_plane_state *plane_state;
> +
> +			plane_state = to_mtk_plane_state(plane->state);
> +
> +			if (plane_state->pending.config) {
> +				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> +				plane_state->pending.config = false;
> +			}
> +		}
> +		mtk_crtc->pending_planes = false;
> +	}
> +}
> +
>  static void mtk_drm_crtc_enable(struct drm_crtc *crtc)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> @@ -405,6 +441,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  				      struct drm_crtc_state *old_crtc_state)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> +	struct mtk_drm_private *priv = crtc->dev->dev_private;
>  	unsigned int pending_planes = 0;
>  	int i;
>  
> @@ -426,6 +463,12 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  	if (crtc->state->color_mgmt_changed)
>  		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
>  			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
> +
> +	if (priv->data->shadow_register) {
> +		mtk_disp_mutex_acquire(mtk_crtc->mutex);
> +		mtk_crtc_ddp_config(crtc);
> +		mtk_disp_mutex_release(mtk_crtc->mutex);
> +	}
>  }
>  
>  static const struct drm_crtc_funcs mtk_crtc_funcs = {
> @@ -471,36 +514,10 @@ static int mtk_drm_crtc_init(struct drm_device *drm,
>  void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
>  {
>  	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
> -	struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
> -	unsigned int i;
> +	struct mtk_drm_private *priv = crtc->dev->dev_private;
>  
> -	/*
> -	 * TODO: instead of updating the registers here, we should prepare
> -	 * working registers in atomic_commit and let the hardware command
> -	 * queue update module registers on vblank.
> -	 */
> -	if (state->pending_config) {
> -		mtk_ddp_comp_config(ovl, state->pending_width,
> -				    state->pending_height,
> -				    state->pending_vrefresh, 0);
> -
> -		state->pending_config = false;
> -	}
> -
> -	if (mtk_crtc->pending_planes) {
> -		for (i = 0; i < OVL_LAYER_NR; i++) {
> -			struct drm_plane *plane = &mtk_crtc->planes[i];
> -			struct mtk_plane_state *plane_state;
> -
> -			plane_state = to_mtk_plane_state(plane->state);
> -
> -			if (plane_state->pending.config) {
> -				mtk_ddp_comp_layer_config(ovl, i, plane_state);
> -				plane_state->pending.config = false;
> -			}
> -		}
> -		mtk_crtc->pending_planes = false;
> -	}
> +	if (!priv->data->shadow_register)
> +		mtk_crtc_ddp_config(crtc);
>  
>  	mtk_drm_finish_page_flip(mtk_crtc);
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> index 8030769..b77d456 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> @@ -12,6 +12,7 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/iopoll.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/platform_device.h>
> @@ -32,10 +33,13 @@
>  #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
>  
>  #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
> +#define DISP_REG_MUTEX(n)	(0x24 + 0x20 * (n))
>  #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
>  #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
>  #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
>  
> +#define INT_MUTEX				BIT(1)
> +
>  #define MT8173_MUTEX_MOD_DISP_OVL0		BIT(11)
>  #define MT8173_MUTEX_MOD_DISP_OVL1		BIT(12)
>  #define MT8173_MUTEX_MOD_DISP_RDMA0		BIT(13)
> @@ -300,6 +304,27 @@ void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
>  	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
>  }
>  
> +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
> +{
> +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> +					   mutex[mutex->id]);
> +	u32 tmp;
> +
> +	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
> +	writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
> +	if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id),
> +				      tmp, tmp & INT_MUTEX, 1, 10000))
> +		pr_err("could not acquire mutex %d\n", mutex->id);
> +}
> +
> +void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
> +{
> +	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
> +					   mutex[mutex->id]);
> +
> +	writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
> +}
> +
>  static int mtk_ddp_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> index 92c1175..f9a7991 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.h
> @@ -37,5 +37,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
>  				enum mtk_ddp_comp_id id);
>  void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
>  void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
> +void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
> +void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
>  
>  #endif /* MTK_DRM_DDP_H */
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> index fa0b106..94f8b66 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> @@ -33,6 +33,7 @@ struct mtk_mmsys_driver_data {
>  	unsigned int main_len;
>  	const enum mtk_ddp_comp_id *ext_path;
>  	unsigned int ext_len;
> +	bool shadow_register;
>  };
>  
>  struct mtk_drm_private {


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v11 03/12] drm/mediatek: add *driver_data for different hardware settings
From: CK Hu @ 2017-01-17  2:37 UTC (permalink / raw)
  To: YT Shen
  Cc: Mark Rutland, devicetree, srv_heupstream, emil.l.velikov,
	linux-kernel, dri-devel, Rob Herring, linux-mediatek,
	Matthias Brugger, yingjoe.chen, linux-arm-kernel
In-Reply-To: <1484117473-46644-4-git-send-email-yt.shen@mediatek.com>

Hi, YT:

On Wed, 2017-01-11 at 14:51 +0800, YT Shen wrote:
> There are some hardware settings changed, between MT8173 & MT2701:
> DISP_OVL address offset changed, color format definition changed.
> DISP_RDMA fifo size changed.
> DISP_COLOR offset changed.
> MIPI_TX pll setting changed.
> And add prefix for mtk_ddp_main & mtk_ddp_ext & mutex_mod.
> 
> Signed-off-by: YT Shen <yt.shen@mediatek.com>

Acked-by: CK Hu <ck.hu@mediatek.com>

> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c     | 41 ++++++++++++-----
>  drivers/gpu/drm/mediatek/mtk_disp_rdma.c    | 18 +++++++-
>  drivers/gpu/drm/mediatek/mtk_drm_ddp.c      | 71 +++++++++++++++--------------
>  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 57 +++++++++++++++++++----
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c      | 25 +++++++---
>  drivers/gpu/drm/mediatek/mtk_drm_drv.h      |  8 ++++
>  drivers/gpu/drm/mediatek/mtk_mipi_tx.c      | 24 +++++++++-
>  7 files changed, 181 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index ce2759f..4552178 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -35,18 +35,27 @@
>  #define DISP_REG_OVL_PITCH(n)			(0x0044 + 0x20 * (n))
>  #define DISP_REG_OVL_RDMA_CTRL(n)		(0x00c0 + 0x20 * (n))
>  #define DISP_REG_OVL_RDMA_GMC(n)		(0x00c8 + 0x20 * (n))
> -#define DISP_REG_OVL_ADDR(n)			(0x0f40 + 0x20 * (n))
> +#define DISP_REG_OVL_ADDR_MT8173		0x0f40
> +#define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
>  
>  #define	OVL_RDMA_MEM_GMC	0x40402020
>  
>  #define OVL_CON_BYTE_SWAP	BIT(24)
> -#define OVL_CON_CLRFMT_RGB565	(0 << 12)
> -#define OVL_CON_CLRFMT_RGB888	(1 << 12)
> +#define OVL_CON_CLRFMT_RGB	(1 << 12)
>  #define OVL_CON_CLRFMT_RGBA8888	(2 << 12)
>  #define OVL_CON_CLRFMT_ARGB8888	(3 << 12)
> +#define OVL_CON_CLRFMT_RGB565(ovl)	((ovl)->data->fmt_rgb565_is_0 ? \
> +					0 : OVL_CON_CLRFMT_RGB)
> +#define OVL_CON_CLRFMT_RGB888(ovl)	((ovl)->data->fmt_rgb565_is_0 ? \
> +					OVL_CON_CLRFMT_RGB : 0)
>  #define	OVL_CON_AEN		BIT(8)
>  #define	OVL_CON_ALPHA		0xff
>  
> +struct mtk_disp_ovl_data {
> +	unsigned int addr;
> +	bool fmt_rgb565_is_0;
> +};
> +
>  /**
>   * struct mtk_disp_ovl - DISP_OVL driver structure
>   * @ddp_comp - structure containing type enum and hardware resources
> @@ -55,6 +64,7 @@
>  struct mtk_disp_ovl {
>  	struct mtk_ddp_comp		ddp_comp;
>  	struct drm_crtc			*crtc;
> +	const struct mtk_disp_ovl_data	*data;
>  };
>  
>  static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
> @@ -141,18 +151,18 @@ static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx)
>  	writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
>  }
>  
> -static unsigned int ovl_fmt_convert(unsigned int fmt)
> +static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
>  {
>  	switch (fmt) {
>  	default:
>  	case DRM_FORMAT_RGB565:
> -		return OVL_CON_CLRFMT_RGB565;
> +		return OVL_CON_CLRFMT_RGB565(ovl);
>  	case DRM_FORMAT_BGR565:
> -		return OVL_CON_CLRFMT_RGB565 | OVL_CON_BYTE_SWAP;
> +		return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
>  	case DRM_FORMAT_RGB888:
> -		return OVL_CON_CLRFMT_RGB888;
> +		return OVL_CON_CLRFMT_RGB888(ovl);
>  	case DRM_FORMAT_BGR888:
> -		return OVL_CON_CLRFMT_RGB888 | OVL_CON_BYTE_SWAP;
> +		return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
>  	case DRM_FORMAT_RGBX8888:
>  	case DRM_FORMAT_RGBA8888:
>  		return OVL_CON_CLRFMT_ARGB8888;
> @@ -171,6 +181,7 @@ static unsigned int ovl_fmt_convert(unsigned int fmt)
>  static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
>  				 struct mtk_plane_state *state)
>  {
> +	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
>  	struct mtk_plane_pending_state *pending = &state->pending;
>  	unsigned int addr = pending->addr;
>  	unsigned int pitch = pending->pitch & 0xffff;
> @@ -182,7 +193,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
>  	if (!pending->enable)
>  		mtk_ovl_layer_off(comp, idx);
>  
> -	con = ovl_fmt_convert(fmt);
> +	con = ovl_fmt_convert(ovl, fmt);
>  	if (idx != 0)
>  		con |= OVL_CON_AEN | OVL_CON_ALPHA;
>  
> @@ -190,7 +201,7 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
>  	writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
>  	writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx));
>  	writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx));
> -	writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(idx));
> +	writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(ovl, idx));
>  
>  	if (pending->enable)
>  		mtk_ovl_layer_on(comp, idx);
> @@ -267,6 +278,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	priv->data = of_device_get_match_data(dev);
> +
>  	platform_set_drvdata(pdev, priv);
>  
>  	ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
> @@ -290,8 +303,14 @@ static int mtk_disp_ovl_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
> +	.addr = DISP_REG_OVL_ADDR_MT8173,
> +	.fmt_rgb565_is_0 = true,
> +};
> +
>  static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
> -	{ .compatible = "mediatek,mt8173-disp-ovl", },
> +	{ .compatible = "mediatek,mt8173-disp-ovl",
> +	  .data = &mt8173_ovl_driver_data},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> index 21eff6f..e5e5318 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> @@ -38,6 +38,11 @@
>  #define RDMA_FIFO_UNDERFLOW_EN				BIT(31)
>  #define RDMA_FIFO_PSEUDO_SIZE(bytes)			(((bytes) / 16) << 16)
>  #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes)		((bytes) / 16)
> +#define RDMA_FIFO_SIZE(rdma)			((rdma)->data->fifo_size)
> +
> +struct mtk_disp_rdma_data {
> +	unsigned int fifo_size;
> +};
>  
>  /**
>   * struct mtk_disp_rdma - DISP_RDMA driver structure
> @@ -47,6 +52,7 @@
>  struct mtk_disp_rdma {
>  	struct mtk_ddp_comp		ddp_comp;
>  	struct drm_crtc			*crtc;
> +	const struct mtk_disp_rdma_data	*data;
>  };
>  
>  static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp)
> @@ -114,6 +120,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
>  {
>  	unsigned int threshold;
>  	unsigned int reg;
> +	struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
>  
>  	rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width);
>  	rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height);
> @@ -126,7 +133,7 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
>  	 */
>  	threshold = width * height * vrefresh * 4 * 7 / 1000000;
>  	reg = RDMA_FIFO_UNDERFLOW_EN |
> -	      RDMA_FIFO_PSEUDO_SIZE(SZ_8K) |
> +	      RDMA_FIFO_PSEUDO_SIZE(RDMA_FIFO_SIZE(rdma)) |
>  	      RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
>  	writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON);
>  }
> @@ -211,6 +218,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	priv->data = of_device_get_match_data(dev);
> +
>  	platform_set_drvdata(pdev, priv);
>  
>  	ret = component_add(dev, &mtk_disp_rdma_component_ops);
> @@ -227,8 +236,13 @@ static int mtk_disp_rdma_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
> +	.fifo_size = SZ_8K,
> +};
> +
>  static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
> -	{ .compatible = "mediatek,mt8173-disp-rdma", },
> +	{ .compatible = "mediatek,mt8173-disp-rdma",
> +	  .data = &mt8173_rdma_driver_data},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> index 17ba935..8030769 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
> @@ -36,21 +36,21 @@
>  #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
>  #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
>  
> -#define MUTEX_MOD_DISP_OVL0		BIT(11)
> -#define MUTEX_MOD_DISP_OVL1		BIT(12)
> -#define MUTEX_MOD_DISP_RDMA0		BIT(13)
> -#define MUTEX_MOD_DISP_RDMA1		BIT(14)
> -#define MUTEX_MOD_DISP_RDMA2		BIT(15)
> -#define MUTEX_MOD_DISP_WDMA0		BIT(16)
> -#define MUTEX_MOD_DISP_WDMA1		BIT(17)
> -#define MUTEX_MOD_DISP_COLOR0		BIT(18)
> -#define MUTEX_MOD_DISP_COLOR1		BIT(19)
> -#define MUTEX_MOD_DISP_AAL		BIT(20)
> -#define MUTEX_MOD_DISP_GAMMA		BIT(21)
> -#define MUTEX_MOD_DISP_UFOE		BIT(22)
> -#define MUTEX_MOD_DISP_PWM0		BIT(23)
> -#define MUTEX_MOD_DISP_PWM1		BIT(24)
> -#define MUTEX_MOD_DISP_OD		BIT(25)
> +#define MT8173_MUTEX_MOD_DISP_OVL0		BIT(11)
> +#define MT8173_MUTEX_MOD_DISP_OVL1		BIT(12)
> +#define MT8173_MUTEX_MOD_DISP_RDMA0		BIT(13)
> +#define MT8173_MUTEX_MOD_DISP_RDMA1		BIT(14)
> +#define MT8173_MUTEX_MOD_DISP_RDMA2		BIT(15)
> +#define MT8173_MUTEX_MOD_DISP_WDMA0		BIT(16)
> +#define MT8173_MUTEX_MOD_DISP_WDMA1		BIT(17)
> +#define MT8173_MUTEX_MOD_DISP_COLOR0		BIT(18)
> +#define MT8173_MUTEX_MOD_DISP_COLOR1		BIT(19)
> +#define MT8173_MUTEX_MOD_DISP_AAL		BIT(20)
> +#define MT8173_MUTEX_MOD_DISP_GAMMA		BIT(21)
> +#define MT8173_MUTEX_MOD_DISP_UFOE		BIT(22)
> +#define MT8173_MUTEX_MOD_DISP_PWM0		BIT(23)
> +#define MT8173_MUTEX_MOD_DISP_PWM1		BIT(24)
> +#define MT8173_MUTEX_MOD_DISP_OD		BIT(25)
>  
>  #define MUTEX_SOF_SINGLE_MODE		0
>  #define MUTEX_SOF_DSI0			1
> @@ -77,24 +77,25 @@ struct mtk_ddp {
>  	struct clk			*clk;
>  	void __iomem			*regs;
>  	struct mtk_disp_mutex		mutex[10];
> +	const unsigned int		*mutex_mod;
>  };
>  
> -static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
> -	[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL,
> -	[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0,
> -	[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1,
> -	[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA,
> -	[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD,
> -	[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0,
> -	[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1,
> -	[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0,
> -	[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1,
> -	[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0,
> -	[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1,
> -	[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2,
> -	[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE,
> -	[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0,
> -	[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1,
> +static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
> +	[DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
> +	[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
> +	[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
> +	[DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
> +	[DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
> +	[DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
> +	[DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
> +	[DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
> +	[DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
> +	[DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
> +	[DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
> +	[DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
> +	[DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
> +	[DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
> +	[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
>  };
>  
>  static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
> @@ -247,7 +248,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
>  		break;
>  	default:
>  		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
> -		reg |= mutex_mod[id];
> +		reg |= ddp->mutex_mod[id];
>  		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
>  		return;
>  	}
> @@ -273,7 +274,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
>  		break;
>  	default:
>  		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
> -		reg &= ~mutex_mod[id];
> +		reg &= ~(ddp->mutex_mod[id]);
>  		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
>  		break;
>  	}
> @@ -326,6 +327,8 @@ static int mtk_ddp_probe(struct platform_device *pdev)
>  		return PTR_ERR(ddp->regs);
>  	}
>  
> +	ddp->mutex_mod = of_device_get_match_data(dev);
> +
>  	platform_set_drvdata(pdev, ddp);
>  
>  	return 0;
> @@ -337,7 +340,7 @@ static int mtk_ddp_remove(struct platform_device *pdev)
>  }
>  
>  static const struct of_device_id ddp_driver_dt_match[] = {
> -	{ .compatible = "mediatek,mt8173-disp-mutex" },
> +	{ .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> index 48cc01f..3ff788c 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
> @@ -39,9 +39,10 @@
>  #define DISP_REG_UFO_START			0x0000
>  
>  #define DISP_COLOR_CFG_MAIN			0x0400
> -#define DISP_COLOR_START			0x0c00
> -#define DISP_COLOR_WIDTH			0x0c50
> -#define DISP_COLOR_HEIGHT			0x0c54
> +#define DISP_COLOR_START_MT8173			0x0c00
> +#define DISP_COLOR_START(comp)			((comp)->data->color_offset)
> +#define DISP_COLOR_WIDTH(comp)			(DISP_COLOR_START(comp) + 0x50)
> +#define DISP_COLOR_HEIGHT(comp)			(DISP_COLOR_START(comp) + 0x54)
>  
>  #define DISP_AAL_EN				0x0000
>  #define DISP_AAL_SIZE				0x0030
> @@ -80,6 +81,20 @@
>  #define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
>  #define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
>  
> +struct mtk_disp_color_data {
> +	unsigned int color_offset;
> +};
> +
> +struct mtk_disp_color {
> +	struct mtk_ddp_comp			ddp_comp;
> +	const struct mtk_disp_color_data	*data;
> +};
> +
> +static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp)
> +{
> +	return container_of(comp, struct mtk_disp_color, ddp_comp);
> +}
> +
>  void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
>  		    unsigned int CFG)
>  {
> @@ -107,15 +122,19 @@ static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
>  			     unsigned int h, unsigned int vrefresh,
>  			     unsigned int bpc)
>  {
> -	writel(w, comp->regs + DISP_COLOR_WIDTH);
> -	writel(h, comp->regs + DISP_COLOR_HEIGHT);
> +	struct mtk_disp_color *color = comp_to_color(comp);
> +
> +	writel(w, comp->regs + DISP_COLOR_WIDTH(color));
> +	writel(h, comp->regs + DISP_COLOR_HEIGHT(color));
>  }
>  
>  static void mtk_color_start(struct mtk_ddp_comp *comp)
>  {
> +	struct mtk_disp_color *color = comp_to_color(comp);
> +
>  	writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
>  	       comp->regs + DISP_COLOR_CFG_MAIN);
> -	writel(0x1, comp->regs + DISP_COLOR_START);
> +	writel(0x1, comp->regs + DISP_COLOR_START(color));
>  }
>  
>  static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
> @@ -264,6 +283,16 @@ struct mtk_ddp_comp_match {
>  	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
>  };
>  
> +static const struct mtk_disp_color_data mt8173_color_driver_data = {
> +	.color_offset = DISP_COLOR_START_MT8173,
> +};
> +
> +static const struct of_device_id mtk_disp_color_driver_dt_match[] = {
> +	{ .compatible = "mediatek,mt8173-disp-color",
> +	  .data = &mt8173_color_driver_data},
> +	{},
> +};
> +
>  int mtk_ddp_comp_get_id(struct device_node *node,
>  			enum mtk_ddp_comp_type comp_type)
>  {
> @@ -286,10 +315,24 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
>  	enum mtk_ddp_comp_type type;
>  	struct device_node *larb_node;
>  	struct platform_device *larb_pdev;
> +	const struct of_device_id *match;
> +	struct mtk_disp_color *color;
>  
>  	if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
>  		return -EINVAL;
>  
> +	type = mtk_ddp_matches[comp_id].type;
> +	if (type == MTK_DISP_COLOR) {
> +		devm_kfree(dev, comp);
> +		color = devm_kzalloc(dev, sizeof(*color), GFP_KERNEL);
> +		if (!color)
> +			return -ENOMEM;
> +
> +		match = of_match_node(mtk_disp_color_driver_dt_match, node);
> +		color->data = match->data;
> +		comp = &color->ddp_comp;
> +	}
> +
>  	comp->id = comp_id;
>  	comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs;
>  
> @@ -308,8 +351,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
>  	if (IS_ERR(comp->clk))
>  		comp->clk = NULL;
>  
> -	type = mtk_ddp_matches[comp_id].type;
> -
>  	/* Only DMA capable components need the LARB property */
>  	comp->larb_dev = NULL;
>  	if (type != MTK_DISP_OVL &&
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> index 4b7fe7e..074fe31 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> @@ -128,7 +128,7 @@ static int mtk_atomic_commit(struct drm_device *drm,
>  	.atomic_commit = mtk_atomic_commit,
>  };
>  
> -static const enum mtk_ddp_comp_id mtk_ddp_main[] = {
> +static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
>  	DDP_COMPONENT_OVL0,
>  	DDP_COMPONENT_COLOR0,
>  	DDP_COMPONENT_AAL,
> @@ -139,7 +139,7 @@ static int mtk_atomic_commit(struct drm_device *drm,
>  	DDP_COMPONENT_PWM0,
>  };
>  
> -static const enum mtk_ddp_comp_id mtk_ddp_ext[] = {
> +static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
>  	DDP_COMPONENT_OVL1,
>  	DDP_COMPONENT_COLOR1,
>  	DDP_COMPONENT_GAMMA,
> @@ -147,6 +147,13 @@ static int mtk_atomic_commit(struct drm_device *drm,
>  	DDP_COMPONENT_DPI0,
>  };
>  
> +static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
> +	.main_path = mt8173_mtk_ddp_main,
> +	.main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
> +	.ext_path = mt8173_mtk_ddp_ext,
> +	.ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
> +};
> +
>  static int mtk_drm_kms_init(struct drm_device *drm)
>  {
>  	struct mtk_drm_private *private = drm->dev_private;
> @@ -189,17 +196,19 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  	 * and each statically assigned to a crtc:
>  	 * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
>  	 */
> -	ret = mtk_drm_crtc_create(drm, mtk_ddp_main, ARRAY_SIZE(mtk_ddp_main));
> +	ret = mtk_drm_crtc_create(drm, private->data->main_path,
> +				  private->data->main_len);
>  	if (ret < 0)
>  		goto err_component_unbind;
>  	/* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */
> -	ret = mtk_drm_crtc_create(drm, mtk_ddp_ext, ARRAY_SIZE(mtk_ddp_ext));
> +	ret = mtk_drm_crtc_create(drm, private->data->ext_path,
> +				  private->data->ext_len);
>  	if (ret < 0)
>  		goto err_component_unbind;
>  
>  	/* Use OVL device for all DMA memory allocations */
> -	np = private->comp_node[mtk_ddp_main[0]] ?:
> -	     private->comp_node[mtk_ddp_ext[0]];
> +	np = private->comp_node[private->data->main_path[0]] ?:
> +	     private->comp_node[private->data->ext_path[0]];
>  	pdev = of_find_device_by_node(np);
>  	if (!pdev) {
>  		ret = -ENODEV;
> @@ -362,6 +371,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  
>  	mutex_init(&private->commit.lock);
>  	INIT_WORK(&private->commit.work, mtk_atomic_work);
> +	private->data = of_device_get_match_data(dev);
>  
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	private->config_regs = devm_ioremap_resource(dev, mem);
> @@ -513,7 +523,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
>  			 mtk_drm_sys_resume);
>  
>  static const struct of_device_id mtk_drm_of_ids[] = {
> -	{ .compatible = "mediatek,mt8173-mmsys", },
> +	{ .compatible = "mediatek,mt8173-mmsys",
> +	  .data = &mt8173_mmsys_driver_data},
>  	{ }
>  };
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> index aa93894..fa0b106 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> @@ -28,6 +28,13 @@
>  struct drm_property;
>  struct regmap;
>  
> +struct mtk_mmsys_driver_data {
> +	const enum mtk_ddp_comp_id *main_path;
> +	unsigned int main_len;
> +	const enum mtk_ddp_comp_id *ext_path;
> +	unsigned int ext_len;
> +};
> +
>  struct mtk_drm_private {
>  	struct drm_device *drm;
>  	struct device *dma_dev;
> @@ -40,6 +47,7 @@ struct mtk_drm_private {
>  	void __iomem *config_regs;
>  	struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
>  	struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX];
> +	const struct mtk_mmsys_driver_data *data;
>  
>  	struct {
>  		struct drm_atomic_state *state;
> diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> index 1c366f8..c4a0165 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c
> @@ -16,6 +16,7 @@
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/phy/phy.h>
>  
> @@ -87,6 +88,9 @@
>  
>  #define MIPITX_DSI_PLL_CON2	0x58
>  
> +#define MIPITX_DSI_PLL_TOP	0x64
> +#define RG_DSI_MPPLL_PRESERVE		(0xff << 8)
> +
>  #define MIPITX_DSI_PLL_PWR	0x68
>  #define RG_DSI_MPPLL_SDM_PWR_ON		BIT(0)
>  #define RG_DSI_MPPLL_SDM_ISO_EN		BIT(1)
> @@ -123,10 +127,15 @@
>  #define SW_LNT2_HSTX_PRE_OE		BIT(24)
>  #define SW_LNT2_HSTX_OE			BIT(25)
>  
> +struct mtk_mipitx_data {
> +	const u32 mppll_preserve;
> +};
> +
>  struct mtk_mipi_tx {
>  	struct device *dev;
>  	void __iomem *regs;
>  	unsigned int data_rate;
> +	const struct mtk_mipitx_data *driver_data;
>  	struct clk_hw pll_hw;
>  	struct clk *pll;
>  };
> @@ -243,6 +252,10 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw)
>  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1,
>  			       RG_DSI_MPPLL_SDM_SSC_EN);
>  
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> +				RG_DSI_MPPLL_PRESERVE,
> +				mipi_tx->driver_data->mppll_preserve);
> +
>  	return 0;
>  }
>  
> @@ -255,6 +268,9 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
>  	mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0,
>  			       RG_DSI_MPPLL_PLL_EN);
>  
> +	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP,
> +				RG_DSI_MPPLL_PRESERVE, 0);
> +
>  	mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR,
>  				RG_DSI_MPPLL_SDM_ISO_EN |
>  				RG_DSI_MPPLL_SDM_PWR_ON,
> @@ -391,6 +407,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
>  	if (!mipi_tx)
>  		return -ENOMEM;
>  
> +	mipi_tx->driver_data = of_device_get_match_data(dev);
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	mipi_tx->regs = devm_ioremap_resource(dev, mem);
>  	if (IS_ERR(mipi_tx->regs)) {
> @@ -448,8 +465,13 @@ static int mtk_mipi_tx_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct mtk_mipitx_data mt8173_mipitx_data = {
> +	.mppll_preserve = (0 << 8)
> +};
> +
>  static const struct of_device_id mtk_mipi_tx_match[] = {
> -	{ .compatible = "mediatek,mt8173-mipi-tx", },
> +	{ .compatible = "mediatek,mt8173-mipi-tx",
> +	  .data = &mt8173_mipitx_data },
>  	{},
>  };
>  


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: add Garmin vendor prefix
From: Marek Vasut @ 2017-01-17  1:52 UTC (permalink / raw)
  To: Matt Ranostay
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jonathan Cameron, Rob Herring
In-Reply-To: <CAJ_EiSQ+kfNnoDsed67v_1CLui7Fp2qMsx67bYMvQ0Y98jO+Aw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On 01/17/2017 02:50 AM, Matt Ranostay wrote:
> On Mon, Jan 16, 2017 at 5:07 PM, Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On 12/29/2016 06:13 AM, Matt Ranostay wrote:
>>
>> Some commit message / description of the company would be useful.
>>
>>> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>> Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
>>> ---
>>> Changes from v1:
>>> * switch to stock ticker for Garmin Limited
>>>
>>>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>>>  1 file changed, 1 insertion(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> index 16d3b5e7f5d1..5749bfc5fc5b 100644
>>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> @@ -107,6 +107,7 @@ firefly   Firefly
>>>  focaltech    FocalTech Systems Co.,Ltd
>>>  friendlyarm  Guangzhou FriendlyARM Computer Tech Co., Ltd
>>>  fsl  Freescale Semiconductor
>>> +grmn Garmin Limited
>>
>> Why grmn ? Why not 'garmin' ? Also, the rest uses Ltd. , so make it
>> consistent ?
>>
> 
> As already stated GRMN is the US stock ticker...  and is the "correct way" :)

So we should use the US stock tickers for DT vendor prefixes now ?

>>>  ge   General Electric Company
>>>  geekbuying   GeekBuying
>>>  gef  GE Fanuc Intelligent Platforms Embedded Systems, Inc.
>>>
>>
>>
>> --
>> Best regards,
>> Marek Vasut


-- 
Best regards,
Marek Vasut

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: add Garmin vendor prefix
From: Matt Ranostay @ 2017-01-17  1:50 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jonathan Cameron, Rob Herring
In-Reply-To: <06f2cde2-ac7e-d0e5-5e35-a4946d0398f8-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Mon, Jan 16, 2017 at 5:07 PM, Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 12/29/2016 06:13 AM, Matt Ranostay wrote:
>
> Some commit message / description of the company would be useful.
>
>> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
>> ---
>> Changes from v1:
>> * switch to stock ticker for Garmin Limited
>>
>>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index 16d3b5e7f5d1..5749bfc5fc5b 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -107,6 +107,7 @@ firefly   Firefly
>>  focaltech    FocalTech Systems Co.,Ltd
>>  friendlyarm  Guangzhou FriendlyARM Computer Tech Co., Ltd
>>  fsl  Freescale Semiconductor
>> +grmn Garmin Limited
>
> Why grmn ? Why not 'garmin' ? Also, the rest uses Ltd. , so make it
> consistent ?
>

As already stated GRMN is the US stock ticker...  and is the "correct way" :)

>>  ge   General Electric Company
>>  geekbuying   GeekBuying
>>  gef  GE Fanuc Intelligent Platforms Embedded Systems, Inc.
>>
>
>
> --
> Best regards,
> Marek Vasut

^ permalink raw reply

* Re: [PATCH v4 2/2] mtd: spi-nor: add rockchip serial flash controller driver
From: Shawn Lin @ 2017-01-17  1:34 UTC (permalink / raw)
  To: Cyrille Pitchen, Cyrille Pitchen
  Cc: devicetree, Heiko Stuebner, Marek Vasut, shawn.lin,
	linux-rockchip, Rob Herring, linux-mtd, Brian Norris,
	David Woodhouse
In-Reply-To: <c4a50d88-4a31-ec67-c180-808bfc81f254@atmel.com>

Hi Cyrille,

On 2017/1/16 22:03, Cyrille Pitchen wrote:
> Le 16/01/2017 à 12:10, Cyrille Pitchen a écrit :
>> Hi Shawn,
>>
>> Le 15/12/2016 à 10:27, Shawn Lin a écrit :
>>> Add rockchip serial flash controller driver
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>>>
>>> ---
>>>
>>> Changes in v4:
>>> - simplify the code of get_if_type
>>> - use dma_dir to simplify the code
>>> - simplify the rockchip_sfc_do_rd_wr
>>> - some minor improvements
>>> - add reset controller when doing resume
>>>
>>> Changes in v3:
>>> - use io{read32,write32}_rep to simplify the corner cases
>>> - remove more unnecessary bit definitions
>>> - some minor comment fixes and improvement
>>> - fix wrong unregister function
>>> - unify more code
>>> - use nor to avoid constantly replicating the whole
>>>   sfc->flash[sfc->num_chip].nor
>>> - add email for MODULE_AUTHOR
>>> - remove #if 1 --- #endif
>>> - extract DMA code to imporve the code structure
>>> - reset all when failing to do dma
>>> - pass sfc to get_if_type
>>> - rename sfc-no-dma to sfc-no-DMA
>>>
>>> Changes in v2:
>>> - fix typos
>>> - add some comment for buffer and others operations
>>> - rename SFC_MAX_CHIP_NUM to MAX_CHIPSELECT_NUM
>>> - use u8 for cs
>>> - return -EINVAL for default case of get_if_type
>>> - use readl_poll_*() to check timeout cases
>>> - simplify and clarify some condition checks
>>> - rework the bitshifts to simplify the code
>>> - define SFC_CMD_DUMMY(x)
>>> - fix ummap for dma read path and finish all the
>>>   cache maintenance.
>>> - rename to rockchip_sfc_chip_priv and embed struct spi_nor
>>>   in it.
>>> - add MODULE_AUTHOR
>>> - add runtime PM and general PM support.
>>> - Thanks for Marek's comments. Link:
>>>   http://lists.infradead.org/pipermail/linux-mtd/2016-November/070321.html
>>>
>>>  MAINTAINERS                        |   8 +
>>>  drivers/mtd/spi-nor/Kconfig        |   7 +
>>>  drivers/mtd/spi-nor/Makefile       |   1 +
>>>  drivers/mtd/spi-nor/rockchip-sfc.c | 872 +++++++++++++++++++++++++++++++++++++
>>>  4 files changed, 888 insertions(+)
>>>  create mode 100644 drivers/mtd/spi-nor/rockchip-sfc.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 1cd38a7..eb7e06d 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -10266,6 +10266,14 @@ L:	linux-serial@vger.kernel.org
>>>  S:	Odd Fixes
>>>  F:	drivers/tty/serial/rp2.*
>>>
>>> +ROCKCHIP SERIAL FLASH CONTROLLER DRIVER
>>> +M:	Shawn Lin <shawn.lin@rock-chips.com>
>>> +L:	linux-mtd@lists.infradead.org
>>> +L:	linux-rockchip@lists.infradead.org
>>> +S:	Maintained
>>> +F:	Documentation/devicetree/bindings/mtd/rockchip-sfc.txt
>>> +F:	drivers/mtd/spi-nor/rockchip-sfc.c
>>> +
>>>  ROSE NETWORK LAYER
>>>  M:	Ralf Baechle <ralf@linux-mips.org>
>>>  L:	linux-hams@vger.kernel.org
>>> diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
>>> index 4a682ee..bf783a8 100644
>>> --- a/drivers/mtd/spi-nor/Kconfig
>>> +++ b/drivers/mtd/spi-nor/Kconfig
>>> @@ -76,4 +76,11 @@ config SPI_NXP_SPIFI
>>>  	  Flash. Enable this option if you have a device with a SPIFI
>>>  	  controller and want to access the Flash as a mtd device.
>>>
>>> +config SPI_ROCKCHIP_SFC
>>> +	tristate "Rockchip Serial Flash Controller(SFC)"
>>> +	depends on ARCH_ROCKCHIP || COMPILE_TEST
>>> +	depends on HAS_IOMEM && HAS_DMA
>>> +	help
>>> +	  This enables support for rockchip serial flash controller.
>>> +
>>>  endif # MTD_SPI_NOR
>>> diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
>>> index 121695e..364d4c6 100644
>>> --- a/drivers/mtd/spi-nor/Makefile
>>> +++ b/drivers/mtd/spi-nor/Makefile
>>> @@ -5,3 +5,4 @@ obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
>>>  obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
>>>  obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
>>>  obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
>>> +obj-$(CONFIG_SPI_ROCKCHIP_SFC)	+= rockchip-sfc.o
>>> diff --git a/drivers/mtd/spi-nor/rockchip-sfc.c b/drivers/mtd/spi-nor/rockchip-sfc.c
>>> new file mode 100644
>>> index 0000000..102c08f
>>> --- /dev/null
>>> +++ b/drivers/mtd/spi-nor/rockchip-sfc.c
>>> @@ -0,0 +1,872 @@
>>> +/*
>>> + * Rockchip Serial Flash Controller Driver
>>> + *
>>> + * Copyright (c) 2016, Rockchip Inc.
>>> + * Author: Shawn Lin <shawn.lin@rock-chips.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +#include <linux/bitops.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/completion.h>
>>> +#include <linux/dma-mapping.h>
>>> +#include <linux/iopoll.h>
>>> +#include <linux/module.h>
>>> +#include <linux/mtd/mtd.h>
>>> +#include <linux/mtd/spi-nor.h>
>>> +#include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/slab.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)
>>> +/* 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
>>> +
>>> +#define SFC_MAX_CHIPSELECT_NUM		4
>>> +#define SFC_DMA_MAX_LEN			0x4000
>>> +#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 spi_nor nor;
>>> +	struct rockchip_sfc *sfc;
>>> +};
>>> +
>>> +struct rockchip_sfc {
>>> +	struct device *dev;
>>> +	struct mutex lock;
>>> +	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];
>>> +	u32 num_chip;
>>> +	bool use_dma;
>>> +	/* use negative edge of hclk to latch data */
>>> +	bool negative_edge;
>>> +};
>>> +
>>> +static int get_if_type(struct rockchip_sfc *sfc, enum read_mode flash_read)
>>> +{
>>> +	if (flash_read == SPI_NOR_DUAL)
>>> +		return IF_TYPE_DUAL;
>>> +	else if (flash_read == SPI_NOR_QUAD)
>>> +		return IF_TYPE_QUAD;
>>> +	else if (flash_read == SPI_NOR_NORMAL ||
>>> +		 flash_read == SPI_NOR_FAST)
>>> +		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);
>>> +	return err;
>>> +}
>>> +
>>> +static int rockchip_sfc_init(struct rockchip_sfc *sfc)
>>> +{
>>> +	int err;
>>> +
>>> +	err = rockchip_sfc_reset(sfc);
>>> +	if (err)
>>> +		return err;
>>> +
>>> +	/* Mask all eight interrupts */
>>> +	writel_relaxed(0xff, sfc->regbase + SFC_IMR);
>>> +
>>> +	/*
>>> +	 * Phase configure for sfc to latch data by using
>>> +	 * ahb clock, and this configuration should be Soc
>>> +	 * specific.
>>> +	 */
>>> +	if (sfc->negative_edge)
>>> +		writel_relaxed(SFC_CTRL_PHASE_SEL_NEGETIVE,
>>> +			       sfc->regbase + SFC_CTRL);
>>> +	else
>>> +		writel_relaxed(0, sfc->regbase + SFC_CTRL);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int rockchip_sfc_prep(struct spi_nor *nor, enum spi_nor_ops ops)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&sfc->lock);
>>> +	pm_runtime_get_sync(sfc->dev);
>>> +
>>> +	ret = clk_set_rate(sfc->clk, priv->clk_rate);
>>> +	if (ret)
>>> +		goto out;
>>> +
>>> +	ret = clk_prepare_enable(sfc->clk);
>>> +	if (ret)
>>> +		goto out;
>>> +
>>> +	return 0;
>>> +
>>> +out:
>>> +	mutex_unlock(&sfc->lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static void rockchip_sfc_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +
>>> +	clk_disable_unprepare(sfc->clk);
>>> +	mutex_unlock(&sfc->lock);
>>> +	pm_runtime_mark_last_busy(sfc->dev);
>>> +	pm_runtime_put_autosuspend(sfc->dev);
>>> +}
>>> +
>>> +static int rockchip_sfc_wait_op_finish(struct rockchip_sfc *sfc)
>>> +{
>>> +	int err;
>>> +	u32 status;
>>> +
>>> +	/*
>>> +	 * Note: tx and rx share the same fifo, so the rx's water level
>>> +	 * is the same as rx's, which means this function could be reused
>>> +	 * for checking the read operations as well.
>>> +	 */
>>> +	err = readl_poll_timeout(sfc->regbase + SFC_FSR, status,
>>> +				 status & SFC_FSR_TX_IS_EMPTY,
>>> +				 20, jiffies_to_usecs(2 * HZ));
>>> +	if (err)
>>> +		dev_err(sfc->dev, "SFC fifo never empty\n");
>>> +
>>> +	return err;
>>> +}
>>> +
>>> +static int rockchip_sfc_op_reg(struct spi_nor *nor,
>>> +				u8 opcode, int len, u8 optype)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	u32 reg;
>>> +	bool tx_no_empty, rx_no_empty, is_busy;
>>> +	int err;
>>> +
>>> +	reg = readl_relaxed(sfc->regbase + SFC_FSR);
>>> +	tx_no_empty = !(reg & SFC_FSR_TX_IS_EMPTY);
>>> +	rx_no_empty = !(reg & SFC_FSR_RX_IS_EMPTY);
>>> +
>>> +	is_busy = readl_relaxed(sfc->regbase + SFC_SR);
>>> +
>>> +	if (tx_no_empty || rx_no_empty || is_busy) {
>>> +		err = rockchip_sfc_reset(sfc);
>>> +		if (err)
>>> +			return err;
>>> +	}
>>> +
>>> +	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 rockchip_sfc_wait_op_finish(sfc);
>>> +}
>>> +
>>> +static void rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len)
>>> +{
>>> +	u32 tmp, i;
>>> +	int total_len = len;
>>> +
>>> +	/* 32-bit access only */
>>> +	if (len >= 4 && !((u32)buf & 0x03)) {
>
> 	if (len >= sizeof(u32) && IS_ALIGNED(buf, sizeof(u32))) {
>>> +		ioread32_rep(sfc->regbase + SFC_DATA, buf, len >> 2);
>>> +		len %= 4;
>>> +		buf += total_len - len;
>>> +	}
>>> +
>>> +	/* read the rest bytes */
>>> +	for (i = 0; i < len; i++) {
>>> +		if (!(i & 0x03))
>>> +			tmp = readl_relaxed(sfc->regbase + SFC_DATA);
>>> +		buf[i] = (tmp >> ((i & 0x03) * 8)) & 0xff;
>>> +	}
>>> +}
>>> +
>>> +static int rockchip_sfc_read_reg(struct spi_nor *nor, u8 opcode,
>>> +				 u8 *buf, int len)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	int ret;
>>> +
>>> +	ret = rockchip_sfc_op_reg(nor, opcode, len, SFC_CMD_DIR_RD);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	rockchip_sfc_read_fifo(sfc, buf, len);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int rockchip_sfc_write_reg(struct spi_nor *nor, u8 opcode,
>>> +				  u8 *buf, int len)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	u32 dwords;
>>> +
>>> +	/* Align bytes to dwords */
>>> +	dwords = DIV_ROUND_UP(len, sizeof(u32));
>>> +	iowrite32_rep(sfc->regbase + SFC_DATA, buf, dwords);
>
> iowrite32_rep() is likely to be implemented with writesl() and writesl()
> casts its "const void *buffer" argument into a "const u32 *buf" local
> variable. Then this buf variable is used with __raw_writel(*buf++).
>
> Hence if the u8 *buf argument of rockchip_sfc_write_reg() is not aligned to
> 32 bits, this function performs unaligned accesses to the memory pointed by
> buf.
>

Good catch, will fix it.

>>> +
>>> +	return rockchip_sfc_op_reg(nor, opcode, len, SFC_CMD_DIR_WR);
>>> +}
>>> +
>>> +static inline void rockchip_sfc_setup_transfer(struct spi_nor *nor,
>>> +					       loff_t from_to,
>>> +					       size_t len, u8 op_type)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	u32 reg;
>>> +	u8 if_type = 0;
>>> +
>>> +	if_type = get_if_type(sfc, nor->flash_read);
>>> +	writel_relaxed((if_type << SFC_CTRL_DATA_BITS_SHIFT) |
>>> +		       (if_type << SFC_CTRL_ADDR_BITS_SHIFT) |
>>> +		       (if_type << SFC_CTRL_CMD_BITS_SHIFT) |
>>> +		       (sfc->negative_edge ? SFC_CTRL_PHASE_SEL_NEGETIVE : 0),
>>> +		       sfc->regbase + SFC_CTRL);
>>
>> Marek rose an issue when commenting v3:
>>
>> Looking at that code it seems that even if the hardware can support SPI
>> 1-1-n protocols, this driver actually allows SPI n-n-n protocols.
>>
>> However with the current spi-nor framework, the values of the enum
>> read_mode must be understood this way:
>> SPI_NOR_FAST or SPI_NOR_NORMAL: SPI 1-1-1 protocol
>> SPI_NOR_DUAL: SPI 1-1-2 protocol
>> SPI_NOR_QUAD: SPI 1-1-4 protocol
>>
>> Support to other SPI protocols such as SPI 1-4-4 or SPI 4-4-4 as not been
>> accepted in mainline yet.
>>
>> Below in this driver, spi_nor_scan() is called with the value SPI_NOR_QUAD
>> hence it asks the spi-nor framework for using the SPI 1-1-4 (and not SPI
>> 4-4-4) *when supported by the QSPI memory*.
>>
>> Also since the driver was tested with a Winbond w25q256 memory, let me warn
>> you that currently the SPI_NOR_QUAD_READ flag is *NOT* set in the "w25q256"
>> entry of the spi_nor_ids[] array. So this claims this memory is not capable
>> of using the SPI 1-1-4 protocol even if the Winbond memory actually
>> supports this protocol. Then the spi-nor framework selects the SPI 1-1-1
>> protocol as a fallback.
>> That's why you have succeeded in using your driver but it would have failed
>> with another QSPI memory with its SPI_NOR_QUAD_READ flag due to a protocol
>> mismatch.
>>
>> So with the current spi-nor framework you must set
>> SFC_CTRL_{DATA|ADDR}_BITS_SHIFT to IF_TYPE_STD.
>>
>> Later, once the patch adding support to other SPI protocols would have been
>> accepted in mainline, you could update your driver to tell the spi-nor
>> framework that the rockchip controller also supports SPI 1-2-2 and SPI
>> 1-4-4 protocols.
>>
>>
>>> +
>>> +	if (op_type == SFC_CMD_DIR_WR)
>>> +		reg = nor->program_opcode << SFC_CMD_IDX_SHIFT;
>>> +	else
>>> +		reg = nor->read_opcode << SFC_CMD_IDX_SHIFT;
>>> +
>>> +	reg |= op_type << SFC_CMD_DIR_SHIFT;
>>> +	reg |= (nor->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;
>>
>> Looking at the definitions of SFC_CMD_TRAN_BYTES_SHIFT (16) and
>> SFC_CMD_CS_SHIFT (30), I understand that the bitfield for the transfer
>> length lays between bits 16 and 30 hence a 14 bit value at most.
>> So what if len is greater than 16384? It overflows in the cs bitfield?
>>
>> You should apply masks to avoid such overflows and also test the len value
>> then report the actual number of transferred bytes.
>>
>>> +
>>> +	if (op_type == SFC_CMD_DIR_RD)
>>> +		reg |= SFC_CMD_DUMMY(nor->read_dummy);
>>> +
>>> +	/* Should minus one as 0x0 means 1 bit flash address */
>>> +	writel_relaxed(nor->addr_width * 8 - 1, sfc->regbase + SFC_ABIT);
>>> +	writel_relaxed(reg, sfc->regbase + SFC_CMD);
>>> +	writel_relaxed(from_to, sfc->regbase + SFC_ADDR);
>>> +}
>>> +
>>> +static int rockchip_sfc_do_dma_transfer(struct spi_nor *nor, loff_t from_to,
>>> +					dma_addr_t dma_buf, size_t len,
>>> +					u8 op_type)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	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);
>>> +
>>> +	rockchip_sfc_setup_transfer(nor, from_to, len, op_type);
>>> +	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_relaxed(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;
>>> +	}
>>> +
>>> +	/* 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 rockchip_sfc_wait_op_finish(sfc);
>>> +}
>>> +
>>> +static inline int rockchip_sfc_pio_write(struct rockchip_sfc *sfc, u_char *buf,
>>> +					 size_t len)
>>> +{
>>> +	u32 dwords;
>>> +
>>> +	/*
>>> +	 * Align bytes to dwords, although we will write some extra
>>> +	 * bytes to fifo but the transfer bytes number in SFC_CMD
>>> +	 * register will make sure we just send out the expected
>>> +	 * byte numbers and the extra bytes will be clean before
>>> +	 * setting up the next transfer. We should always round up
>>> +	 * to align to DWORD as the ahb for Rockchip Socs won't
>>> +	 * support non-aligned-to-DWORD transfer.
>>> +	 */
>>> +	dwords = DIV_ROUND_UP(len, sizeof(u32));
>>> +	iowrite32_rep(sfc->regbase + SFC_DATA, buf, dwords);
>>> +
>
> Here again the buf pointer might not be aligned to 4 bytes.
>
>>> +	return rockchip_sfc_wait_op_finish(sfc);
>>> +}
>>> +
>>> +static inline int rockchip_sfc_pio_read(struct rockchip_sfc *sfc, u_char *buf,
>>> +					size_t len)
>>> +{
>>> +	rockchip_sfc_read_fifo(sfc, buf, len);
>>> +
>>> +	return rockchip_sfc_wait_op_finish(sfc);
>>> +}
>>> +
>>> +static int rockchip_sfc_pio_transfer(struct spi_nor *nor, loff_t from_to,
>>> +				     size_t len, u_char *buf, u8 op_type)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +
>>> +	rockchip_sfc_setup_transfer(nor, from_to, len, op_type);
>>> +
>>> +	if (op_type == SFC_CMD_DIR_WR)
>>> +		return rockchip_sfc_pio_write(sfc, buf, len);
>>> +	else
>>> +		return rockchip_sfc_pio_read(sfc, buf, len);
>>> +}
>>> +
>>> +static int rockchip_sfc_dma_transfer(struct spi_nor *nor, loff_t from_to,
>>> +				     size_t len, u_char *buf, u8 op_type)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	size_t offset;
>>> +	int ret;
>>> +	dma_addr_t dma_addr = 0;
>>> +	int dma_dir;
>>> +
>>> +	dma_dir = (op_type == SFC_CMD_DIR_RD) ?
>>> +		   DMA_FROM_DEVICE : DMA_TO_DEVICE;
>>> +
>>> +	for (offset = 0; offset < len; offset += SFC_DMA_MAX_LEN) {
>>> +		size_t trans = min_t(size_t, SFC_DMA_MAX_LEN, len - offset);
>>> +
>>> +		dma_addr = dma_map_single(NULL, (void *)buf, trans, dma_dir);
>> not good: buf may have been allocated with vmalloc() hence the pages of buf
>> are not garanteed to be contiguous in physical memory.
>>
>> Just write a ubifs image into your QSPI memory and try to mount it. You are
>> very likely to notice some issues/crashes.
>>
>>
>
> This code can only work when:
> - len <= SFC_DMA_MAX_LEN and (buf + len) points inside the very same page
> as buf.
> or
> - dma_map_single() always fails so the driver always copy from/to buf data
> to/from sfc->buffer and transfers from/to sfc->buffer_dma.
>
> Otherwise the driver always tries to dma map from buf but buf is never
> incremented by offset after a transfer. Hence the driver transfers the
> right data during the first loop but starting from the 2nd loop it
> transfers the very same data again and again till offset >= len.
>
> I think you have forgotten a "+ offset" in the dma_map_single() call:
>
> dma_map_single(NULL, (void *)buf + offset, trans, dma_dir);
>
>                ^^ should be better to provide some dev, e.g. nor->dev
>
> Anyway, like I've explained in my previous mail dma_map_single() is not
> suited to buffers allocated by vmalloc().
>

Got it, thanks.

>
>>> +
>>> +		if (dma_mapping_error(sfc->dev, dma_addr)) {
>>> +			/*
>>> +			 * If we use pre-allocated dma_buffer, we need to
>>> +			 * do a copy here.
>>> +			 */
>>> +			if (op_type == SFC_CMD_DIR_WR)
>>> +				memcpy(sfc->buffer, buf + offset, trans);
>>> +
>>> +			dma_addr = 0;
>>> +		}
>>> +
>>> +		if (op_type == SFC_CMD_DIR_WR)
>>> +			/*
>>> +			 * Flush the write data from write_buf to dma_addr
>>> +			 * if using dynamic allocated dma buffer before dma
>>> +			 * moves data from dma_addr to fifo.
>>> +			 */
>>> +			dma_sync_single_for_device(sfc->dev, dma_addr,
>>> +						   trans, DMA_TO_DEVICE);
>>> +
>>> +
>>> +		/* If failing to map dma, use pre-allocated area instead */
>>> +		ret = rockchip_sfc_do_dma_transfer(nor, from_to + offset,
>>> +						dma_addr ? dma_addr :
>>> +						sfc->dma_buffer,
>>> +						trans, op_type);
>>> +
>>> +		if (dma_addr) {
>>> +			/*
>>> +			 * Invalidate the read data from dma_addr if using
>>> +			 * dynamic allocated dma buffer after dma moves data
>>> +			 * from fifo to dma_addr.
>>> +			 */
>>> +			if (op_type == SFC_CMD_DIR_RD)
>>> +				dma_sync_single_for_cpu(sfc->dev, dma_addr,
>>> +							trans, DMA_FROM_DEVICE);
>>> +
>>> +			dma_unmap_single(NULL, dma_addr,
>>> +					 trans, dma_dir);
>>> +		}
>>> +
>>> +		if (ret) {
>>> +			dev_warn(nor->dev, "DMA read timeout\n");
>>> +			return ret;
>>> +		}
>>> +		/*
>>> +		 * If we use pre-allocated dma_buffer for read, we need to
>>> +		 * do a copy here.
>>> +		 */
>>> +		if (!dma_addr && (op_type == SFC_CMD_DIR_RD))
>>> +			memcpy(buf + offset, sfc->buffer, trans);
>>> +	}
>>> +
>>> +	return len;
>>> +}
>>> +
>>> +static ssize_t rockchip_sfc_do_rd_wr(struct spi_nor *nor, loff_t from_to,
>>> +				     size_t len, u_char *buf, u32 op_type)
>>> +{
>>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>>> +	struct rockchip_sfc *sfc = priv->sfc;
>>> +	int ret;
>>> +
>>> +	if (likely(sfc->use_dma))
>>> +		return rockchip_sfc_dma_transfer(nor, from_to, len,
>>> +						 buf, op_type);
>>> +
>>> +	/* Fall back to PIO mode if DMA isn't present */
>>> +	ret = rockchip_sfc_pio_transfer(nor, from_to, len,
>>> +					(u_char *)buf, op_type);
>>> +	if (ret) {
>>> +		if (op_type == SFC_CMD_DIR_RD)
>>> +			dev_warn(nor->dev, "PIO read timeout\n");
>>> +		else
>>> +			dev_warn(nor->dev, "PIO write timeout\n");
>>> +		return ret;
>>> +	}
>>> +
>>> +	return len;
>>> +}
>>> +
>>> +static ssize_t rockchip_sfc_read(struct spi_nor *nor, loff_t from,
>>> +				 size_t len, u_char *read_buf)
>>> +{
>>> +	return rockchip_sfc_do_rd_wr(nor, from, len,
>>> +				     read_buf, SFC_CMD_DIR_RD);
>>> +}
>>> +
>>> +static ssize_t rockchip_sfc_write(struct spi_nor *nor, loff_t to,
>>> +				  size_t len, const u_char *write_buf)
>>> +{
>>> +	return rockchip_sfc_do_rd_wr(nor, to, len,
>>> +				     (u_char *)write_buf,
>>> +				     SFC_CMD_DIR_WR);
>>> +}
>>> +
>>> +static int rockchip_sfc_register(struct device_node *np,
>>> +				 struct rockchip_sfc *sfc)
>>> +{
>>> +	struct device *dev = sfc->dev;
>>> +	struct mtd_info *mtd;
>>> +	struct spi_nor *nor;
>>> +	int ret;
>>> +
>>> +	nor = &sfc->flash[sfc->num_chip].nor;
>>> +	nor->dev = dev;
>>> +	spi_nor_set_flash_node(nor, np);
>>> +
>>> +	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;
>>> +	nor->priv = &(sfc->flash[sfc->num_chip]);
>>> +
>>> +	nor->prepare = rockchip_sfc_prep;
>>> +	nor->unprepare = rockchip_sfc_unprep;
>>> +	nor->read_reg = rockchip_sfc_read_reg;
>>> +	nor->write_reg = rockchip_sfc_write_reg;
>>> +	nor->read = rockchip_sfc_read;
>>> +	nor->write = rockchip_sfc_write;
>>> +	nor->erase = NULL;
>>> +	ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	mtd = &(nor->mtd);
>>> +	mtd->name = np->name;
>>> +	ret = mtd_device_register(mtd, NULL, 0);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	sfc->num_chip++;
>>> +	return 0;
>>> +}
>>> +
>>> +static void rockchip_sfc_unregister_all(struct rockchip_sfc *sfc)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < sfc->num_chip; i++)
>>> +		mtd_device_unregister(&sfc->flash[i].nor.mtd);
>>> +}
>>> +
>>> +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)
>>> +			goto fail;
>>> +
>>> +		if (sfc->num_chip == SFC_MAX_CHIPSELECT_NUM) {
>>> +			dev_warn(dev, "Exceeds the max cs limitation\n");
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +
>>> +fail:
>>> +	dev_err(dev, "Failed to register all chips\n");
>>> +	/* Unregister all the _registered_ nor flash */
>>> +	rockchip_sfc_unregister_all(sfc);
>>> +	return ret;
>>> +}
>>> +
>>> +static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
>>> +{
>>> +	struct rockchip_sfc *sfc = dev_id;
>>> +	u32 reg;
>>> +
>>> +	reg = readl_relaxed(sfc->regbase + SFC_RISR);
>>> +	dev_dbg(sfc->dev, "Get irq: 0x%x\n", reg);
>>> +
>>> +	/* 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 resource *res;
>>> +	struct rockchip_sfc *sfc;
>>> +	int ret;
>>> +
>>> +	sfc = devm_kzalloc(dev, sizeof(*sfc), GFP_KERNEL);
>>> +	if (!sfc)
>>> +		return -ENOMEM;
>>> +
>>> +	platform_set_drvdata(pdev, sfc);
>>> +	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, "hsfc");
>>> +	if (IS_ERR(sfc->hclk)) {
>>> +		dev_err(&pdev->dev, "Failed to get sfc ahp clk\n");
>>> +		return PTR_ERR(sfc->hclk);
>>> +	}
>>> +
>>> +	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_DMA_MAX_LEN,
>>> +			&sfc->dma_buffer, GFP_KERNEL);
>>> +	if (!sfc->buffer)
>>> +		return -ENOMEM;
>>> +
>>> +	mutex_init(&sfc->lock);
>>> +
>>> +	ret = clk_prepare_enable(sfc->hclk);
>>> +	if (ret) {
>>> +		dev_err(&pdev->dev, "Failed to enable hclk\n");
>>> +		goto err_hclk;
>>> +	}
>>> +
>>> +	ret = clk_prepare_enable(sfc->clk);
>>> +	if (ret) {
>>> +		dev_err(&pdev->dev, "Failed to enable clk\n");
>>> +		goto err_clk;
>>> +	}
>>> +
>>> +	sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
>>> +					      "rockchip,sfc-no-DMA");
>>> +
>>> +	sfc->negative_edge = of_device_is_compatible(sfc->dev->of_node,
>>> +						     "rockchip,rk1108-sfc");
>>> +	/* 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;
>>> +
>>> +	pm_runtime_get_noresume(&pdev->dev);
>>> +	pm_runtime_set_active(&pdev->dev);
>>> +	pm_runtime_enable(&pdev->dev);
>>> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
>>> +	pm_runtime_use_autosuspend(&pdev->dev);
>>> +
>>> +	ret = rockchip_sfc_register_all(sfc);
>>> +	if (ret)
>>> +		goto err_register;
>>> +
>>> +	clk_disable_unprepare(sfc->clk);
>>> +	pm_runtime_put_autosuspend(&pdev->dev);
>>> +	return 0;
>>> +
>>> +err_register:
>>> +	pm_runtime_disable(&pdev->dev);
>>> +	pm_runtime_set_suspended(&pdev->dev);
>>> +	pm_runtime_put_noidle(&pdev->dev);
>>> +err_irq:
>>> +	clk_disable_unprepare(sfc->clk);
>>> +err_clk:
>>> +	clk_disable_unprepare(sfc->hclk);
>>> +err_hclk:
>>> +	mutex_destroy(&sfc->lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static int rockchip_sfc_remove(struct platform_device *pdev)
>>> +{
>>> +	struct rockchip_sfc *sfc = platform_get_drvdata(pdev);
>>> +
>>> +	pm_runtime_get_sync(&pdev->dev);
>>> +	pm_runtime_disable(&pdev->dev);
>>> +	pm_runtime_put_noidle(&pdev->dev);
>>> +
>>> +	rockchip_sfc_unregister_all(sfc);
>>> +	mutex_destroy(&sfc->lock);
>>> +	clk_disable_unprepare(sfc->clk);
>>> +	clk_disable_unprepare(sfc->hclk);
>>> +	return 0;
>>> +}
>>> +
>>> +#ifdef CONFIG_PM
>>> +int rockchip_sfc_runtime_suspend(struct device *dev)
>>> +{
>>> +	struct rockchip_sfc *sfc = dev_get_drvdata(dev);
>>> +
>>> +	clk_disable_unprepare(sfc->hclk);
>>> +	return 0;
>>> +}
>>> +
>>> +int rockchip_sfc_runtime_resume(struct device *dev)
>>> +{
>>> +	struct rockchip_sfc *sfc = dev_get_drvdata(dev);
>>> +
>>> +	clk_prepare_enable(sfc->hclk);
>>> +	return rockchip_sfc_reset(sfc);
>>> +}
>>> +#endif /* CONFIG_PM */
>>> +
>>> +static const struct of_device_id rockchip_sfc_dt_ids[] = {
>>> +	{ .compatible = "rockchip,sfc"},
>>> +	{ /* sentinel */ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids);
>>> +
>>> +static const struct dev_pm_ops rockchip_sfc_dev_pm_ops = {
>>> +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>>> +				pm_runtime_force_resume)
>>> +	SET_RUNTIME_PM_OPS(rockchip_sfc_runtime_suspend,
>>> +			   rockchip_sfc_runtime_resume, NULL)
>>> +};
>>> +
>>> +static struct platform_driver rockchip_sfc_driver = {
>>> +	.driver = {
>>> +		.name	= "rockchip-sfc",
>>> +		.of_match_table = rockchip_sfc_dt_ids,
>>> +		.pm = &rockchip_sfc_dev_pm_ops,
>>> +	},
>>> +	.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>");
>>>
>>
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>
>
>
>
>


-- 
Best Regards
Shawn Lin


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

^ permalink raw reply

* Re: [PATCH] Add Nexus 6P(msm8994) SDHCI support
From: Jeremy McNicoll @ 2017-01-17  1:33 UTC (permalink / raw)
  To: Bastian.=?iso-8859-1?B?S/ZjaGVyIDxnaXRAa2Noci5kZT4=?=
  Cc: linux-arm-msm, linux-soc, devicetree, linux-mmc, jeremymc,
	robh+dt, andy.gross, david.brown
In-Reply-To: <20161228162134.13687-1-git@kchr.de>

On Wed, Dec 28, 2016 at 05:21:34PM +0100, Bastian Köcher wrote:
> Signed-off-by: Bastian Köcher <git@kchr.de>
> ---
>
Sorry for the delay, my vactions this year ended up being a
little longer than expected given the chaos in Fort Lauderdale
airport. 


See comments / suggestions below.

> Patch for enabling Nexus 6P(msm8994) SDHCI support.
> 
> The patch is based on the work of Jeremy McNicoll for 
> the Nexus 5x:
> https://www.spinics.net/lists/linux-arm-msm/msg24827.html
> 
>  .../arm64/boot/dts/qcom/msm8994-angler-rev-101.dts | 262 +++++++++++++++++++++
>  arch/arm64/boot/dts/qcom/msm8994-pins.dtsi         |  82 +++++++
>  arch/arm64/boot/dts/qcom/msm8994.dtsi              | 154 ++++++++++--
>  3 files changed, 483 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts
> index dfa08f513dc4..d0bf9072b614 100644
> --- a/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts
> +++ b/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts
> @@ -38,3 +38,265 @@
>  		};
>  	};
>  };
> +
> +&smd_rpm {

This node seems to be identical to what I have, so it makes
more sense for us to share this type of thing.
Can you take a look at the V2 I just sent and CC'd you on.
By removing smd_rpm and including 
arch/arm64/boot/dts/qcom/msm8994-smd-rpm.dtsi
you get all my fixes for FREE!



> +	rpm {
> +		rpm_requests {
> +			pm8994-regulators {
> +
> +				vdd_l1-supply = <&pm8994_s1>;
> +				vdd_l2_26_28-supply = <&pm8994_s3>;
> +				vdd_l3_11-supply = <&pm8994_s3>;
> +				vdd_l4_27_31-supply = <&pm8994_s3>;
> +				vdd_l5_7-supply = <&pm8994_s3>;
> +				vdd_l6_12_32-supply = <&pm8994_s5>;
> +				vdd_l8_16_30-supply = <&vreg_vph_pwr>;
> +				vdd_l9_10_18_22-supply = <&vreg_vph_pwr>;
> +				vdd_l13_19_23_24-supply = <&vreg_vph_pwr>;
> +				vdd_l14_15-supply = <&pm8994_s5>;
> +				vdd_l17_29-supply = <&vreg_vph_pwr>;
> +				vdd_l20_21-supply = <&vreg_vph_pwr>;
> +				vdd_l25-supply = <&pm8994_s5>;
> +				/*vin_lvs1_2 = <&pm8994_s4>; */
> +
> +				s1 {
> +					regulator-min-microvolt = <800000>;
> +					regulator-max-microvolt = <800000>;
> +				};
> +
> +				s2 {
> +				};
> +
> +				s3 {
> +					regulator-min-microvolt = <1300000>;
> +					regulator-max-microvolt = <1300000>;
> +				};
> +
> +				s4 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					regulator-allow-set-load;
> +					regulator-system-load = <325000>;
> +				};
> +
> +				s5 {
> +					regulator-min-microvolt = <2150000>;
> +					regulator-max-microvolt = <2150000>;
> +				};
> +
> +				s7 {
> +					regulator-min-microvolt = <1000000>;
> +					regulator-max-microvolt = <1000000>;
> +				};
> +
> +				l1 {
> +					regulator-min-microvolt = <1000000>;
> +					regulator-max-microvolt = <1000000>;
> +				};
> +
> +				l2 {
> +					regulator-min-microvolt = <1250000>;
> +					regulator-max-microvolt = <1250000>;
> +				};
> +
> +				l3 {
> +					regulator-min-microvolt = <1200000>;
> +					regulator-max-microvolt = <1200000>;
> +				};
> +
> +				l4 {
> +					regulator-min-microvolt = <1225000>;
> +					regulator-max-microvolt = <1225000>;
> +				};
> +
> +				l5 {
> +				};
> +
> +				l6 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +				};
> +
> +				l7 {
> +				};
> +
> +				l8 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +				};
> +
> +				l9 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +				};
> +
> +				l10 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +				};
> +
> +				l11 {
> +					regulator-min-microvolt = <1200000>;
> +					regulator-max-microvolt = <1200000>;
> +					qcom,init-voltage = <1200000>;
> +				};
> +
> +				l12 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +					proxy-supply = <&pm8994_l12>;
> +					qcom,proxy-consumer-enable;
> +					qcom,proxy-consumer-current = <10000>;
> +					status = "okay";
> +				};
> +
> +				l13 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <2950000>;
> +					qcom,init-voltage = <2950000>;
> +					status = "okay";
> +				};
> +
> +				l14 {
> +					regulator-min-microvolt = <1200000>;
> +					regulator-max-microvolt = <1200000>;
> +					qcom,init-voltage = <1200000>;
> +					proxy-supply = <&pm8994_l14>;
> +					qcom,proxy-consumer-enable;
> +					qcom,proxy-consumer-current = <10000>;
> +					status = "okay";
> +				};
> +
> +				l15 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +					status = "okay";
> +				};
> +
> +				l16 {
> +					regulator-min-microvolt = <2700000>;
> +					regulator-max-microvolt = <2700000>;
> +					qcom,init-voltage = <2700000>;
> +					status = "okay";
> +				};
> +
> +				l17 {
> +					regulator-min-microvolt = <2700000>;
> +					regulator-max-microvolt = <2700000>;
> +					qcom,init-voltage = <2700000>;
> +					status = "okay";
> +				};
> +
> +				l18 {
> +					regulator-min-microvolt = <3000000>;
> +					regulator-max-microvolt = <3000000>;
> +					regulator-always-on;
> +					qcom,init-voltage = <3000000>;
> +					qcom,init-ldo-mode = <1>;
> +				};
> +
> +				l19 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +					status = "okay";
> +				};
> +
> +				l20 {
> +					regulator-min-microvolt = <2950000>;
> +					regulator-max-microvolt = <2950000>;
> +					regulator-always-on;
> +					regulator-boot-on;
> +					regulator-allow-set-load;
> +					regulator-system-load = <570000>;
> +				};
> +
> +				l21 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					regulator-always-on;
> +					qcom,init-voltage = <1800000>;
> +				};
> +
> +				l22 {
> +					regulator-min-microvolt = <3100000>;
> +					regulator-max-microvolt = <3100000>;
> +					qcom,init-voltage = <3100000>;
> +				};
> +
> +				l23 {
> +					regulator-min-microvolt = <2800000>;
> +					regulator-max-microvolt = <2800000>;
> +					qcom,init-voltage = <2800000>;
> +				};
> +
> +				l24 {
> +					regulator-min-microvolt = <3075000>;
> +					regulator-max-microvolt = <3150000>;
> +					qcom,init-voltage = <3075000>;
> +				};
> +
> +				l25 {
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +				};
> +
> +				l26 {
> +					/* TODO: value from downstream
> +					regulator-min-microvolt = <987500>;
> +					fails to apply */
> +				};
> +
> +				l27 {
> +					regulator-min-microvolt = <1050000>;
> +					regulator-max-microvolt = <1050000>;
> +					qcom,init-voltage = <1050000>;
> +				};
> +
> +				l28 {
> +					regulator-min-microvolt = <1000000>;
> +					regulator-max-microvolt = <1000000>;
> +					qcom,init-voltage = <1000000>;
> +					proxy-supply = <&pm8994_l28>;
> +					qcom,proxy-consumer-enable;
> +					qcom,proxy-consumer-current = <10000>;
> +				};
> +
> +				l29 {
> +					/* TODO: Unsupported voltage range..
> +					regulator-min-microvolt = <2800000>;
> +					regulator-max-microvolt = <2800000>;
> +					qcom,init-voltage = <2800000>;
> +					*/
> +				};
> +
> +				l30 {
> +					/* TODO: get this verified
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +					*/
> +				};
> +
> +				l31 {
> +					regulator-min-microvolt = <1262500>;
> +					regulator-max-microvolt = <1262500>;
> +					qcom,init-voltage = <1262500>;
> +				};
> +
> +				l32 {
> +					/* TODO: get this verified
> +					regulator-min-microvolt = <1800000>;
> +					regulator-max-microvolt = <1800000>;
> +					qcom,init-voltage = <1800000>;
> +					*/
> +				};
> +
> +			};
> +		};
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/qcom/msm8994-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8994-pins.dtsi
> index 0e4eea0df25d..66c46b8f9e83 100644
> --- a/arch/arm64/boot/dts/qcom/msm8994-pins.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8994-pins.dtsi
> @@ -35,4 +35,86 @@
>  			bias-pull-down;
>  		};
>  	};
> +
> +	/* 0-3 for sdc1 4-6 for sdc2 */
> +	/* Order of pins */
> +	/* SDC1: CLK -> 0, CMD -> 1, DATA -> 2, RCLK -> 3 */
> +	/* SDC2: CLK -> 4, CMD -> 5, DATA -> 6 */
> +	pmx_sdc1_clk {

Change all your node names,
 anything before the '{'
 to make sure it doesn't have '_' underscores.



> +		sdc1_clk_on: clk_on {

change this to 

sdc1_clk_on: clk-on {

label: node-name {




> +			pinmux {
> +				pins = "sdc1_clk";
> +			};
> +			pinconf {
> +				pins = "sdc1_clk";
> +				bias-disable = <0>; /* No pull */
> +				drive-strength = <16>; /* 16mA */
> +			};
> +		};
> +		sdc1_clk_off: clk_off {
> +			pinmux {
> +				pins = "sdc1_clk";
> +			};
> +			pinconf {
> +				pins = "sdc1_clk";
> +				bias-disable = <0>; /* No pull */
> +				drive-strength = <2>; /* 2mA */
> +			};
> +		};
> +	};
> +
> +	pmx_sdc1_cmd {
> +		sdc1_cmd_on: cmd_on {
> +			pinmux {
> +				pins = "sdc1_cmd";
> +			};
> +			pinconf {
> +				pins = "sdc1_cmd";
> +				bias-pull-up;
> +				drive-strength = <8>;
> +			};
> +		};
> +		sdc1_cmd_off: cmd_off {
> +			pinmux {
> +				pins = "sdc1_cmd";
> +			};
> +			pinconf {
> +				pins = "sdc1_cmd";
> +				bias-pull-up = <0x3>; /* same as 3.10 ?? */
> +				drive-strength = <2>; /* 2mA */
> +			};
> +		};
> +	};
> +
> +	pmx_sdc1_data {
> +		sdc1_data_on: data_on {
> +			pinmux {
> +				pins = "sdc1_data";
> +			};
> +			pinconf {
> +				pins = "sdc1_data";
> +				bias-pull-up;
> +				drive-strength = <8>; /* 8mA */
> +			};
> +		};
> +		sdc1_data_off: data_off {
> +			pinmux {
> +				pins = "sdc1_data";
> +			};
> +			pinconf {
> +				pins = "sdc1_data";
> +				bias-pull-up;
> +				drive-strength = <2>;
> +			};
> +		};
> +	};
> +
> +	pmx_sdc1_rclk {
> +		sdc1_rclk_on: rclk_on {
> +			bias-pull-down; /* pull down */
> +		};
> +		sdc1_rclk_off: rclk_off {
> +			bias-pull-down; /* pull down */
> +		};
> +	};
>  };
> diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi
> index f33c41d01c86..703888d608c6 100644
> --- a/arch/arm64/boot/dts/qcom/msm8994.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi
> @@ -73,6 +73,11 @@
>  				  <0xf9002000 0x1000>;
>  		};
>  
> +		apcs: syscon@f900d000 {
> +			compatible = "syscon";
> +			reg = <0xf900d000 0x2000>;
> +		};
> +
>  		timer@f9020000 {
>  			#address-cells = <1>;
>  			#size-cells = <1>;
> @@ -156,11 +161,6 @@
>  				 <&clock_gcc GCC_BLSP1_AHB_CLK>;
>  		};
>  
> -		tcsr_mutex_regs: syscon@fd484000 {
> -			compatible = "syscon";
> -			reg = <0xfd484000 0x2000>;
> -		};
> -
>  		clock_gcc: clock-controller@fc400000 {
>  			compatible = "qcom,gcc-msm8994";
>  			#clock-cells = <1>;
> @@ -168,6 +168,75 @@
>  			#power-domain-cells = <1>;
>  			reg = <0xfc400000 0x2000>;
>  		};
> +
> +		sdhci1: mmc@f9824900 {
> +			compatible = "qcom,sdhci-msm-v4";
> +			reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
> +			reg-names = "hc_mem", "core_mem";
> +
> +			interrupts = <GIC_SPI 123 IRQ_TYPE_NONE>,
> +					<GIC_SPI 138 IRQ_TYPE_NONE>;
> +			interrupt-names = "hc_irq", "pwr_irq";
> +
> +			clocks = <&clock_gcc GCC_SDCC1_APPS_CLK>,
> +				<&clock_gcc GCC_SDCC1_AHB_CLK>;
> +			clock-names = "core", "iface";
> +
> +			pinctrl-names = "default", "sleep";
> +			pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on
> +					&sdc1_rclk_on>;
> +			pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off
> +					&sdc1_rclk_off>;
> +
> +			vdd-supply = <&pm8994_l20>;
> +			qcom,vdd-voltage-level = <2950000 2950000>;
> +			qcom,vdd-current-level = <200 570000>;
> +
> +			vdd-io-supply = <&pm8994_s4>;
> +			qcom,vdd-io-voltage-level = <1800000 1800000>;
> +			qcom,vdd-io-current-level = <200 325000>;
> +
> +			regulator-always-on;
> +			bus-width = <8>;
> +			mmc-hs400-1_8v;
> +			status = "okay";
> +		};
> +
> +		vreg_vph_pwr: vreg-vph-pwr {
> +			compatible = "regulator-fixed";
> +			status = "okay";
> +			regulator-name = "vph-pwr";
> +
> +			regulator-min-microvolt = <3600000>;
> +			regulator-max-microvolt = <3600000>;
> +
> +			regulator-always-on;
> +		};
> +
> +		rpm_msg_ram: memory@fc428000 {
> +			compatible = "qcom,rpm-msg-ram";
> +			reg = <0xfc428000 0x4000>;
> +		};
> +
> +		sfpb_mutex_regs: syscon@fd484000 {
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			compatible = "syscon";
> +			reg = <0xfd484000 0x400>;
> +		};
> +
> +		sfpb_mutex: hwmutex {
> +			compatible = "qcom,sfpb-mutex";
> +			syscon = <&sfpb_mutex_regs 0x0 0x100>;
> +			#hwlock-cells = <1>;
> +		};
> +
> +		smem {
> +			compatible = "qcom,smem";
> +			memory-region = <&smem_region>;
> +			qcom,rpm-msg-ram = <&rpm_msg_ram>;
> +			hwlocks = <&sfpb_mutex 3>;
> +		};
>  	};
>  
>  	memory {
> @@ -193,22 +262,77 @@
>  		#size-cells = <2>;
>  		ranges;
>  
> -		smem_mem: smem_region@6a00000 {
> +		smem_region: smem@6a00000 {

good.

>  			reg = <0x0 0x6a00000 0x0 0x200000>;
>  			no-map;
>  		};
>  	};
>  
> -	tcsr_mutex: hwlock {
> -		compatible = "qcom,tcsr-mutex";
> -		syscon = <&tcsr_mutex_regs 0 0x80>;
> -		#hwlock-cells = <1>;
> -	};
> +	smd_rpm: smd {
> +		compatible = "qcom,smd";
> +
> +		rpm {
> +			interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> +			qcom,ipc = <&apcs 8 0>;
> +			qcom,smd-edge = <15>;
> +			qcom,local-pid = <0>;
> +			qcom,remote-pid = <6>;
> +
> +			rpm_requests {


s/rpm_requests {/rpm-requests {/

Node names cannot have an underscore. 

-jeremy

> +				compatible = "qcom,rpm-msm8994";
> +				qcom,smd-channels = "rpm_requests";
> +
> +				rpmcc: qcom,rpmcc {
> +					/* TODO: update when rpmcc-msm8994 support added */
> +					compatible = "qcom,rpmcc-msm8916",
> +							"qcom,rpmcc";
> +					#clock-cells = <1>;
> +				};
>  
> -	qcom,smem@6a00000 {
> -		compatible = "qcom,smem";
> -		memory-region = <&smem_mem>;
> -		hwlocks = <&tcsr_mutex 3>;
> +				smd_rpm_regulators: pm8994-regulators {
> +					compatible = "qcom,rpm-pm8994-regulators";
> +
> +					pm8994_s1: s1 {};
> +					pm8994_s2: s2 {};
> +					pm8994_s3: s3 {};
> +					pm8994_s4: s4 {};
> +					pm8994_s5: s5 {};
> +					pm8994_s6: s6 {};
> +					pm8994_s7: s7 {};
> +
> +					pm8994_l1: l1 {};
> +					pm8994_l2: l2 {};
> +					pm8994_l3: l3 {};
> +					pm8994_l4: l4 {};
> +					pm8994_l6: l6 {};
> +					pm8994_l8: l8 {};
> +					pm8994_l9: l9 {};
> +					pm8994_l10: l10 {};
> +					pm8994_l11: l11 {};
> +					pm8994_l12: l12 {};
> +					pm8994_l13: l13 {};
> +					pm8994_l14: l14 {};
> +					pm8994_l15: l15 {};
> +					pm8994_l16: l16 {};
> +					pm8994_l17: l17 {};
> +					pm8994_l18: l18 {};
> +					pm8994_l19: l19 {};
> +					pm8994_l20: l20 {};
> +					pm8994_l21: l21 {};
> +					pm8994_l22: l22 {};
> +					pm8994_l23: l23 {};
> +					pm8994_l24: l24 {};
> +					pm8994_l25: l25 {};
> +					pm8994_l26: l26 {};
> +					pm8994_l27: l27 {};
> +					pm8994_l28: l28 {};
> +					pm8994_l29: l29 {};
> +					pm8994_l30: l30 {};
> +					pm8994_l31: l31 {};
> +					pm8994_l32: l32 {};
> +				};
> +			};
> +		};
>  	};
>  };
>  
> -- 
> 2.11.0
> 

^ permalink raw reply

* Re: [PATCH v4 2/2] mtd: spi-nor: add rockchip serial flash controller driver
From: Shawn Lin @ 2017-01-17  1:31 UTC (permalink / raw)
  To: Cyrille Pitchen
  Cc: David Woodhouse, Brian Norris, shawn.lin-TNX95d0MmH7DzftRWevZcw,
	Marek Vasut, Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Heiko Stuebner
In-Reply-To: <e5852f21-7aa0-8091-dc85-774e306e6f73-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>

Hi Cyrille,

On 2017/1/16 19:10, Cyrille Pitchen wrote:
> Hi Shawn,
>
> Le 15/12/2016 à 10:27, Shawn Lin a écrit :
>> Add rockchip serial flash controller driver
>>
>> Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>
>> ---
>>
>> Changes in v4:
>> - simplify the code of get_if_type
>> - use dma_dir to simplify the code
>> - simplify the rockchip_sfc_do_rd_wr
>> - some minor improvements
>> - add reset controller when doing resume
>>
>> Changes in v3:
>> - use io{read32,write32}_rep to simplify the corner cases
>> - remove more unnecessary bit definitions
>> - some minor comment fixes and improvement
>> - fix wrong unregister function
>> - unify more code
>> - use nor to avoid constantly replicating the whole
>>   sfc->flash[sfc->num_chip].nor
>> - add email for MODULE_AUTHOR
>> - remove #if 1 --- #endif
>> - extract DMA code to imporve the code structure
>> - reset all when failing to do dma
>> - pass sfc to get_if_type
>> - rename sfc-no-dma to sfc-no-DMA
>>
>> Changes in v2:
>> - fix typos
>> - add some comment for buffer and others operations
>> - rename SFC_MAX_CHIP_NUM to MAX_CHIPSELECT_NUM
>> - use u8 for cs
>> - return -EINVAL for default case of get_if_type
>> - use readl_poll_*() to check timeout cases
>> - simplify and clarify some condition checks
>> - rework the bitshifts to simplify the code
>> - define SFC_CMD_DUMMY(x)
>> - fix ummap for dma read path and finish all the
>>   cache maintenance.
>> - rename to rockchip_sfc_chip_priv and embed struct spi_nor
>>   in it.
>> - add MODULE_AUTHOR
>> - add runtime PM and general PM support.
>> - Thanks for Marek's comments. Link:
>>   http://lists.infradead.org/pipermail/linux-mtd/2016-November/070321.html
>>
>>  MAINTAINERS                        |   8 +
>>  drivers/mtd/spi-nor/Kconfig        |   7 +
>>  drivers/mtd/spi-nor/Makefile       |   1 +
>>  drivers/mtd/spi-nor/rockchip-sfc.c | 872 +++++++++++++++++++++++++++++++++++++
>>  4 files changed, 888 insertions(+)
>>  create mode 100644 drivers/mtd/spi-nor/rockchip-sfc.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 1cd38a7..eb7e06d 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -10266,6 +10266,14 @@ L:	linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>>  S:	Odd Fixes
>>  F:	drivers/tty/serial/rp2.*
>>
>> +ROCKCHIP SERIAL FLASH CONTROLLER DRIVER
>> +M:	Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> +L:	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> +L:	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> +S:	Maintained
>> +F:	Documentation/devicetree/bindings/mtd/rockchip-sfc.txt
>> +F:	drivers/mtd/spi-nor/rockchip-sfc.c
>> +
>>  ROSE NETWORK LAYER
>>  M:	Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>
>>  L:	linux-hams-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
>> index 4a682ee..bf783a8 100644
>> --- a/drivers/mtd/spi-nor/Kconfig
>> +++ b/drivers/mtd/spi-nor/Kconfig
>> @@ -76,4 +76,11 @@ config SPI_NXP_SPIFI
>>  	  Flash. Enable this option if you have a device with a SPIFI
>>  	  controller and want to access the Flash as a mtd device.
>>
>> +config SPI_ROCKCHIP_SFC
>> +	tristate "Rockchip Serial Flash Controller(SFC)"
>> +	depends on ARCH_ROCKCHIP || COMPILE_TEST
>> +	depends on HAS_IOMEM && HAS_DMA
>> +	help
>> +	  This enables support for rockchip serial flash controller.
>> +
>>  endif # MTD_SPI_NOR
>> diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
>> index 121695e..364d4c6 100644
>> --- a/drivers/mtd/spi-nor/Makefile
>> +++ b/drivers/mtd/spi-nor/Makefile
>> @@ -5,3 +5,4 @@ obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
>>  obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
>>  obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
>>  obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
>> +obj-$(CONFIG_SPI_ROCKCHIP_SFC)	+= rockchip-sfc.o
>> diff --git a/drivers/mtd/spi-nor/rockchip-sfc.c b/drivers/mtd/spi-nor/rockchip-sfc.c
>> new file mode 100644
>> index 0000000..102c08f
>> --- /dev/null
>> +++ b/drivers/mtd/spi-nor/rockchip-sfc.c
>> @@ -0,0 +1,872 @@
>> +/*
>> + * Rockchip Serial Flash Controller Driver
>> + *
>> + * Copyright (c) 2016, Rockchip Inc.
>> + * Author: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#include <linux/bitops.h>
>> +#include <linux/clk.h>
>> +#include <linux/completion.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/module.h>
>> +#include <linux/mtd/mtd.h>
>> +#include <linux/mtd/spi-nor.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/slab.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)
>> +/* 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
>> +
>> +#define SFC_MAX_CHIPSELECT_NUM		4
>> +#define SFC_DMA_MAX_LEN			0x4000
>> +#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 spi_nor nor;
>> +	struct rockchip_sfc *sfc;
>> +};
>> +
>> +struct rockchip_sfc {
>> +	struct device *dev;
>> +	struct mutex lock;
>> +	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];
>> +	u32 num_chip;
>> +	bool use_dma;
>> +	/* use negative edge of hclk to latch data */
>> +	bool negative_edge;
>> +};
>> +
>> +static int get_if_type(struct rockchip_sfc *sfc, enum read_mode flash_read)
>> +{
>> +	if (flash_read == SPI_NOR_DUAL)
>> +		return IF_TYPE_DUAL;
>> +	else if (flash_read == SPI_NOR_QUAD)
>> +		return IF_TYPE_QUAD;
>> +	else if (flash_read == SPI_NOR_NORMAL ||
>> +		 flash_read == SPI_NOR_FAST)
>> +		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);
>> +	return err;
>> +}
>> +
>> +static int rockchip_sfc_init(struct rockchip_sfc *sfc)
>> +{
>> +	int err;
>> +
>> +	err = rockchip_sfc_reset(sfc);
>> +	if (err)
>> +		return err;
>> +
>> +	/* Mask all eight interrupts */
>> +	writel_relaxed(0xff, sfc->regbase + SFC_IMR);
>> +
>> +	/*
>> +	 * Phase configure for sfc to latch data by using
>> +	 * ahb clock, and this configuration should be Soc
>> +	 * specific.
>> +	 */
>> +	if (sfc->negative_edge)
>> +		writel_relaxed(SFC_CTRL_PHASE_SEL_NEGETIVE,
>> +			       sfc->regbase + SFC_CTRL);
>> +	else
>> +		writel_relaxed(0, sfc->regbase + SFC_CTRL);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_sfc_prep(struct spi_nor *nor, enum spi_nor_ops ops)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	int ret;
>> +
>> +	mutex_lock(&sfc->lock);
>> +	pm_runtime_get_sync(sfc->dev);
>> +
>> +	ret = clk_set_rate(sfc->clk, priv->clk_rate);
>> +	if (ret)
>> +		goto out;
>> +
>> +	ret = clk_prepare_enable(sfc->clk);
>> +	if (ret)
>> +		goto out;
>> +
>> +	return 0;
>> +
>> +out:
>> +	mutex_unlock(&sfc->lock);
>> +	return ret;
>> +}
>> +
>> +static void rockchip_sfc_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +
>> +	clk_disable_unprepare(sfc->clk);
>> +	mutex_unlock(&sfc->lock);
>> +	pm_runtime_mark_last_busy(sfc->dev);
>> +	pm_runtime_put_autosuspend(sfc->dev);
>> +}
>> +
>> +static int rockchip_sfc_wait_op_finish(struct rockchip_sfc *sfc)
>> +{
>> +	int err;
>> +	u32 status;
>> +
>> +	/*
>> +	 * Note: tx and rx share the same fifo, so the rx's water level
>> +	 * is the same as rx's, which means this function could be reused
>> +	 * for checking the read operations as well.
>> +	 */
>> +	err = readl_poll_timeout(sfc->regbase + SFC_FSR, status,
>> +				 status & SFC_FSR_TX_IS_EMPTY,
>> +				 20, jiffies_to_usecs(2 * HZ));
>> +	if (err)
>> +		dev_err(sfc->dev, "SFC fifo never empty\n");
>> +
>> +	return err;
>> +}
>> +
>> +static int rockchip_sfc_op_reg(struct spi_nor *nor,
>> +				u8 opcode, int len, u8 optype)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	u32 reg;
>> +	bool tx_no_empty, rx_no_empty, is_busy;
>> +	int err;
>> +
>> +	reg = readl_relaxed(sfc->regbase + SFC_FSR);
>> +	tx_no_empty = !(reg & SFC_FSR_TX_IS_EMPTY);
>> +	rx_no_empty = !(reg & SFC_FSR_RX_IS_EMPTY);
>> +
>> +	is_busy = readl_relaxed(sfc->regbase + SFC_SR);
>> +
>> +	if (tx_no_empty || rx_no_empty || is_busy) {
>> +		err = rockchip_sfc_reset(sfc);
>> +		if (err)
>> +			return err;
>> +	}
>> +
>> +	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 rockchip_sfc_wait_op_finish(sfc);
>> +}
>> +
>> +static void rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len)
>> +{
>> +	u32 tmp, i;
>> +	int total_len = len;
>> +
>> +	/* 32-bit access only */
>> +	if (len >= 4 && !((u32)buf & 0x03)) {
>> +		ioread32_rep(sfc->regbase + SFC_DATA, buf, len >> 2);
>> +		len %= 4;
>> +		buf += total_len - len;
>> +	}
>> +
>> +	/* read the rest bytes */
>> +	for (i = 0; i < len; i++) {
>> +		if (!(i & 0x03))
>> +			tmp = readl_relaxed(sfc->regbase + SFC_DATA);
>> +		buf[i] = (tmp >> ((i & 0x03) * 8)) & 0xff;
>> +	}
>> +}
>> +
>> +static int rockchip_sfc_read_reg(struct spi_nor *nor, u8 opcode,
>> +				 u8 *buf, int len)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	int ret;
>> +
>> +	ret = rockchip_sfc_op_reg(nor, opcode, len, SFC_CMD_DIR_RD);
>> +	if (ret)
>> +		return ret;
>> +
>> +	rockchip_sfc_read_fifo(sfc, buf, len);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_sfc_write_reg(struct spi_nor *nor, u8 opcode,
>> +				  u8 *buf, int len)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	u32 dwords;
>> +
>> +	/* Align bytes to dwords */
>> +	dwords = DIV_ROUND_UP(len, sizeof(u32));
>> +	iowrite32_rep(sfc->regbase + SFC_DATA, buf, dwords);
>> +
>> +	return rockchip_sfc_op_reg(nor, opcode, len, SFC_CMD_DIR_WR);
>> +}
>> +
>> +static inline void rockchip_sfc_setup_transfer(struct spi_nor *nor,
>> +					       loff_t from_to,
>> +					       size_t len, u8 op_type)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	u32 reg;
>> +	u8 if_type = 0;
>> +
>> +	if_type = get_if_type(sfc, nor->flash_read);
>> +	writel_relaxed((if_type << SFC_CTRL_DATA_BITS_SHIFT) |
>> +		       (if_type << SFC_CTRL_ADDR_BITS_SHIFT) |
>> +		       (if_type << SFC_CTRL_CMD_BITS_SHIFT) |
>> +		       (sfc->negative_edge ? SFC_CTRL_PHASE_SEL_NEGETIVE : 0),
>> +		       sfc->regbase + SFC_CTRL);
>
> Marek rose an issue when commenting v3:
>
> Looking at that code it seems that even if the hardware can support SPI
> 1-1-n protocols, this driver actually allows SPI n-n-n protocols.
>
> However with the current spi-nor framework, the values of the enum
> read_mode must be understood this way:
> SPI_NOR_FAST or SPI_NOR_NORMAL: SPI 1-1-1 protocol
> SPI_NOR_DUAL: SPI 1-1-2 protocol
> SPI_NOR_QUAD: SPI 1-1-4 protocol
>
> Support to other SPI protocols such as SPI 1-4-4 or SPI 4-4-4 as not been
> accepted in mainline yet.
>
> Below in this driver, spi_nor_scan() is called with the value SPI_NOR_QUAD
> hence it asks the spi-nor framework for using the SPI 1-1-4 (and not SPI
> 4-4-4) *when supported by the QSPI memory*.
>
> Also since the driver was tested with a Winbond w25q256 memory, let me warn
> you that currently the SPI_NOR_QUAD_READ flag is *NOT* set in the "w25q256"
> entry of the spi_nor_ids[] array. So this claims this memory is not capable
> of using the SPI 1-1-4 protocol even if the Winbond memory actually
> supports this protocol. Then the spi-nor framework selects the SPI 1-1-1
> protocol as a fallback.
> That's why you have succeeded in using your driver but it would have failed
> with another QSPI memory with its SPI_NOR_QUAD_READ flag due to a protocol
> mismatch.
>
> So with the current spi-nor framework you must set
> SFC_CTRL_{DATA|ADDR}_BITS_SHIFT to IF_TYPE_STD.
>
> Later, once the patch adding support to other SPI protocols would have been
> accepted in mainline, you could update your driver to tell the spi-nor
> framework that the rockchip controller also supports SPI 1-2-2 and SPI
> 1-4-4 protocols.
>

Thanks, I will fix it in v5.

>
>> +
>> +	if (op_type == SFC_CMD_DIR_WR)
>> +		reg = nor->program_opcode << SFC_CMD_IDX_SHIFT;
>> +	else
>> +		reg = nor->read_opcode << SFC_CMD_IDX_SHIFT;
>> +
>> +	reg |= op_type << SFC_CMD_DIR_SHIFT;
>> +	reg |= (nor->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;
>
> Looking at the definitions of SFC_CMD_TRAN_BYTES_SHIFT (16) and
> SFC_CMD_CS_SHIFT (30), I understand that the bitfield for the transfer
> length lays between bits 16 and 30 hence a 14 bit value at most.
> So what if len is greater than 16384? It overflows in the cs bitfield?
>
> You should apply masks to avoid such overflows and also test the len value
> then report the actual number of transferred bytes.

Sure, will fix.

>
>> +
>> +	if (op_type == SFC_CMD_DIR_RD)
>> +		reg |= SFC_CMD_DUMMY(nor->read_dummy);
>> +
>> +	/* Should minus one as 0x0 means 1 bit flash address */
>> +	writel_relaxed(nor->addr_width * 8 - 1, sfc->regbase + SFC_ABIT);
>> +	writel_relaxed(reg, sfc->regbase + SFC_CMD);
>> +	writel_relaxed(from_to, sfc->regbase + SFC_ADDR);
>> +}
>> +
>> +static int rockchip_sfc_do_dma_transfer(struct spi_nor *nor, loff_t from_to,
>> +					dma_addr_t dma_buf, size_t len,
>> +					u8 op_type)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	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);
>> +
>> +	rockchip_sfc_setup_transfer(nor, from_to, len, op_type);
>> +	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_relaxed(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;
>> +	}
>> +
>> +	/* 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 rockchip_sfc_wait_op_finish(sfc);
>> +}
>> +
>> +static inline int rockchip_sfc_pio_write(struct rockchip_sfc *sfc, u_char *buf,
>> +					 size_t len)
>> +{
>> +	u32 dwords;
>> +
>> +	/*
>> +	 * Align bytes to dwords, although we will write some extra
>> +	 * bytes to fifo but the transfer bytes number in SFC_CMD
>> +	 * register will make sure we just send out the expected
>> +	 * byte numbers and the extra bytes will be clean before
>> +	 * setting up the next transfer. We should always round up
>> +	 * to align to DWORD as the ahb for Rockchip Socs won't
>> +	 * support non-aligned-to-DWORD transfer.
>> +	 */
>> +	dwords = DIV_ROUND_UP(len, sizeof(u32));
>> +	iowrite32_rep(sfc->regbase + SFC_DATA, buf, dwords);
>> +
>> +	return rockchip_sfc_wait_op_finish(sfc);
>> +}
>> +
>> +static inline int rockchip_sfc_pio_read(struct rockchip_sfc *sfc, u_char *buf,
>> +					size_t len)
>> +{
>> +	rockchip_sfc_read_fifo(sfc, buf, len);
>> +
>> +	return rockchip_sfc_wait_op_finish(sfc);
>> +}
>> +
>> +static int rockchip_sfc_pio_transfer(struct spi_nor *nor, loff_t from_to,
>> +				     size_t len, u_char *buf, u8 op_type)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +
>> +	rockchip_sfc_setup_transfer(nor, from_to, len, op_type);
>> +
>> +	if (op_type == SFC_CMD_DIR_WR)
>> +		return rockchip_sfc_pio_write(sfc, buf, len);
>> +	else
>> +		return rockchip_sfc_pio_read(sfc, buf, len);
>> +}
>> +
>> +static int rockchip_sfc_dma_transfer(struct spi_nor *nor, loff_t from_to,
>> +				     size_t len, u_char *buf, u8 op_type)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	size_t offset;
>> +	int ret;
>> +	dma_addr_t dma_addr = 0;
>> +	int dma_dir;
>> +
>> +	dma_dir = (op_type == SFC_CMD_DIR_RD) ?
>> +		   DMA_FROM_DEVICE : DMA_TO_DEVICE;
>> +
>> +	for (offset = 0; offset < len; offset += SFC_DMA_MAX_LEN) {
>> +		size_t trans = min_t(size_t, SFC_DMA_MAX_LEN, len - offset);
>> +
>> +		dma_addr = dma_map_single(NULL, (void *)buf, trans, dma_dir);
> not good: buf may have been allocated with vmalloc() hence the pages of buf
> are not garanteed to be contiguous in physical memory.
>
> Just write a ubifs image into your QSPI memory and try to mount it. You are
> very likely to notice some issues/crashes.
>

You are right. I wasn't aware that the buf from vmalloc will pass in
here so I need to check the address and if that was coming from vmalloc,
we should use pre-allocated dma buf and do a copy here, although it's
quite low performance. :)


>
>> +
>> +		if (dma_mapping_error(sfc->dev, dma_addr)) {
>> +			/*
>> +			 * If we use pre-allocated dma_buffer, we need to
>> +			 * do a copy here.
>> +			 */
>> +			if (op_type == SFC_CMD_DIR_WR)
>> +				memcpy(sfc->buffer, buf + offset, trans);
>> +
>> +			dma_addr = 0;
>> +		}
>> +
>> +		if (op_type == SFC_CMD_DIR_WR)
>> +			/*
>> +			 * Flush the write data from write_buf to dma_addr
>> +			 * if using dynamic allocated dma buffer before dma
>> +			 * moves data from dma_addr to fifo.
>> +			 */
>> +			dma_sync_single_for_device(sfc->dev, dma_addr,
>> +						   trans, DMA_TO_DEVICE);
>> +
>> +
>> +		/* If failing to map dma, use pre-allocated area instead */
>> +		ret = rockchip_sfc_do_dma_transfer(nor, from_to + offset,
>> +						dma_addr ? dma_addr :
>> +						sfc->dma_buffer,
>> +						trans, op_type);
>> +
>> +		if (dma_addr) {
>> +			/*
>> +			 * Invalidate the read data from dma_addr if using
>> +			 * dynamic allocated dma buffer after dma moves data
>> +			 * from fifo to dma_addr.
>> +			 */
>> +			if (op_type == SFC_CMD_DIR_RD)
>> +				dma_sync_single_for_cpu(sfc->dev, dma_addr,
>> +							trans, DMA_FROM_DEVICE);
>> +
>> +			dma_unmap_single(NULL, dma_addr,
>> +					 trans, dma_dir);
>> +		}
>> +
>> +		if (ret) {
>> +			dev_warn(nor->dev, "DMA read timeout\n");
>> +			return ret;
>> +		}
>> +		/*
>> +		 * If we use pre-allocated dma_buffer for read, we need to
>> +		 * do a copy here.
>> +		 */
>> +		if (!dma_addr && (op_type == SFC_CMD_DIR_RD))
>> +			memcpy(buf + offset, sfc->buffer, trans);
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +static ssize_t rockchip_sfc_do_rd_wr(struct spi_nor *nor, loff_t from_to,
>> +				     size_t len, u_char *buf, u32 op_type)
>> +{
>> +	struct rockchip_sfc_chip_priv *priv = nor->priv;
>> +	struct rockchip_sfc *sfc = priv->sfc;
>> +	int ret;
>> +
>> +	if (likely(sfc->use_dma))
>> +		return rockchip_sfc_dma_transfer(nor, from_to, len,
>> +						 buf, op_type);
>> +
>> +	/* Fall back to PIO mode if DMA isn't present */
>> +	ret = rockchip_sfc_pio_transfer(nor, from_to, len,
>> +					(u_char *)buf, op_type);
>> +	if (ret) {
>> +		if (op_type == SFC_CMD_DIR_RD)
>> +			dev_warn(nor->dev, "PIO read timeout\n");
>> +		else
>> +			dev_warn(nor->dev, "PIO write timeout\n");
>> +		return ret;
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +static ssize_t rockchip_sfc_read(struct spi_nor *nor, loff_t from,
>> +				 size_t len, u_char *read_buf)
>> +{
>> +	return rockchip_sfc_do_rd_wr(nor, from, len,
>> +				     read_buf, SFC_CMD_DIR_RD);
>> +}
>> +
>> +static ssize_t rockchip_sfc_write(struct spi_nor *nor, loff_t to,
>> +				  size_t len, const u_char *write_buf)
>> +{
>> +	return rockchip_sfc_do_rd_wr(nor, to, len,
>> +				     (u_char *)write_buf,
>> +				     SFC_CMD_DIR_WR);
>> +}
>> +
>> +static int rockchip_sfc_register(struct device_node *np,
>> +				 struct rockchip_sfc *sfc)
>> +{
>> +	struct device *dev = sfc->dev;
>> +	struct mtd_info *mtd;
>> +	struct spi_nor *nor;
>> +	int ret;
>> +
>> +	nor = &sfc->flash[sfc->num_chip].nor;
>> +	nor->dev = dev;
>> +	spi_nor_set_flash_node(nor, np);
>> +
>> +	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;
>> +	nor->priv = &(sfc->flash[sfc->num_chip]);
>> +
>> +	nor->prepare = rockchip_sfc_prep;
>> +	nor->unprepare = rockchip_sfc_unprep;
>> +	nor->read_reg = rockchip_sfc_read_reg;
>> +	nor->write_reg = rockchip_sfc_write_reg;
>> +	nor->read = rockchip_sfc_read;
>> +	nor->write = rockchip_sfc_write;
>> +	nor->erase = NULL;
>> +	ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
>> +	if (ret)
>> +		return ret;
>> +
>> +	mtd = &(nor->mtd);
>> +	mtd->name = np->name;
>> +	ret = mtd_device_register(mtd, NULL, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	sfc->num_chip++;
>> +	return 0;
>> +}
>> +
>> +static void rockchip_sfc_unregister_all(struct rockchip_sfc *sfc)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < sfc->num_chip; i++)
>> +		mtd_device_unregister(&sfc->flash[i].nor.mtd);
>> +}
>> +
>> +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)
>> +			goto fail;
>> +
>> +		if (sfc->num_chip == SFC_MAX_CHIPSELECT_NUM) {
>> +			dev_warn(dev, "Exceeds the max cs limitation\n");
>> +			break;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +
>> +fail:
>> +	dev_err(dev, "Failed to register all chips\n");
>> +	/* Unregister all the _registered_ nor flash */
>> +	rockchip_sfc_unregister_all(sfc);
>> +	return ret;
>> +}
>> +
>> +static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct rockchip_sfc *sfc = dev_id;
>> +	u32 reg;
>> +
>> +	reg = readl_relaxed(sfc->regbase + SFC_RISR);
>> +	dev_dbg(sfc->dev, "Get irq: 0x%x\n", reg);
>> +
>> +	/* 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 resource *res;
>> +	struct rockchip_sfc *sfc;
>> +	int ret;
>> +
>> +	sfc = devm_kzalloc(dev, sizeof(*sfc), GFP_KERNEL);
>> +	if (!sfc)
>> +		return -ENOMEM;
>> +
>> +	platform_set_drvdata(pdev, sfc);
>> +	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, "hsfc");
>> +	if (IS_ERR(sfc->hclk)) {
>> +		dev_err(&pdev->dev, "Failed to get sfc ahp clk\n");
>> +		return PTR_ERR(sfc->hclk);
>> +	}
>> +
>> +	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_DMA_MAX_LEN,
>> +			&sfc->dma_buffer, GFP_KERNEL);
>> +	if (!sfc->buffer)
>> +		return -ENOMEM;
>> +
>> +	mutex_init(&sfc->lock);
>> +
>> +	ret = clk_prepare_enable(sfc->hclk);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to enable hclk\n");
>> +		goto err_hclk;
>> +	}
>> +
>> +	ret = clk_prepare_enable(sfc->clk);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to enable clk\n");
>> +		goto err_clk;
>> +	}
>> +
>> +	sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
>> +					      "rockchip,sfc-no-DMA");
>> +
>> +	sfc->negative_edge = of_device_is_compatible(sfc->dev->of_node,
>> +						     "rockchip,rk1108-sfc");
>> +	/* 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;
>> +
>> +	pm_runtime_get_noresume(&pdev->dev);
>> +	pm_runtime_set_active(&pdev->dev);
>> +	pm_runtime_enable(&pdev->dev);
>> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
>> +	pm_runtime_use_autosuspend(&pdev->dev);
>> +
>> +	ret = rockchip_sfc_register_all(sfc);
>> +	if (ret)
>> +		goto err_register;
>> +
>> +	clk_disable_unprepare(sfc->clk);
>> +	pm_runtime_put_autosuspend(&pdev->dev);
>> +	return 0;
>> +
>> +err_register:
>> +	pm_runtime_disable(&pdev->dev);
>> +	pm_runtime_set_suspended(&pdev->dev);
>> +	pm_runtime_put_noidle(&pdev->dev);
>> +err_irq:
>> +	clk_disable_unprepare(sfc->clk);
>> +err_clk:
>> +	clk_disable_unprepare(sfc->hclk);
>> +err_hclk:
>> +	mutex_destroy(&sfc->lock);
>> +	return ret;
>> +}
>> +
>> +static int rockchip_sfc_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_sfc *sfc = platform_get_drvdata(pdev);
>> +
>> +	pm_runtime_get_sync(&pdev->dev);
>> +	pm_runtime_disable(&pdev->dev);
>> +	pm_runtime_put_noidle(&pdev->dev);
>> +
>> +	rockchip_sfc_unregister_all(sfc);
>> +	mutex_destroy(&sfc->lock);
>> +	clk_disable_unprepare(sfc->clk);
>> +	clk_disable_unprepare(sfc->hclk);
>> +	return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +int rockchip_sfc_runtime_suspend(struct device *dev)
>> +{
>> +	struct rockchip_sfc *sfc = dev_get_drvdata(dev);
>> +
>> +	clk_disable_unprepare(sfc->hclk);
>> +	return 0;
>> +}
>> +
>> +int rockchip_sfc_runtime_resume(struct device *dev)
>> +{
>> +	struct rockchip_sfc *sfc = dev_get_drvdata(dev);
>> +
>> +	clk_prepare_enable(sfc->hclk);
>> +	return rockchip_sfc_reset(sfc);
>> +}
>> +#endif /* CONFIG_PM */
>> +
>> +static const struct of_device_id rockchip_sfc_dt_ids[] = {
>> +	{ .compatible = "rockchip,sfc"},
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids);
>> +
>> +static const struct dev_pm_ops rockchip_sfc_dev_pm_ops = {
>> +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>> +				pm_runtime_force_resume)
>> +	SET_RUNTIME_PM_OPS(rockchip_sfc_runtime_suspend,
>> +			   rockchip_sfc_runtime_resume, NULL)
>> +};
>> +
>> +static struct platform_driver rockchip_sfc_driver = {
>> +	.driver = {
>> +		.name	= "rockchip-sfc",
>> +		.of_match_table = rockchip_sfc_dt_ids,
>> +		.pm = &rockchip_sfc_dev_pm_ops,
>> +	},
>> +	.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-TNX95d0MmH7DzftRWevZcw@public.gmane.org>");
>>
>
>
>
>


-- 
Best Regards
Shawn Lin

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 0/8] ARM: dts: Switch to new DSA binding
From: Florian Fainelli @ 2017-01-17  1:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	vivien.didelot, Russell King, open list, Rob Herring,
	Gregory Clement, Sebastian Hesselbarth
In-Reply-To: <20170105192957.14304-1-f.fainelli@gmail.com>

On 01/05/2017 11:29 AM, Florian Fainelli wrote:
> Hi all,
> 
> This patch series converts the in-tree users to utilize the new (relatively)
> DSA binding that was introduced with commit 8c5ad1d6179d ("net: dsa: Document
> new binding"). The legacy binding node is kept included, but is marked
> disabled.
> 
> Changes in v2:
> 
> - patch 1: Use an hexadecimal reg property
> - patch 2: fixed the subject
> - patch 3: s/okay/disabled/ for the legacy DSA node
> - patches 7/8: fixed a stray whitespace
> 
> In about 2-3 releases we may consider removing the old DSA binding entirely
> from the kernel.

Gregory, are you going to take this for 4.11? Thanks

> 
> Thank you!
> 
> Florian Fainelli (8):
>   ARM: dts: armada-370-rd: Utilize new DSA binding
>   ARM: dts: armada-385-linksys: Utilize new DSA binding
>   ARM: dts: armada-388-clearfog: Utilize new DSA binding
>   ARM: dts: armada-xp-linksys-mamba: Utilize new DSA binding
>   ARM: dts: kirkwood-dir665: Utilize new DSA binding
>   ARM: dts: kirkwood-linksys-viper: Utilize new DSA binding
>   ARM: dts: kirkwood-mv88f6281gtw-ge: Utilize new DSA binding
>   ARM: dts: kirkwood-rd88f6281: Utilize new DSA binding
> 
>  arch/arm/boot/dts/armada-370-rd.dts            | 44 +++++++++++++++++
>  arch/arm/boot/dts/armada-385-linksys.dtsi      | 52 ++++++++++++++++++++-
>  arch/arm/boot/dts/armada-388-clearfog.dts      | 65 ++++++++++++++++++++++++++
>  arch/arm/boot/dts/armada-xp-linksys-mamba.dts  | 53 +++++++++++++++++++++
>  arch/arm/boot/dts/kirkwood-dir665.dts          | 49 +++++++++++++++++++
>  arch/arm/boot/dts/kirkwood-linksys-viper.dts   | 49 +++++++++++++++++++
>  arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts | 49 +++++++++++++++++++
>  arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts    | 11 +++++
>  arch/arm/boot/dts/kirkwood-rd88f6281.dtsi      | 44 +++++++++++++++++
>  9 files changed, 415 insertions(+), 1 deletion(-)
> 


-- 
Florian

^ permalink raw reply


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