Skip to contentSkip to conversation

MIPS: pistachio: Creator Ci40 aka Marduk SPI-UART

PATCH In review Andreas Färber 6 participants 30 messages Jul 22, 2018 – Jul 31, 2018

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover MIPS: pistachio: Creator Ci40 aka Marduk SPI-UART

Hello,

This patchset enables SPI and UARTs for the Ci40's mikroBUS and Raspberry Pi B+ connectors, as well as the remaining seven LEDs and as dependency the 802.15.4.

I also dug out some related driver fixes from their pistachio-4.9-lede branch:
https://github.com/CreatorDev/linux/commits/pistachio-4.9-lede

Tested with a LoRa click expansion board. [*]
Note that a number of drivers are missing in the pistachio defconfig. This should probably be remedied as follow-up.

While all creatordev.io websites appear to be gone, I still had a local copy of the Ci40 schematics document.

This patchset: https://github.com/afaerber/linux/commits/ci40-spi-uart.v1

Some more potential patches for missing features appear to be here:
https://github.com/CreatorDev/linux/commits/pistachio-4.9-wip

Have a lot of fun!

Cheers,
Andreas

P.S. As follow-up to this series I've reported on linux-serial that sc16is7xx and serdev drivers don't appear to play nicely together:
https://marc.info/?l=linux-serial&m=153228314300681&w=2

[*] Cf. netdev https://patchwork.ozlabs.org/cover/937545/

Cc Michael Turquette <[email protected]>
Cc Stephen Boyd <[email protected]>

Andreas Färber (7):
MIPS: dts: img: pistachio_marduk: Reorder nodes
MIPS: dts: img: pistachio_marduk: Cleanups
MIPS: dts: img: pistachio: Rename spim0-clk pin node label
MIPS: dts: img: pistachio_marduk: Enable SPIM0
MIPS: dts: img: pistachio_marduk: Add 6Lowpan node
MIPS: dts: img: pistachio_marduk: Add SPI UART node
MIPS: dts: img: pistachio_marduk: Add user LEDs

Damien Horsley (1):
dmaengine: img-mdc: Handle early status read

Govindraj Raja (1):
clk: pistachio: Fix wrong SDHost card speed

Ian Pozella (1):
MIPS: dts: img: pistachio_marduk: Switch mmc to 1 bit mode

Ionela Voinescu (5):
spi: img-spfi: Implement dual and quad mode
spi: img-spfi: Set device select bits for SPFI port state
spi: img-spfi: Use device 0 configuration for all devices
spi: img-spfi: RX maximum burst size for DMA is 8
spi: img-spfi: Finish every transfer cleanly

 arch/mips/boot/dts/img/pistachio.dtsi       |   2 +-
 arch/mips/boot/dts/img/pistachio_marduk.dts | 174 ++++++++++++++++++++++------
 drivers/clk/pistachio/clk-pistachio.c       |   3 +-
 drivers/dma/img-mdc-dma.c                   |  40 ++++---
 drivers/spi/spi-img-spfi.c                  | 165 +++++++++++++++++++++-----
 include/dt-bindings/clock/pistachio-clk.h   |   1 +
 6 files changed, 299 insertions(+), 86 deletions(-)
Signature · 1 line
2.16.4
#1 lore raw

PATCH 1/15 MIPS: dts: img: pistachio_marduk: Reorder nodes

Consistently order nodes referenced by label alphabetically. No functional changes. This prepares for adding nodes.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 76 ++++++++++++++---------------
 1 file changed, 38 insertions(+), 38 deletions(-)
arch/mips/boot/dts/img/pistachio_marduk.dts +38 -38
index cf9cebd52294..f03f4114e645 100644
@@ -74,40 +74,34 @@
 	};
 };
 
-&internal_dac {
-	VDD-supply = <&internal_dac_supply>;
-};
-
-&spfi1 {
+&adc {
 	status = "okay";
-
-	pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>, <&spim1_cs0_pin>,
-		    <&spim1_cs1_pin>;
-	pinctrl-names = "default";
-	cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>;
-
-	flash@0 {
-		compatible = "spansion,s25fl016k", "jedec,spi-nor";
-		reg = <0>;
-		spi-max-frequency = <50000000>;
-	};
+	vref-supply = <&reg_1v8>;
+	adc-reserved-channels = <0x10>;
 };
 
-&uart0 {
+&enet {
 	status = "okay";
-	assigned-clock-rates = <114278400>, <1843200>;
 };
 
-&uart1 {
+&i2c2 {
 	status = "okay";
+	clock-frequency = <400000>;
+
+	tpm@20 {
+		compatible = "infineon,slb9645tt";
+		reg = <0x20>;
+	};
+
 };
 
-&usb {
+&i2c3 {
 	status = "okay";
+	clock-frequency = <400000>;
 };
 
-&enet {
-	status = "okay";
+&internal_dac {
+	VDD-supply = <&internal_dac_supply>;
 };
 
 &pin_enet {
@@ -118,12 +112,6 @@
 	drive-strength = <2>;
 };
 
-&sdhost {
-	status = "okay";
-	bus-width = <4>;
-	disable-wp;
-};
-
 &pin_sdhost_cmd {
 	drive-strength = <2>;
 };
@@ -140,24 +128,36 @@
 	pinctrl-names = "default";
 };
 
-&adc {
+&sdhost {
 	status = "okay";
-	vref-supply = <&reg_1v8>;
-	adc-reserved-channels = <0x10>;
+	bus-width = <4>;
+	disable-wp;
 };
 
-&i2c2 {
+&spfi1 {
 	status = "okay";
-	clock-frequency = <400000>;
 
-	tpm@20 {
-		compatible = "infineon,slb9645tt";
-		reg = <0x20>;
+	pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>, <&spim1_cs0_pin>,
+		    <&spim1_cs1_pin>;
+	pinctrl-names = "default";
+	cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>;
+
+	flash@0 {
+		compatible = "spansion,s25fl016k", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
 	};
+};
 
+&uart0 {
+	status = "okay";
+	assigned-clock-rates = <114278400>, <1843200>;
 };
 
-&i2c3 {
+&uart1 {
+	status = "okay";
+};
+
+&usb {
 	status = "okay";
-	clock-frequency = <400000>;
 };
Signature · 1 line
2.16.4
#2 lore raw

PATCH 2/15 MIPS: dts: img: pistachio_marduk: Cleanups

In reply to Andreas Färber

Add and remove some white lines for consistency.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
arch/mips/boot/dts/img/pistachio_marduk.dts +3 -1
index f03f4114e645..29358d1f7027 100644
@@ -51,6 +51,7 @@
 
 	leds {
 		compatible = "pwm-leds";
+
 		heartbeat {
 			label = "marduk:red:heartbeat";
 			pwms = <&pwm 3 300000>;
@@ -61,11 +62,13 @@
 
 	keys {
 		compatible = "gpio-keys";
+
 		button@1 {
 			label = "Button 1";
 			linux,code = <0x101>; /* BTN_1 */
 			gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
 		};
+
 		button@2 {
 			label = "Button 2";
 			linux,code = <0x102>; /* BTN_2 */
@@ -92,7 +95,6 @@
 		compatible = "infineon,slb9645tt";
 		reg = <0x20>;
 	};
-
 };
 
 &i2c3 {
Signature · 1 line
2.16.4
#3 lore raw

PATCH 3/15 MIPS: dts: img: pistachio: Rename spim0-clk pin node label

In reply to Andreas Färber

Renaming will allow consistent ordering when referenced.

---
 arch/mips/boot/dts/img/pistachio.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/boot/dts/img/pistachio.dtsi +1 -1
index f8d7e6f622cb..1adef5bc740d 100644
@@ -406,7 +406,7 @@
 				function = "spim0";
 				drive-strength = <4>;
 			};
-			spim0_clk: spim0-clk {
+			pin_spim0_clk: spim0-clk {
 				pins = "mfio8";
 				function = "spim0";
 				drive-strength = <4>;
Signature · 1 line
2.16.4
#4 lore raw

PATCH 4/15 MIPS: dts: img: pistachio_marduk: Switch mmc to 1 bit mode

In reply to Andreas Färber

From: Ian Pozella <[email protected]>

The mmc block in Pistachio allows 1 to 8 data bits to be used. Marduk uses 4 bits allowing the upper 4 bits to be allocated to the Mikrobus ports. However these bits are still connected internally meaning the mmc block recieves signals on all data lines and seems the internal HW CRC checks get corrupted by this erroneous data.

We cannot control what data is sent on these lines because they go to external ports. 1 bit mode does not exhibit the issue hence the safe default is to use this. If a user knows that in their use case they will not use the upper bits then they can set to 4 bit mode in order to improve performance.

Also make sure that the upper 4 bits don't get allocated to the mmc driver (the default is to assign all 8 pins) so they can be allocated to other drivers. Allocating all 4 despite setting 1 bit mode as this matches what is there in hardware.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/mips/boot/dts/img/pistachio_marduk.dts +2 -1
index 29358d1f7027..5557a6ad61c3 100644
@@ -120,6 +120,7 @@
 
 &pin_sdhost_data {
 	drive-strength = <2>;
+	pins = "mfio17", "mfio18", "mfio19", "mfio20";
 };
 
 &pwm {
@@ -132,7 +133,7 @@
 
 &sdhost {
 	status = "okay";
-	bus-width = <4>;
+	bus-width = <1>;
 	disable-wp;
 };
 
Signature · 1 line
2.16.4
#5 lore raw

Re: [PATCH 04/15] MIPS: dts: img: pistachio_marduk: Switch mmc to 1 bit mode

Am 22.07.2018 um 23:19 schrieb Andreas Färber:

Quoted 6 lines

From: Ian Pozella <[email protected]>

The mmc block in Pistachio allows 1 to 8 data bits to be used. Marduk uses 4 bits allowing the upper 4 bits to be allocated to the Mikrobus ports. However these bits are still connected internally meaning the mmc block recieves signals on all data lines

"receives"

I had fixed a number of typos from the downstream patches already, but this one slipped through.

Regards,
Andreas

Quoted 16 lines

and seems the internal HW CRC checks get corrupted by this erroneous data.

We cannot control what data is sent on these lines because they go to external ports. 1 bit mode does not exhibit the issue hence the safe default is to use this. If a user knows that in their use case they will not use the upper bits then they can set to 4 bit mode in order to improve performance.

Also make sure that the upper 4 bits don't get allocated to the mmc driver (the default is to assign all 8 pins) so they can be allocated to other drivers. Allocating all 4 despite setting 1 bit mode as this matches what is there in hardware.

[snip]

Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
#6 lore raw

PATCH 5/15 MIPS: dts: img: pistachio_marduk: Enable SPIM0

In reply to Andreas Färber

SPIM0 supplies SPI pins on the mikroBUS and Raspberry Pi B+ connectors.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
arch/mips/boot/dts/img/pistachio_marduk.dts +23 -0
index 5557a6ad61c3..d723b68084c9 100644
@@ -123,6 +123,14 @@
 	pins = "mfio17", "mfio18", "mfio19", "mfio20";
 };
 
+&pin_spim0 {
+	drive-strength = <2>;
+};
+
+&pin_spim0_clk {
+	drive-strength = <2>;
+};
+
 &pwm {
 	status = "okay";
 
@@ -137,6 +145,21 @@
 	disable-wp;
 };
 
+&spfi0 {
+	status = "okay";
+
+	pinctrl-0 = <&spim0_pins>,
+		    <&spim0_cs0_alt_pin>,
+		    <&spim0_cs2_alt_pin>,
+		    <&spim0_cs3_alt_pin>,
+		    <&spim0_cs4_alt_pin>;
+	pinctrl-names = "default";
+	cs-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>, <0>,
+		   <&gpio1 12 GPIO_ACTIVE_HIGH>,
+		   <&gpio1 13 GPIO_ACTIVE_HIGH>,
+		   <&gpio1 14 GPIO_ACTIVE_HIGH>;
+};
+
 &spfi1 {
 	status = "okay";
 
Signature · 1 line
2.16.4
#7 lore raw

PATCH 6/15 MIPS: dts: img: pistachio_marduk: Add 6Lowpan node

In reply to Andreas Färber

The CA8210's clock output is needed for the SPI-UART bridge.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
arch/mips/boot/dts/img/pistachio_marduk.dts +14 -0
index d723b68084c9..b0b6b534a41f 100644
@@ -158,6 +158,20 @@
 		   <&gpio1 12 GPIO_ACTIVE_HIGH>,
 		   <&gpio1 13 GPIO_ACTIVE_HIGH>,
 		   <&gpio1 14 GPIO_ACTIVE_HIGH>;
+
+	ca8210: sixlowpan@4 {
+		compatible = "cascoda,ca8210";
+		reg = <4>;
+		spi-max-frequency = <3000000>;
+		spi-cpol;
+		reset-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+		irq-gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+
+		extclock-enable;
+		extclock-freq = <16000000>;
+		extclock-gpio = <2>; /* spiuart_clk */
+		#clock-cells = <0>;
+	};
 };
 
 &spfi1 {
Signature · 1 line
2.16.4
#8 lore raw

Re: [PATCH 06/15] MIPS: dts: img: pistachio_marduk: Add 6Lowpan node

Hi Andreas,

Quoted 12 lines · Andreas Färber
arch/mips/boot/dts/img/pistachio_marduk.dts +4 -0
index d723b68084c9..b0b6b534a41f 100644
@@ -158,6 +158,20 @@
 		   <&gpio1 12 GPIO_ACTIVE_HIGH>,
 		   <&gpio1 13 GPIO_ACTIVE_HIGH>,
 		   <&gpio1 14 GPIO_ACTIVE_HIGH>;
+
+	ca8210: sixlowpan@4 {
+		compatible = "cascoda,ca8210";
+		reg = <4>;

arch/mips/boot/dts/img/pistachio_marduk.dts line 174

Quoted 10 lines
arch/mips/boot/dts/img/pistachio_marduk.dts +10 -0
+		spi-max-frequency = <3000000>;
+		spi-cpol;
+		reset-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+		irq-gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+
+		extclock-enable;
+		extclock-freq = <16000000>;
+		extclock-gpio = <2>; /* spiuart_clk */
+		#clock-cells = <0>;
+	};

dtc complains about the extclock-gpio property because it expects a property named *-gpio to contain a gpio-list:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])

Rob, perhaps this should be added as a second false-positive case in dtc's prop_is_gpio()?

Thanks,
Paul

#9 lore raw

PATCH 1/1 checks: Detect cascoda,ca8210 extclock-gpio false-positive

The binding for the cascoda,ca8210 IEEE 802.15.4 (6LoWPAN) device includes an extclock-gpio property which does not contain a gpio-list, but is instead an integer representing a pin of the device itself. This falls foul of the gpios_property check, for example:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])

Extend the checking for false-positives in prop_is_gpio() to detect this case in addition to the existing nr-gpio case. The false-positive cases are described by an array including a compatible string & property name. A NULL compatible string indicates that the property may be present in any node, otherwise the property is only allowed in a node compatible with the given string. This allows us to whitelist the extclock-gpio property for the cascoda,ca8210 device without allowing it anywhere else.

Since checks for false-positives now have a little higher cost, they are moved to after the detection of the gpio(s) substring, which the vast majority of property names will fail avoiding needless checks against the false_positives array.

Cc David Gibson <[email protected]>
Cc Jon Loeliger <[email protected]>
Cc Rob Herring <[email protected]>
Cc Andreas Färber <[email protected]>
---
 checks.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)
checks.c +26 -10
index a2cc103..c76e312 100644
@@ -1254,16 +1254,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells");
 WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells");
 WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells");
 
-static bool prop_is_gpio(struct property *prop)
+static bool prop_is_gpio(struct node *node, struct property *prop)
 {
+	const struct {
+		char *compat;
+		char *prop;
+	} false_positives[] = {
+		{ NULL, "nr-gpio" },
+		{ "cascoda,ca8210", "extclock-gpio" },
+	};
 	char *str;
-
-	/*
-	 * *-gpios and *-gpio can appear in property names,
-	 * so skip over any false matches (only one known ATM)
-	 */
-	if (strstr(prop->name, "nr-gpio"))
-		return false;
+	int i;
 
 	str = strrchr(prop->name, '-');
 	if (str)
@@ -1273,6 +1274,21 @@ static bool prop_is_gpio(struct property *prop)
 	if (!(streq(str, "gpios") || streq(str, "gpio")))
 		return false;
 
+	/*
+	 * *-gpios and *-gpio can appear in property names,
+	 * so skip over any false matches.
+	 */
+	for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
+		if (strstr(prop->name, false_positives[i].prop))
+			return false;
+
+		if (!false_positives[i].compat)
+			return false;
+
+		if (node_is_compatible(node, false_positives[i].compat))
+			return false;
+	}
+
 	return true;
 }
 
@@ -1289,7 +1305,7 @@ static void check_gpios_property(struct check *c,
 	for_each_property(node, prop) {
 		struct provider provider;
 
-		if (!prop_is_gpio(prop))
+		if (!prop_is_gpio(node, prop))
 			continue;
 
 		provider.prop_name = prop->name;
@@ -1310,7 +1326,7 @@ static void check_deprecated_gpio_property(struct check *c,
 	for_each_property(node, prop) {
 		char *str;
 
-		if (!prop_is_gpio(prop))
+		if (!prop_is_gpio(node, prop))
 			continue;
 
 		str = strstr(prop->name, "gpio");
Signature · 1 line
2.18.0
#10 lore raw

Re: [PATCH] checks: Detect cascoda,ca8210 extclock-gpio false-positive

Hi all,

checks.c static bool prop_is_gpio(struct property *prop) · line 1283

Quoted 11 lines · Paul Burton
checks.c +7 -0
@@ -1273,6 +1274,21 @@ static bool prop_is_gpio(struct property *prop)
 	if (!(streq(str, "gpios") || streq(str, "gpio")))
 		return false;
 
+	/*
+	 * *-gpios and *-gpio can appear in property names,
+	 * so skip over any false matches.
+	 */
+	for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
+		if (strstr(prop->name, false_positives[i].prop))
+			return false;

Of course as soon as I hit send I noticed this is strstr(), not strcmp(), and this probably doesn't make much sense... Please ignore.

Thanks,
Paul

maintainer
#11 lore raw

Re: [PATCH] checks: Detect cascoda,ca8210 extclock-gpio false-positive

In reply to Paul Burton
Quoted 11 lines · Paul Burton

The binding for the cascoda,ca8210 IEEE 802.15.4 (6LoWPAN) device includes an extclock-gpio property which does not contain a gpio-list, but is instead an integer representing a pin of the device itself. This falls foul of the gpios_property check, for example:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])
Quoted 8 lines

Extend the checking for false-positives in prop_is_gpio() to detect this case in addition to the existing nr-gpio case. The false-positive cases are described by an array including a compatible string & property name. A NULL compatible string indicates that the property may be present in any node, otherwise the property is only allowed in a node compatible with the given string. This allows us to whitelist the extclock-gpio property for the cascoda,ca8210 device without allowing it anywhere else.

IMO the binding should be fixed. It wasn't reviewed and there are no dts files using it. I see several issues with it.

Rob

#12 lore raw

Re: [PATCH] checks: Detect cascoda,ca8210 extclock-gpio false-positive

Hi Rob,

Quoted 21 lines · Rob Herring
Quoted 11 lines · Paul Burton

The binding for the cascoda,ca8210 IEEE 802.15.4 (6LoWPAN) device includes an extclock-gpio property which does not contain a gpio-list, but is instead an integer representing a pin of the device itself. This falls foul of the gpios_property check, for example:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])
Quoted 8 lines

Extend the checking for false-positives in prop_is_gpio() to detect this case in addition to the existing nr-gpio case. The false-positive cases are described by an array including a compatible string & property name. A NULL compatible string indicates that the property may be present in any node, otherwise the property is only allowed in a node compatible with the given string. This allows us to whitelist the extclock-gpio property for the cascoda,ca8210 device without allowing it anywhere else.

Quoted 2 lines

IMO the binding should be fixed. It wasn't reviewed and there are no dts files using it. I see several issues with it.

Okie dokie - I'll drop Andreas' series that makes use of it[1] until this is addressed.

I know there are no .dts files in-tree that use it, but figured that doesn't necessarily mean there are no users. Copying Harry who wrote the binding doc, Stefan who acked it & Marcel who committed it in case they have more information.

Thanks,
Paul

[1] https://patchwork.linux-mips.org/project/linux-mips/list/?series=1286&state=%2A&archive=both

#13 lore raw

Re: [PATCH] checks: Detect cascoda,ca8210 extclock-gpio false-positive

Hi Rob and Paul,

Am 24.07.2018 um 22:17 schrieb Paul Burton:

Quoted 22 lines · Rob Herring
Quoted 21 lines · Paul Burton
Quoted 19 lines

The binding for the cascoda,ca8210 IEEE 802.15.4 (6LoWPAN) device includes an extclock-gpio property which does not contain a gpio-list, but is instead an integer representing a pin of the device itself. This falls foul of the gpios_property check, for example:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])

Extend the checking for false-positives in prop_is_gpio() to detect this case in addition to the existing nr-gpio case. The false-positive cases are described by an array including a compatible string & property name. A NULL compatible string indicates that the property may be present in any node, otherwise the property is only allowed in a node compatible with the given string. This allows us to whitelist the extclock-gpio property for the cascoda,ca8210 device without allowing it anywhere else.

Quoted 2 lines
Quoted 2 lines

IMO the binding should be fixed. It wasn't reviewed and there are no dts files using it. I see several issues with it.

It looked strange to me, too, so revising it will be appreciated. Will you be driving this, Rob? Thanks.

BTW not a single binding in net/ieee802154/ has Rob's Reviewed-by or Acked-by, not just this binding.

Quoted 2 lines

Okie dokie - I'll drop Andreas' series that makes use of it[1] until this is addressed.

Please continue reviewing the remainder of that series - the patches before could easily be applied for anyone wanting to work on this board. And the patches after that are not about DT are independent, too. Only patches 6-8 are affected.

Who knows how long fixing the binding will take...

Thanks,
Andreas

Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
maintainer
#14 lore raw

Re: [PATCH] checks: Detect cascoda,ca8210 extclock-gpio false-positive

Quoted 26 lines · Andreas Färber

Hi Rob and Paul,

Am 24.07.2018 um 22:17 schrieb Paul Burton:

Quoted 22 lines · Rob Herring
Quoted 21 lines · Paul Burton
Quoted 19 lines

The binding for the cascoda,ca8210 IEEE 802.15.4 (6LoWPAN) device includes an extclock-gpio property which does not contain a gpio-list, but is instead an integer representing a pin of the device itself. This falls foul of the gpios_property check, for example:

DTC arch/mips/boot/dts/img/pistachio_marduk.dtb
arch/mips/boot/dts/img/pistachio_marduk.dtb: Warning (gpios_property):

    /spi@18100f00/sixlowpan@4: Missing property '#gpio-cells' in node
    /clk@18144000 or bad phandle (referred from extclock-gpio[0])

Extend the checking for false-positives in prop_is_gpio() to detect this case in addition to the existing nr-gpio case. The false-positive cases are described by an array including a compatible string & property name. A NULL compatible string indicates that the property may be present in any node, otherwise the property is only allowed in a node compatible with the given string. This allows us to whitelist the extclock-gpio property for the cascoda,ca8210 device without allowing it anywhere else.

Quoted 5 lines
Quoted 2 lines
Quoted 2 lines

IMO the binding should be fixed. It wasn't reviewed and there are no dts files using it. I see several issues with it.

It looked strange to me, too, so revising it will be appreciated. Will you be driving this, Rob? Thanks.

Well, I'll happily list what should be fixed:

- s/reset-gpio/reset-gpios/
- Use 'interrupts' instead of irq-gpio
- Use clock binding instead of extclock-freq
- s/extclock-gpio/cascoda,extclock-gpio-pin/
- Seems like extclock-gpio being present can imply extclock-enable

Quoted 2 lines

BTW not a single binding in net/ieee802154/ has Rob's Reviewed-by or Acked-by, not just this binding.

get_maintainers.pl is not perfect, but still...

Rob

#15 lore raw

PATCH 7/15 MIPS: dts: img: pistachio_marduk: Add SPI UART node

In reply to Andreas Färber

The mikroBUS and Raspberry Pi B+ connector UARTs are behind an SC16IS752 SPI-UART bridge. Add it in order to be able to use these connectors.

Note: For UART flow control two pairs of jumpers need to be configured.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
arch/mips/boot/dts/img/pistachio_marduk.dts +12 -0
index b0b6b534a41f..f682d0a5a3d9 100644
@@ -159,6 +159,18 @@
 		   <&gpio1 13 GPIO_ACTIVE_HIGH>,
 		   <&gpio1 14 GPIO_ACTIVE_HIGH>;
 
+	sc16is752: uart@0 {
+		compatible = "nxp,sc16is752";
+		reg = <0>;
+		spi-max-frequency = <4000000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		clocks = <&ca8210>;
+
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
 	ca8210: sixlowpan@4 {
 		compatible = "cascoda,ca8210";
 		reg = <4>;
Signature · 1 line
2.16.4
#16 lore raw

PATCH 8/15 MIPS: dts: img: pistachio_marduk: Add user LEDs

In reply to Andreas Färber

Add the LEDs that are connected to the SPI UART bridge.

---
 arch/mips/boot/dts/img/pistachio_marduk.dts | 46 +++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
arch/mips/boot/dts/img/pistachio_marduk.dts +46 -0
index f682d0a5a3d9..6984933b3cdc 100644
@@ -60,6 +60,52 @@
 		};
 	};
 
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led0 {
+			label = "marduk:red:user0";
+			gpios = <&sc16is752 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led1 {
+			label = "marduk:red:user1";
+			gpios = <&sc16is752 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led2 {
+			label = "marduk:red:user2";
+			gpios = <&sc16is752 2 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led3 {
+			label = "marduk:red:user3";
+			gpios = <&sc16is752 3 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led4 {
+			label = "marduk:red:user4";
+			gpios = <&sc16is752 4 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led5 {
+			label = "marduk:red:user5";
+			gpios = <&sc16is752 5 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led6 {
+			label = "marduk:red:user6";
+			gpios = <&sc16is752 6 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
 	keys {
 		compatible = "gpio-keys";
 
Signature · 1 line
2.16.4
#17 lore raw

PATCH 9/15 dmaengine: img-mdc: Handle early status read

In reply to Andreas Färber

From: Damien Horsley <[email protected]>

It is possible that mdc_tx_status may be called before the first node has been read from memory.

In this case, the residue value stored in the register is undefined. Return the transfer size instead.

---
 drivers/dma/img-mdc-dma.c | 40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)
drivers/dma/img-mdc-dma.c +24 -16
index 25cec9c243e1..0f2f0f52d83a 100644
@@ -621,25 +621,33 @@ static enum dma_status mdc_tx_status(struct dma_chan *chan,
 			(MDC_CMDS_PROCESSED_CMDS_DONE_MASK + 1);
 
 		/*
-		 * If the command loaded event hasn't been processed yet, then
-		 * the difference above includes an extra command.
+		 * If the first node has not yet been read from memory,
+		 * the residue register value is undefined
 		 */
-		if (!mdesc->cmd_loaded)
-			cmds--;
-		else
-			cmds += mdesc->list_cmds_done;
-
-		bytes = mdesc->list_xfer_size;
-		ldesc = mdesc->list;
-		for (i = 0; i < cmds; i++) {
-			bytes -= ldesc->xfer_size + 1;
-			ldesc = ldesc->next_desc;
-		}
-		if (ldesc) {
-			if (residue != MDC_TRANSFER_SIZE_MASK)
-				bytes -= ldesc->xfer_size - residue;
+		if (!mdesc->cmd_loaded && !cmds) {
+			bytes = mdesc->list_xfer_size;
+		} else {
+			/*
+			 * If the command loaded event hasn't been processed yet, then
+			 * the difference above includes an extra command.
+			 */
+			if (!mdesc->cmd_loaded)
+				cmds--;
 			else
+				cmds += mdesc->list_cmds_done;
+
+			bytes = mdesc->list_xfer_size;
+			ldesc = mdesc->list;
+			for (i = 0; i < cmds; i++) {
 				bytes -= ldesc->xfer_size + 1;
+				ldesc = ldesc->next_desc;
+			}
+			if (ldesc) {
+				if (residue != MDC_TRANSFER_SIZE_MASK)
+					bytes -= ldesc->xfer_size - residue;
+				else
+					bytes -= ldesc->xfer_size + 1;
+			}
 		}
 	}
 	spin_unlock_irqrestore(&mchan->vc.lock, flags);
#18 lore raw

Re: [PATCH 09/15] dmaengine: img-mdc: Handle early status read

Quoted 19 lines · Andreas Färber

From: Damien Horsley <[email protected]>

It is possible that mdc_tx_status may be called before the first node has been read from memory.

In this case, the residue value stored in the register is undefined. Return the transfer size instead.

---
 drivers/dma/img-mdc-dma.c | 40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)
drivers/dma/img-mdc-dma.c +0 -0
index 25cec9c243e1..0f2f0f52d83a 100644

drivers/dma/img-mdc-dma.c static enum dma_status mdc_tx_status(struct dma_chan *chan, · line 625

Quoted 7 lines
drivers/dma/img-mdc-dma.c +2 -2
@@ -621,25 +621,33 @@ static enum dma_status mdc_tx_status(struct dma_chan *chan,
 			(MDC_CMDS_PROCESSED_CMDS_DONE_MASK + 1);
 
 		/*
-		 * If the command loaded event hasn't been processed yet, then
-		 * the difference above includes an extra command.
+		 * If the first node has not yet been read from memory,
+		 * the residue register value is undefined

so is this the case when transfer is not started ?

Quoted 44 lines
drivers/dma/img-mdc-dma.c +22 -14
 		 */
-		if (!mdesc->cmd_loaded)
-			cmds--;
-		else
-			cmds += mdesc->list_cmds_done;
-
-		bytes = mdesc->list_xfer_size;
-		ldesc = mdesc->list;
-		for (i = 0; i < cmds; i++) {
-			bytes -= ldesc->xfer_size + 1;
-			ldesc = ldesc->next_desc;
-		}
-		if (ldesc) {
-			if (residue != MDC_TRANSFER_SIZE_MASK)
-				bytes -= ldesc->xfer_size - residue;
+		if (!mdesc->cmd_loaded && !cmds) {
+			bytes = mdesc->list_xfer_size;
+		} else {
+			/*
+			 * If the command loaded event hasn't been processed yet, then
+			 * the difference above includes an extra command.
+			 */
+			if (!mdesc->cmd_loaded)
+				cmds--;
 			else
+				cmds += mdesc->list_cmds_done;
+
+			bytes = mdesc->list_xfer_size;
+			ldesc = mdesc->list;
+			for (i = 0; i < cmds; i++) {
 				bytes -= ldesc->xfer_size + 1;
+				ldesc = ldesc->next_desc;
+			}
+			if (ldesc) {
+				if (residue != MDC_TRANSFER_SIZE_MASK)
+					bytes -= ldesc->xfer_size - residue;
+				else
+					bytes -= ldesc->xfer_size + 1;
+			}
 		}
 	}
 	spin_unlock_irqrestore(&mchan->vc.lock, flags);
Signature · 1 line
2.16.4
#19 lore raw

PATCH 10/15 spi: img-spfi: Implement dual and quad mode

In reply to Andreas Färber

From: Ionela Voinescu <[email protected]>

For dual and quad modes to work, the SPFI controller needs to have information about command/address/dummy bytes in the transaction register. This information is not relevant for single mode, and therefore it can have any value in the allowed range. Therefore, for any read or write transfers of less than 8 bytes (cmd = 1 byte, addr up to 7 bytes), SPFI will be configured, but not enabled (unless it is the last transfer in the queue). The transfer will be enabled by the subsequent transfer. A pending transfer is determined by the content of the transaction
register: if command part is set and tsize is not.

This way we ensure that for dual and quad transactions the command request size will appear in the command/address part of the transaction register, while the data size will be in tsize, all data being sent/received in the same transaction (as set up in the transaction register).

---
 drivers/spi/spi-img-spfi.c | 96 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 85 insertions(+), 11 deletions(-)
drivers/spi/spi-img-spfi.c +85 -11
index 7a37090dabbe..c845a505bae6 100644
@@ -40,7 +40,8 @@
 #define SPFI_CONTROL_SOFT_RESET			BIT(11)
 #define SPFI_CONTROL_SEND_DMA			BIT(10)
 #define SPFI_CONTROL_GET_DMA			BIT(9)
-#define SPFI_CONTROL_SE			BIT(8)
+#define SPFI_CONTROL_SE				BIT(8)
+#define SPFI_CONTROL_TX_RX			BIT(1)
 #define SPFI_CONTROL_TMODE_SHIFT		5
 #define SPFI_CONTROL_TMODE_MASK			0x7
 #define SPFI_CONTROL_TMODE_SINGLE		0
@@ -51,6 +52,10 @@
 #define SPFI_TRANSACTION			0x18
 #define SPFI_TRANSACTION_TSIZE_SHIFT		16
 #define SPFI_TRANSACTION_TSIZE_MASK		0xffff
+#define SPFI_TRANSACTION_CMD_SHIFT		13
+#define SPFI_TRANSACTION_CMD_MASK		0x7
+#define SPFI_TRANSACTION_ADDR_SHIFT		10
+#define SPFI_TRANSACTION_ADDR_MASK		0x7
 
 #define SPFI_PORT_STATE				0x1c
 #define SPFI_PORT_STATE_DEV_SEL_SHIFT		20
@@ -87,6 +92,7 @@
  */
 #define SPFI_32BIT_FIFO_SIZE			64
 #define SPFI_8BIT_FIFO_SIZE			16
+#define SPFI_DATA_REQUEST_MAX_SIZE		8
 
 struct img_spfi {
 	struct device *dev;
@@ -103,6 +109,8 @@ struct img_spfi {
 	struct dma_chan *tx_ch;
 	bool tx_dma_busy;
 	bool rx_dma_busy;
+
+	bool complete;
 };
 
 struct img_spfi_device_data {
@@ -123,9 +131,11 @@ static inline void spfi_start(struct img_spfi *spfi)
 {
 	u32 val;
 
-	val = spfi_readl(spfi, SPFI_CONTROL);
-	val |= SPFI_CONTROL_SPFI_EN;
-	spfi_writel(spfi, val, SPFI_CONTROL);
+	if (spfi->complete) {
+		val = spfi_readl(spfi, SPFI_CONTROL);
+		val |= SPFI_CONTROL_SPFI_EN;
+		spfi_writel(spfi, val, SPFI_CONTROL);
+	}
 }
 
 static inline void spfi_reset(struct img_spfi *spfi)
@@ -138,12 +148,21 @@ static int spfi_wait_all_done(struct img_spfi *spfi)
 {
 	unsigned long timeout = jiffies + msecs_to_jiffies(50);
 
+	if (!(spfi->complete))
+		return 0;
+
 	while (time_before(jiffies, timeout)) {
 		u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
 
 		if (status & SPFI_INTERRUPT_ALLDONETRIG) {
 			spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
 				    SPFI_INTERRUPT_CLEAR);
+			/*
+			 * Disable SPFI for it not to interfere with
+			 * pending transactions
+			 */
+			spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL)
+			& ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL);
 			return 0;
 		}
 		cpu_relax();
@@ -494,9 +513,32 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
 			    struct spi_transfer *xfer)
 {
 	struct img_spfi *spfi = spi_master_get_devdata(spi->master);
-	u32 val, div;
+	u32 val, div, transact;
+	bool is_pending;
 
 	/*
+	 * For read or write transfers of less than 8 bytes (cmd = 1 byte,
+	 * addr up to 7 bytes), SPFI will be configured, but not enabled
+	 * (unless it is the last transfer in the queue).The transfer will
+	 * be enabled by the subsequent transfer.
+	 * A pending transfer is determined by the content of the
+	 * transaction register: if command part is set and tsize
+	 * is not
+	 */
+	transact = spfi_readl(spfi, SPFI_TRANSACTION);
+	is_pending = ((transact >> SPFI_TRANSACTION_CMD_SHIFT) &
+			SPFI_TRANSACTION_CMD_MASK) &&
+			(!((transact >> SPFI_TRANSACTION_TSIZE_SHIFT) &
+			SPFI_TRANSACTION_TSIZE_MASK));
+
+	/* If there are no pending transactions it's OK to soft reset */
+	if (!is_pending) {
+		/* Start the transaction from a known (reset) state */
+		spfi_reset(spfi);
+	}
+
+	/*
+	 * Before anything else, set up parameters.
 	 * output = spfi_clk * (BITCLK / 512), where BITCLK must be a
 	 * power of 2 up to 128
 	 */
@@ -509,20 +551,52 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
 	val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
 	spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
 
-	spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
-		    SPFI_TRANSACTION);
+	if (!list_is_last(&xfer->transfer_list, &master->cur_msg->transfers) &&
+		/*
+		 * For duplex mode (both the tx and rx buffers are !NULL) the
+		 * CMD, ADDR, and DUMMY byte parts of the transaction register
+		 * should always be 0 and therefore the pending transfer
+		 * technique cannot be used.
+		 */
+		(xfer->tx_buf) && (!xfer->rx_buf) &&
+		(xfer->len <= SPFI_DATA_REQUEST_MAX_SIZE) && !is_pending) {
+		transact = (1 & SPFI_TRANSACTION_CMD_MASK) <<
+			SPFI_TRANSACTION_CMD_SHIFT;
+		transact |= ((xfer->len - 1) & SPFI_TRANSACTION_ADDR_MASK) <<
+			SPFI_TRANSACTION_ADDR_SHIFT;
+		spfi->complete = false;
+	} else {
+		spfi->complete = true;
+		if (is_pending) {
+			/* Keep setup from pending transfer */
+			transact |= ((xfer->len & SPFI_TRANSACTION_TSIZE_MASK) <<
+				SPFI_TRANSACTION_TSIZE_SHIFT);
+		} else {
+			transact = ((xfer->len & SPFI_TRANSACTION_TSIZE_MASK) <<
+				SPFI_TRANSACTION_TSIZE_SHIFT);
+		}
+	}
+	spfi_writel(spfi, transact, SPFI_TRANSACTION);
 
 	val = spfi_readl(spfi, SPFI_CONTROL);
 	val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
-	if (xfer->tx_buf)
+	/*
+	 * We set up send DMA for pending transfers also, as
+	 * those are always send transfers
+	 */
+	if ((xfer->tx_buf) || is_pending)
 		val |= SPFI_CONTROL_SEND_DMA;
-	if (xfer->rx_buf)
+	if (xfer->tx_buf)
+		val |= SPFI_CONTROL_TX_RX;
+	if (xfer->rx_buf) {
 		val |= SPFI_CONTROL_GET_DMA;
+		val &= ~SPFI_CONTROL_TX_RX;
+	}
 	val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT);
-	if (xfer->tx_nbits == SPI_NBITS_DUAL &&
+	if (xfer->tx_nbits == SPI_NBITS_DUAL ||
 	    xfer->rx_nbits == SPI_NBITS_DUAL)
 		val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT;
-	else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
+	else if (xfer->tx_nbits == SPI_NBITS_QUAD ||
 		 xfer->rx_nbits == SPI_NBITS_QUAD)
 		val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
 	val |= SPFI_CONTROL_SE;
Signature · 1 line
2.16.4
maintainer
#20 lore raw

Re: [PATCH 10/15] spi: img-spfi: Implement dual and quad mode

drivers/spi/spi-img-spfi.c line 44

Quoted 4 lines · Andreas Färber

#define SPFI_CONTROL_GET_DMA BIT(9)

drivers/spi/spi-img-spfi.c +2 -1
-#define SPFI_CONTROL_SE			BIT(8)
+#define SPFI_CONTROL_SE				BIT(8)
+#define SPFI_CONTROL_TX_RX			BIT(1)

Random reindent of _SE there?

drivers/spi/spi-img-spfi.c static int spfi_wait_all_done(struct img_spfi *spfi) · line 166

Quoted 7 lines
drivers/spi/spi-img-spfi.c +6 -0
+			/*
+			 * Disable SPFI for it not to interfere with
+			 * pending transactions
+			 */
+			spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL)
+			& ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL);
 			return 0;

The indentation on the second line of the write is very confusing, it should be indented relative to the first line.

drivers/spi/spi-img-spfi.c static void img_spfi_config(struct spi_master *master, struct spi_device *spi, · line 563

Quoted 10 lines
drivers/spi/spi-img-spfi.c +10 -0
+	if (!list_is_last(&xfer->transfer_list, &master->cur_msg->transfers) &&
+		/*
+		 * For duplex mode (both the tx and rx buffers are !NULL) the
+		 * CMD, ADDR, and DUMMY byte parts of the transaction register
+		 * should always be 0 and therefore the pending transfer
+		 * technique cannot be used.
+		 */
+		(xfer->tx_buf) && (!xfer->rx_buf) &&
+		(xfer->len <= SPFI_DATA_REQUEST_MAX_SIZE) && !is_pending) {
+		transact = (1 & SPFI_TRANSACTION_CMD_MASK) <<

This is again *really* hard to read - having the comment in the middle of the condidional for the if statement, then indenting the code within the if statement to the same depth is just super confusing.

#21 lore raw

PATCH 11/15 spi: img-spfi: Set device select bits for SPFI port state

In reply to Andreas Färber

From: Ionela Voinescu <[email protected]>

Even if the chip select line is not controlled by the SPFI hardware, the device select bits need to be set to specify the chip select line in use for the hardware to know what parameters to use for the current transfer.

---
 drivers/spi/spi-img-spfi.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/spi/spi-img-spfi.c +3 -0
index c845a505bae6..0d73d31a6a2b 100644
@@ -438,6 +438,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
 	u32 val;
 
 	val = spfi_readl(spfi, SPFI_PORT_STATE);
+	val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK <<
+		 SPFI_PORT_STATE_DEV_SEL_SHIFT);
+	val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
 	if (msg->spi->mode & SPI_CPHA)
 		val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
 	else
Signature · 1 line
2.16.4
#22 lore raw

PATCH 12/15 spi: img-spfi: Use device 0 configuration for all devices

In reply to Andreas Färber

From: Ionela Voinescu <[email protected]>

Given that we control the chip select line externally, we can use only one parameter register (device 0 parameter register) and one set of configuration bits (port configuration bits for device 0) for all devices (all chip select lines).

---
 drivers/spi/spi-img-spfi.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)
drivers/spi/spi-img-spfi.c +16 -7
index 0d73d31a6a2b..231b59c1ab60 100644
@@ -437,18 +437,23 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
 	struct img_spfi *spfi = spi_master_get_devdata(master);
 	u32 val;
 
+	/*
+	 * The chip select line is controlled externally so
+	 * we can use the CS0 configuration for all devices
+	 */
 	val = spfi_readl(spfi, SPFI_PORT_STATE);
+
+	/* 0 for device selection */
 	val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK <<
 		 SPFI_PORT_STATE_DEV_SEL_SHIFT);
-	val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
 	if (msg->spi->mode & SPI_CPHA)
-		val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
+		val |= SPFI_PORT_STATE_CK_PHASE(0);
 	else
-		val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
+		val &= ~SPFI_PORT_STATE_CK_PHASE(0);
 	if (msg->spi->mode & SPI_CPOL)
-		val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
+		val |= SPFI_PORT_STATE_CK_POL(0);
 	else
-		val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
+		val &= ~SPFI_PORT_STATE_CK_POL(0);
 	spfi_writel(spfi, val, SPFI_PORT_STATE);
 
 	return 0;
@@ -548,11 +553,15 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
 	div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz);
 	div = clamp(512 / (1 << get_count_order(div)), 1, 128);
 
-	val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select));
+	/*
+	 * The chip select line is controlled externally so
+	 * we can use the CS0 parameters for all devices
+	 */
+	val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(0));
 	val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK <<
 		 SPFI_DEVICE_PARAMETER_BITCLK_SHIFT);
 	val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
-	spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
+	spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(0));
 
 	if (!list_is_last(&xfer->transfer_list, &master->cur_msg->transfers) &&
 		/*
Signature · 1 line
2.16.4
#23 lore raw

PATCH 13/15 spi: img-spfi: RX maximum burst size for DMA is 8

In reply to Andreas Färber

From: Ionela Voinescu <[email protected]>

The depth of the FIFOs is 16 bytes. The DMA request line is tied to the half full/empty (depending on the use of the TX or RX FIFO) threshold. For the TX FIFO, if you set a burst size of 8 (equal to half the depth) the first burst goes into FIFO without any issues, but due the latency involved (the time the data leaves the DMA engine to the time it arrives at the FIFO), the DMA might trigger another burst of 8. But given that there is no space for 2 additonal bursts of 8, this would result in a failure. Therefore, we have to keep the burst size for TX to 4 to accomodate for an extra burst.

For the read (RX) scenario, the DMA request line goes high when there is at least 8 entries in the FIFO (half full), and we can program the burst size to be 8 because the risk of accidental burst does not exist. The DMA engine will not trigger another read until the read data for all the burst it has sent out has been received.

While here, move the burst size setting outside of the if/else branches as they have the same value for both 8 and 32 bit data widths.

---
 drivers/spi/spi-img-spfi.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/spi/spi-img-spfi.c +2 -4
index 231b59c1ab60..8ad6c75d0af5 100644
@@ -346,12 +346,11 @@ static int img_spfi_start_dma(struct spi_master *master,
 		if (xfer->len % 4 == 0) {
 			rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA;
 			rxconf.src_addr_width = 4;
-			rxconf.src_maxburst = 4;
 		} else {
 			rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA;
 			rxconf.src_addr_width = 1;
-			rxconf.src_maxburst = 4;
 		}
+		rxconf.src_maxburst = 8;
 		dmaengine_slave_config(spfi->rx_ch, &rxconf);
 
 		rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl,
@@ -370,12 +369,11 @@ static int img_spfi_start_dma(struct spi_master *master,
 		if (xfer->len % 4 == 0) {
 			txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA;
 			txconf.dst_addr_width = 4;
-			txconf.dst_maxburst = 4;
 		} else {
 			txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA;
 			txconf.dst_addr_width = 1;
-			txconf.dst_maxburst = 4;
 		}
+		txconf.dst_maxburst = 4;
 		dmaengine_slave_config(spfi->tx_ch, &txconf);
 
 		txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl,
Signature · 1 line
2.16.4
maintainer
#24 lore raw

Re: [PATCH 13/15] spi: img-spfi: RX maximum burst size for DMA is 8

Quoted 11 lines · Andreas Färber

From: Ionela Voinescu <[email protected]>

The depth of the FIFOs is 16 bytes. The DMA request line is tied to the half full/empty (depending on the use of the TX or RX FIFO) threshold. For the TX FIFO, if you set a burst size of 8 (equal to half the depth) the first burst goes into FIFO without any issues, but due the latency involved (the time the data leaves the DMA engine to the time it arrives at the FIFO), the DMA might trigger another burst of 8. But given that there is no space for 2 additonal bursts of 8, this would result in a failure. Therefore, we have to keep the burst size for TX to 4 to accomodate for an extra burst.

This seems like something that should be sent as a bug fix - doesn't it fix anything? If it is a fix then it should've gone at the start of the series so it's got no dependencies and could be sent to Linus for the current release.

Quoted 2 lines

While here, move the burst size setting outside of the if/else branches as they have the same value for both 8 and 32 bit data widths.

Though this refactoring probably less so.

#25 lore raw

PATCH 14/15 spi: img-spfi: Finish every transfer cleanly

In reply to Andreas Färber

From: Ionela Voinescu <[email protected]>

Before this change, the interrupt status bit that signaled the end of a transfer was cleared in the wait_all_done function. That functionality triggered issues for DMA duplex transactions where the wait function was called twice, in both the TX and RX callbacks.

In order to fix the issue, clear all interrupt data bits at the end of a PIO transfer or at the end of both TX and RX duplex transfers, if the transfer is not a pending transfer (command waiting for data). After that, the status register is checked for new incoming data or new data requests to be signaled. If SPFI finished cleanly, no new interrupt data bits should be set.

---
 drivers/spi/spi-img-spfi.c | 49 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 14 deletions(-)
drivers/spi/spi-img-spfi.c +35 -14
index 8ad6c75d0af5..a1244234daa5 100644
@@ -83,6 +83,14 @@
 #define SPFI_INTERRUPT_SDE			BIT(1)
 #define SPFI_INTERRUPT_SDTRIG			BIT(0)
 
+#define SPFI_INTERRUPT_DATA_BITS		(SPFI_INTERRUPT_SDHF |\
+						SPFI_INTERRUPT_SDFUL |\
+						SPFI_INTERRUPT_GDEX32BIT |\
+						SPFI_INTERRUPT_GDHF |\
+						SPFI_INTERRUPT_GDFUL |\
+						SPFI_INTERRUPT_ALLDONETRIG |\
+						SPFI_INTERRUPT_GDEX8BIT)
+
 /*
  * There are four parallel FIFOs of 16 bytes each.  The word buffer
  * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an
@@ -144,6 +152,23 @@ static inline void spfi_reset(struct img_spfi *spfi)
 	spfi_writel(spfi, 0, SPFI_CONTROL);
 }
 
+static inline void spfi_finish(struct img_spfi *spfi)
+{
+	if (!(spfi->complete))
+		return;
+
+	/* Clear data bits as all transfers(TX and RX) have finished */
+	spfi_writel(spfi, SPFI_INTERRUPT_DATA_BITS, SPFI_INTERRUPT_CLEAR);
+	if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & SPFI_INTERRUPT_DATA_BITS) {
+		dev_err(spfi->dev, "SPFI did not finish transfer cleanly.\n");
+		spfi_reset(spfi);
+	}
+	/* Disable SPFI for it not to interfere with pending transactions */
+	spfi_writel(spfi,
+		    spfi_readl(spfi, SPFI_CONTROL) & ~SPFI_CONTROL_SPFI_EN,
+		    SPFI_CONTROL);
+}
+
 static int spfi_wait_all_done(struct img_spfi *spfi)
 {
 	unsigned long timeout = jiffies + msecs_to_jiffies(50);
@@ -152,19 +177,9 @@ static int spfi_wait_all_done(struct img_spfi *spfi)
 		return 0;
 
 	while (time_before(jiffies, timeout)) {
-		u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
-
-		if (status & SPFI_INTERRUPT_ALLDONETRIG) {
-			spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
-				    SPFI_INTERRUPT_CLEAR);
-			/*
-			 * Disable SPFI for it not to interfere with
-			 * pending transactions
-			 */
-			spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL)
-			& ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL);
+		if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) &
+		    SPFI_INTERRUPT_ALLDONETRIG)
 			return 0;
-		}
 		cpu_relax();
 	}
 
@@ -296,6 +311,8 @@ static int img_spfi_start_pio(struct spi_master *master,
 	}
 
 	ret = spfi_wait_all_done(spfi);
+	spfi_finish(spfi);
+
 	if (ret < 0)
 		return ret;
 
@@ -311,8 +328,10 @@ static void img_spfi_dma_rx_cb(void *data)
 
 	spin_lock_irqsave(&spfi->lock, flags);
 	spfi->rx_dma_busy = false;
-	if (!spfi->tx_dma_busy)
+	if (!spfi->tx_dma_busy) {
+		spfi_finish(spfi);
 		spi_finalize_current_transfer(spfi->master);
+	}
 	spin_unlock_irqrestore(&spfi->lock, flags);
 }
 
@@ -325,8 +344,10 @@ static void img_spfi_dma_tx_cb(void *data)
 
 	spin_lock_irqsave(&spfi->lock, flags);
 	spfi->tx_dma_busy = false;
-	if (!spfi->rx_dma_busy)
+	if (!spfi->rx_dma_busy) {
+		spfi_finish(spfi);
 		spi_finalize_current_transfer(spfi->master);
+	}
 	spin_unlock_irqrestore(&spfi->lock, flags);
 }
 
Signature · 1 line
2.16.4
maintainer
#26 lore raw

Re: [PATCH 14/15] spi: img-spfi: Finish every transfer cleanly

Quoted 7 lines · Andreas Färber

From: Ionela Voinescu <[email protected]>

Before this change, the interrupt status bit that signaled the end of a transfer was cleared in the wait_all_done function. That functionality triggered issues for DMA duplex transactions where the wait function was called twice, in both the TX and RX callbacks.

Again, is this not a fix?

#27 lore raw

PATCH 15/15 clk: pistachio: Fix wrong SDHost card speed

In reply to Andreas Färber

From: Govindraj Raja <[email protected]>

The SDHost currently clocks the card 4x slower than it should do, because there is a fixed divide by 4 in the sdhost wrapper that is not present in the clock tree. To model this, add a fixed divide by 4 clock node in the SDHost clock path.

This will ensure the right clock frequency is selected when the mmc driver tries to configure frequency on card insert.

---
 drivers/clk/pistachio/clk-pistachio.c     | 3 ++-
 include/dt-bindings/clock/pistachio-clk.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/clk/pistachio/clk-pistachio.c +2 -1
index c4ceb5eaf46c..1c968d9a6e17 100644
@@ -44,7 +44,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = {
 	GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div",
 	     0x104, 22),
 	GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23),
-	GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24),
+	GATE(CLK_SD_HOST, "sd_host", "sd_host_div4", 0x104, 24),
 	GATE(CLK_BT, "bt", "bt_div", 0x104, 25),
 	GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26),
 	GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27),
@@ -54,6 +54,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = {
 static struct pistachio_fixed_factor pistachio_ffs[] __initdata = {
 	FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4),
 	FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8),
+	FIXED_FACTOR(CLK_SDHOST_DIV4, "sd_host_div4", "sd_host_div", 4),
 };
 
 static struct pistachio_div pistachio_divs[] __initdata = {
include/dt-bindings/clock/pistachio-clk.h +1 -0
index 039f83facb68..77b92aed241d 100644
@@ -21,6 +21,7 @@
 /* Fixed-factor clocks */
 #define CLK_WIFI_DIV4			16
 #define CLK_WIFI_DIV8			17
+#define CLK_SDHOST_DIV4			18
 
 /* Gate clocks */
 #define CLK_MIPS			32
Signature · 1 line
2.16.4
maintainer Acked-by on v1 15/15
#28 lore raw

Re: [PATCH 15/15] clk: pistachio: Fix wrong SDHost card speed

Quoting Andreas F=C3=A4rber (2018-07-22 14:20:10)

Quoted 10 lines

From: Govindraj Raja <[email protected]>
=

The SDHost currently clocks the card 4x slower than it should do, because there is a fixed divide by 4 in the sdhost wrapper that is not present in the clock tree. To model this, add a fixed divide by 4 clock node in the SDHost clock path.
=

Quoted 7 lines

This will ensure the right clock frequency is selected when the mmc driver tries to configure frequency on card insert. =

---

maintainer
#29 lore raw

Re: [PATCH 15/15] clk: pistachio: Fix wrong SDHost card speed

In reply to Andreas Färber
Quoted 44 lines · Andreas Färber

From: Govindraj Raja <[email protected]>

The SDHost currently clocks the card 4x slower than it should do, because there is a fixed divide by 4 in the sdhost wrapper that is not present in the clock tree. To model this, add a fixed divide by 4 clock node in the SDHost clock path.

This will ensure the right clock frequency is selected when the mmc driver tries to configure frequency on card insert.

---
 drivers/clk/pistachio/clk-pistachio.c     | 3 ++-
 include/dt-bindings/clock/pistachio-clk.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/clk/pistachio/clk-pistachio.c +2 -1
index c4ceb5eaf46c..1c968d9a6e17 100644
@@ -44,7 +44,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = {
 	GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div",
 	     0x104, 22),
 	GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23),
-	GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24),
+	GATE(CLK_SD_HOST, "sd_host", "sd_host_div4", 0x104, 24),
 	GATE(CLK_BT, "bt", "bt_div", 0x104, 25),
 	GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26),
 	GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27),
@@ -54,6 +54,7 @@ static struct pistachio_gate pistachio_gates[] __initdata = {
 static struct pistachio_fixed_factor pistachio_ffs[] __initdata = {
 	FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4),
 	FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8),
+	FIXED_FACTOR(CLK_SDHOST_DIV4, "sd_host_div4", "sd_host_div", 4),
 };
 
 static struct pistachio_div pistachio_divs[] __initdata = {
include/dt-bindings/clock/pistachio-clk.h +0 -0
index 039f83facb68..77b92aed241d 100644

include/dt-bindings/clock/pistachio-clk.h line 24

Quoted 4 lines
include/dt-bindings/clock/pistachio-clk.h +1 -0
@@ -21,6 +21,7 @@
 /* Fixed-factor clocks */
 #define CLK_WIFI_DIV4			16
 #define CLK_WIFI_DIV8			17
+#define CLK_SDHOST_DIV4			18

Does this clock really need to be exposed in DT?

Quoted 6 lines
include/dt-bindings/clock/pistachio-clk.h +0 -0
 /* Gate clocks */
 #define CLK_MIPS			32
Signature · 1 line
2.16.4