Skip to contentSkip to conversation

ARM: sun9i: Enable MMC support on Allwinner A80

PATCH Superseded Chen-Yu Tsai 2 participants 30 messages Dec 3, 2014 – Dec 7, 2014

Subsystems (4)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

cover ARM: sun9i: Enable MMC support on Allwinner A80

Hi Maxime,

This series enables MMC support on the A80 using existing drivers we have. The A80 has 4 MMC controllers. These controllers share a common clock gate and reset control, which are then sub-divided to each controller.

The phase clocks are the same as the older SoCs, so it should be straight forward to add them with the rest of the sunxi family. I did find that Allwinner's kernel uses different delay values for the A80, but so far I've not run into any issues using the mainline kernel.

Patch 1 adds module 0 type clock support for the A80. These are essentially the same as mod0 clocks on other Allwinner SoCs, except for the wider mux bits.

Patch 2 adds mmc mod clocks to the DTSI.

Patch 3 adds support for the mmc config (term from user manual) clocks. This is the part that breaks out the clock gates and reset controls for each controller. This is implemented as a platform driver, as the shared reset control must be de-asserted for any of either this or the mmc blocks to work.

Patch 4 adds clock-indices properties to the AHB/APB gate clocks. This is needed for of_clk_get_parent_name to work properly, as we use bit indices instead of counting the entries.

Patch 5 adds the mmc config clock nodes to the DTSI.

Patch 6 adds the mmc controller nodes to the DTSI.

Patch 7 and 9 add the pinmux settings for mmc0 and mmc2.

Patch 8 and 10 enable mmc0 and mmc2 on the A80 Optimus Board.

Kudos to Andreas for figuring out all the DT bits. His SoB is on the relevant patches.

Cheers
ChenYu Tsai

Chen-Yu Tsai (10):
clk: sunxi: Add module 0 (storage) style clock support for A80
ARM: dts: sun9i: Add mmc module clock nodes for A80
clk: sunxi: Add driver for A80 MMC config clocks/resets
ARM: dts: sun9i: Add clock-indices property for bus gate clocks
ARM: dts: sun9i: Add mmc config clock nodes
ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi
ARM: dts: sun9i: Add pinmux setting for mmc0
ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board
ARM: dts: sun9i: Add pinmux settings for mmc2
ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board

 Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
 arch/arm/boot/dts/sun9i-a80-optimus.dts           |  33 ++++
 arch/arm/boot/dts/sun9i-a80.dtsi                  | 122 ++++++++++++
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-mod0.c                      |  24 +++
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 228 ++++++++++++++++++++++
 6 files changed, 410 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c
Signature · 1 line
2.1.3
#1 lore raw

PATCH 1/10 clk: sunxi: Add module 0 (storage) style clock support for A80

The module 0 style clocks, or storage module clocks as named in the official SDK, are almost the same as the module 0 clocks on earlier Allwinner SoCs. The only difference is wider mux register bits.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
 drivers/clk/sunxi/clk-mod0.c                      | 24 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
index 9dc4f55..d0fb9c5 100644
@@ -58,6 +58,7 @@ Required properties:
 	"allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
 	"allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
 	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+	"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
 	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
 	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
drivers/clk/sunxi/clk-mod0.c +24 -0
index 658d74f..d72063f 100644
@@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
 
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+	.enable = 31,
+	.mux = 24,
+	.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+	.table = &sun4i_a10_mod0_config,
+	.getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+	void __iomem *reg;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (!reg) {
+		pr_err("Could not get registers for mod0-clk: %s\n",
+		       node->name);
+		return;
+	}
+
+	sunxi_factors_register(node, &sun9i_a80_mod0_data,
+			       &sun4i_a10_mod0_lock, reg);
+}
+CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
+
 static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
 
 static void __init sun5i_a13_mbus_setup(struct device_node *node)
Signature · 1 line
2.1.3
#2 lore raw

PATCH 1/10 clk: sunxi: Add module 0 (storage) style clock support for A80

Hi Chen-Yu,

Thanks for working on this

Quoted 41 lines · Chen-Yu Tsai

The module 0 style clocks, or storage module clocks as named in the official SDK, are almost the same as the module 0 clocks on earlier Allwinner SoCs. The only difference is wider mux register bits.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
 drivers/clk/sunxi/clk-mod0.c                      | 24 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
index 9dc4f55..d0fb9c5 100644
@@ -58,6 +58,7 @@ Required properties:
 	"allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
 	"allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
 	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+	"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
 	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
 	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
drivers/clk/sunxi/clk-mod0.c +11 -0
index 658d74f..d72063f 100644
@@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
 
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+	.enable = 31,
+	.mux = 24,
+	.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+	.table = &sun4i_a10_mod0_config,
+	.getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+	void __iomem *reg;

drivers/clk/sunxi/clk-mod0.c static void __init sun4i_a10_mod0_setup(struct device_node *node) · line 116

Quoted 10 lines
drivers/clk/sunxi/clk-mod0.c +10 -0
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (!reg) {
+		pr_err("Could not get registers for mod0-clk: %s\n",
+		       node->name);
+		return;
+	}
+
+	sunxi_factors_register(node, &sun9i_a80_mod0_data,
+			       &sun4i_a10_mod0_lock, reg);

Is there any particular reason to use the mod0 lock there? Or since only the A80 mod0 clocks are going to be used, it doesn't make any difference?

(Which makes me wonder why do we the same spinlock for all the instances of the mod0 clocks, but that's another story)

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141206/e45bd20a/attachment-0001.sig>
#3 lore raw

[linux-sunxi] Re: [PATCH 01/10] clk: sunxi: Add module 0 (storage) style clock support for A80

Hi,

Quoted 52 lines · Maxime Ripard

Hi Chen-Yu,

Thanks for working on this

Quoted 47 lines · Chen-Yu Tsai

The module 0 style clocks, or storage module clocks as named in the official SDK, are almost the same as the module 0 clocks on earlier Allwinner SoCs. The only difference is wider mux register bits.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
 drivers/clk/sunxi/clk-mod0.c                      | 24 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
index 9dc4f55..d0fb9c5 100644
@@ -58,6 +58,7 @@ Required properties:
      "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
      "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
      "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+     "allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
      "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
      "allwinner,sun7i-a20-out-clk" - for the external output clocks
      "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
drivers/clk/sunxi/clk-mod0.c +17 -0
index 658d74f..d72063f 100644
@@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
 
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+     .enable = 31,
+     .mux = 24,
+     .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+     .table = &sun4i_a10_mod0_config,
+     .getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+     void __iomem *reg;
+
+     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+     if (!reg) {
+             pr_err("Could not get registers for mod0-clk: %s\n",
+                    node->name);
+             return;
Quoted 8 lines

drivers/clk/sunxi/clk-mod0.c static void __init sun4i_a10_mod0_setup(struct device_node *node) · line 116

Quoted 4 lines
drivers/clk/sunxi/clk-mod0.c +4 -0
+     }
+
+     sunxi_factors_register(node, &sun9i_a80_mod0_data,
+                            &sun4i_a10_mod0_lock, reg);

Is there any particular reason to use the mod0 lock there? Or since only the A80 mod0 clocks are going to be used, it doesn't make any difference?

It doesn't make any difference for now.

Quoted 2 lines

(Which makes me wonder why do we the same spinlock for all the instances of the mod0 clocks, but that's another story)

Are you worried about contention? AFAIK we don't do anything fancy in our code that would result in a major problem. I was wondering the same thing a while ago.

ChenYu

#4 lore raw

[linux-sunxi] Re: [PATCH 01/10] clk: sunxi: Add module 0 (storage) style clock support for A80

Quoted 6 lines · Chen-Yu Tsai
Quoted 2 lines

(Which makes me wonder why do we the same spinlock for all the instances of the mod0 clocks, but that's another story)

Are you worried about contention? AFAIK we don't do anything fancy in our code that would result in a major problem. I was wondering the same thing a while ago.

Yes. While I'm not overly concerned about a performance bottleneck, it does seems a bit odd to have a shared lock when there's no shared resources.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/a2295bc8/attachment.sig>
#5 lore raw

PATCH 2/10 ARM: dts: sun9i: Add mmc module clock nodes for A80

In reply to Chen-Yu Tsai

The mmc module clocks are A80 specific module 0 (storage) type clocks.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +32 -0
index 494714f..33d18dc 100644
@@ -215,6 +215,38 @@
 			clock-output-names = "cci400";
 		};
 
+		mmc0_clk: clk at 06000410 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000410 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc0";
+		};
+
+		mmc1_clk: clk at 06000414 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000414 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc1";
+		};
+
+		mmc2_clk: clk at 06000418 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000418 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc2";
+		};
+
+		mmc3_clk: clk at 0600041c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x0600041c 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc3";
+		};
+
 		ahb0_gates: clk at 06000580 {
 			#clock-cells = <1>;
 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
Signature · 1 line
2.1.3
#6 lore raw

PATCH 2/10 ARM: dts: sun9i: Add mmc module clock nodes for A80

Hi,

Quoted 38 lines · Chen-Yu Tsai

The mmc module clocks are A80 specific module 0 (storage) type clocks.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +22 -0
index 494714f..33d18dc 100644
@@ -215,6 +215,38 @@
 			clock-output-names = "cci400";
 		};
 
+		mmc0_clk: clk at 06000410 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000410 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc0";
+		};
+
+		mmc1_clk: clk at 06000414 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000414 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc1";
+		};
+
+		mmc2_clk: clk at 06000418 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x06000418 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc2";

arch/arm/boot/dts/sun9i-a80.dtsi line 249

Quoted 10 lines
arch/arm/boot/dts/sun9i-a80.dtsi +10 -0
+		};
+
+		mmc3_clk: clk at 0600041c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun9i-a80-mod0-clk";
+			reg = <0x0600041c 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc3";
+		};
+

How is the phase stuff supposed to work? Is this still used on the A80?

Also, wasn't the mux supposed to have 4 bits (so something like at least 9 parent clocks?) given your previous patch?

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141206/65168323/attachment.sig>
#7 lore raw

PATCH 2/10 ARM: dts: sun9i: Add mmc module clock nodes for A80

Hi,

Quoted 45 lines · Maxime Ripard

Hi,

Quoted 42 lines · Chen-Yu Tsai

The mmc module clocks are A80 specific module 0 (storage) type clocks.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +26 -0
index 494714f..33d18dc 100644
@@ -215,6 +215,38 @@
                      clock-output-names = "cci400";
              };
 
+             mmc0_clk: clk at 06000410 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000410 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc0";
+             };
+
+             mmc1_clk: clk at 06000414 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000414 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc1";
+             };
+
+             mmc2_clk: clk at 06000418 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000418 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc2";
+             };
+
+             mmc3_clk: clk at 0600041c {
+                     #clock-cells = <0>;
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80.dtsi line 249

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +6 -0
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x0600041c 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc3";
+             };
+

How is the phase stuff supposed to work? Is this still used on the A80?

It is. This time, the register bits are actually documented.

Quoted 2 lines

Also, wasn't the mux supposed to have 4 bits (so something like at least 9 parent clocks?) given your previous patch?

The mux has 4 bits of valid settings. But only the first 2 have valid parent clocks. I suppose I should make it clear in the bindings?

Some of the other module clocks have parents on the first 2 and last 2 valid settings, so we'll need to use a mux table for them.

ChenYu

#8 lore raw

PATCH 2/10 ARM: dts: sun9i: Add mmc module clock nodes for A80

Quoted 58 lines · Chen-Yu Tsai

Hi,

Quoted 45 lines · Maxime Ripard

Hi,

Quoted 42 lines · Chen-Yu Tsai

The mmc module clocks are A80 specific module 0 (storage) type clocks.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +26 -0
index 494714f..33d18dc 100644
@@ -215,6 +215,38 @@
                      clock-output-names = "cci400";
              };
 
+             mmc0_clk: clk at 06000410 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000410 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc0";
+             };
+
+             mmc1_clk: clk at 06000414 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000414 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc1";
+             };
+
+             mmc2_clk: clk at 06000418 {
+                     #clock-cells = <0>;
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x06000418 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc2";
+             };
+
+             mmc3_clk: clk at 0600041c {
+                     #clock-cells = <0>;
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80.dtsi line 249

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +6 -0
+                     compatible = "allwinner,sun9i-a80-mod0-clk";
+                     reg = <0x0600041c 0x4>;
+                     clocks = <&osc24M>, <&pll4>;
+                     clock-output-names = "mmc3";
+             };
+

How is the phase stuff supposed to work? Is this still used on the A80?

Quoted 1 line

It is. This time, the register bits are actually documented.

Ok, cool.

Depending on when the patches are coming in, that might conflict with the last bits of the MMC clocks rework I'm about to send.

Quoted 5 lines
Quoted 2 lines

Also, wasn't the mux supposed to have 4 bits (so something like at least 9 parent clocks?) given your previous patch?

The mux has 4 bits of valid settings. But only the first 2 have valid parent clocks. I suppose I should make it clear in the bindings?

Not really, this is an implementation detail, it shouldn't leak in the DT. What you have is fine.

Quoted 2 lines

Some of the other module clocks have parents on the first 2 and last 2 valid settings, so we'll need to use a mux table for them.

Ok.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/c4f67af3/attachment-0001.sig>
#9 lore raw

PATCH 3/10 clk: sunxi: Add driver for A80 MMC config clocks/resets

In reply to Chen-Yu Tsai

On the A80 SoC, the 4 mmc controllers each have a separate register controlling their register access clocks and reset controls. These registers in turn share a ahb clock gate and reset control.

This patch adds a platform device driver for these controls. It requires both clocks and reset controls to be available, so using CLK_OF_DECLARE might not be the best way.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 228 ++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
index d0fb9c5..2de90ea 100644
@@ -65,6 +65,7 @@ Required properties:
 	"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+	"allwinner,sun9i-a80-mmc-clk" - for mmc gates + resets on A80
 
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
drivers/clk/sunxi/Makefile +1 -0
index a66953c..3a5292e 100644
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
 
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
 	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
drivers/clk/sunxi/clk-sun9i-mmc.c new file +228 -0

228 lines not on this page · raw message

Signature · 1 line
2.1.3
#10 lore raw

PATCH 3/10 clk: sunxi: Add driver for A80 MMC config clocks/resets

Hi,

Quoted 21 lines · Chen-Yu Tsai

On the A80 SoC, the 4 mmc controllers each have a separate register controlling their register access clocks and reset controls. These registers in turn share a ahb clock gate and reset control.

This patch adds a platform device driver for these controls. It requires both clocks and reset controls to be available, so using CLK_OF_DECLARE might not be the best way.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 228 ++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c
Documentation/devicetree/bindings/clock/sunxi.txt +0 -0
index d0fb9c5..2de90ea 100644

Documentation/devicetree/bindings/clock/sunxi.txt Required properties: · line 68

Quoted 4 lines
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
@@ -65,6 +65,7 @@ Required properties:
 	"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+	"allwinner,sun9i-a80-mmc-clk" - for mmc gates + resets on A80

Please document the arguments required for this clock as well.

Quoted 115 lines
Documentation/devicetree/bindings/clock/sunxi.txt +0 -0
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
drivers/clk/sunxi/Makefile +1 -0
index a66953c..3a5292e 100644
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
 
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
 	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
drivers/clk/sunxi/clk-sun9i-mmc.c new file +94 -0
new file mode 100644
index 0000000..7569625
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2013 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai	<[email protected]>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH		4
+
+#define SUN9I_MMC_GATE_BIT	16
+#define SUN9I_MMC_RESET_BIT	18
+
+struct sun9i_mmc_clk_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct clk			*clk;
+	struct reset_control		*reset;
+	struct clk_onecell_data		clk_data;
+	struct reset_controller_dev	rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct sun9i_mmc_clk_data *data = container_of(rcdev,
+						       struct sun9i_mmc_clk_data,
+						       rcdev);
+	unsigned long flags;
+	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+	u32 val;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	val = readl(reg);
+	writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct sun9i_mmc_clk_data *data = container_of(rcdev,
+						       struct sun9i_mmc_clk_data,
+						       rcdev);
+	unsigned long flags;
+	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+	u32 val;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	val = readl(reg);
+	writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+	.assert		= sun9i_mmc_reset_assert,
+	.deassert	= sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_clk_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sun9i_mmc_clk_data *data;
+	struct clk_onecell_data *clk_data;
+	const char *clk_name = np->name;
+	const char *clk_parent;
+	struct resource *r;
+	int count, i, ret;

drivers/clk/sunxi/clk-sun9i-mmc.c line 104

Quoted 10 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +10 -0
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	spin_lock_init(&data->lock);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* one clock/reset pair per word */
+	count = (r->end - r->start + 1) / SUN9I_MMC_WIDTH;

div_round_up(resource_size(r), sizeof(u32)) ?

Quoted 22 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +22 -0
+	data->membase = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(data->membase))
+		return PTR_ERR(data->membase);
+
+	clk_data = &data->clk_data;
+	clk_data->clk_num = count;
+	clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+				      GFP_KERNEL);
+	if (!clk_data->clks)
+		return -ENOMEM;
+
+	clk_parent = of_clk_get_parent_name(np, 0);
+	if (!clk_parent)
+		return -EINVAL;
+
+	data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	data->reset = devm_reset_control_get(&pdev->dev, NULL);

drivers/clk/sunxi/clk-sun9i-mmc.c line 136

Quoted 10 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +10 -0
+	if (IS_ERR(data->reset)) {
+		dev_err(&pdev->dev, "Could not get reset control\n");
+		return PTR_ERR(data->reset);
+	}
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Clock enable err %d\n", ret);
+		return ret;
+	}

So that means that the clock will always be enabled, even if there's no downstream users?

Having the either clk_prepare_enable (or clk_enable if you're in atomic context) in the assert/deassert seems more logical.

Quoted 81 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +81 -0
+	ret = reset_control_deassert(data->reset);
+	if (ret) {
+		dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+		goto err_reset;
+	}
+
+	for (i = 0; i < count; i++) {
+		of_property_read_string_index(np, "clock-output-names",
+					      i, &clk_name);
+
+		clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+						      clk_parent, 0,
+						      data->membase + SUN9I_MMC_WIDTH * i,
+						      SUN9I_MMC_GATE_BIT, 0,
+						      &data->lock);
+
+		if (IS_ERR(clk_data->clks[i])) {
+			ret = PTR_ERR(clk_data->clks[i]);
+			goto err_clk_register;
+		}
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	if (ret)
+		goto err_clk_provider;
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = count;
+	data->rcdev.ops = &sun9i_mmc_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	ret = reset_controller_register(&data->rcdev);
+	if (ret)
+		goto err_rc_reg;
+
+	platform_set_drvdata(pdev, data);
+
+	return 0;
+
+err_rc_reg:
+	of_clk_del_provider(np);
+
+err_clk_provider:
+	for (i = 0; i < count; i++)
+		clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+	reset_control_assert(data->reset);
+
+err_reset:
+	clk_disable_unprepare(data->clk);
+
+	return ret;
+}
+
+static int sun9i_a80_mmc_clk_remove(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+	struct clk_onecell_data *clk_data = &data->clk_data;
+	int i;
+
+	reset_controller_unregister(&data->rcdev);
+	of_clk_del_provider(np);
+	for (i = 0; i < clk_data->clk_num; i++)
+		clk_unregister(clk_data->clks[i]);
+
+	reset_control_assert(data->reset);
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_clk_dt_ids[] = {
+	{ .compatible = "allwinner,sun9i-a80-mmc-clk" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_clk_driver = {
+	.driver = {
+		.name = "sun9i-a80-mmc-clk",

drivers/clk/sunxi/clk-sun9i-mmc.c line 228

Quoted 10 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +10 -0
+		.of_match_table = sun9i_a80_mmc_clk_dt_ids,
+	},
+	.probe = sun9i_a80_mmc_clk_probe,
+	.remove = sun9i_a80_mmc_clk_remove,
+};
+module_platform_driver(sun9i_a80_mmc_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");

What's the real benefit of enabling it as a platform driver? the reset framework is set up early enough that you can use OF_CLK_DECLARE.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141206/6d4f4d6b/attachment-0001.sig>
#11 lore raw

PATCH 3/10 clk: sunxi: Add driver for A80 MMC config clocks/resets

Hi,

Quoted 19 lines · Maxime Ripard

Hi,

Quoted 16 lines · Chen-Yu Tsai

On the A80 SoC, the 4 mmc controllers each have a separate register controlling their register access clocks and reset controls. These registers in turn share a ahb clock gate and reset control.

This patch adds a platform device driver for these controls. It requires both clocks and reset controls to be available, so using CLK_OF_DECLARE might not be the best way.

---
 Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 228 ++++++++++++++++++++++
 3 files changed, 230 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c
Quoted 11 lines

Documentation/devicetree/bindings/clock/sunxi.txt Required properties: · line 68

Quoted 9 lines
Documentation/devicetree/bindings/clock/sunxi.txt +1 -0
index d0fb9c5..2de90ea 100644
@@ -65,6 +65,7 @@ Required properties:
      "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
      "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
      "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+     "allwinner,sun9i-a80-mmc-clk" - for mmc gates + resets on A80

Please document the arguments required for this clock as well.

Ok.

Quoted 119 lines
Quoted 119 lines
Documentation/devicetree/bindings/clock/sunxi.txt +0 -0
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
drivers/clk/sunxi/Makefile +1 -0
index a66953c..3a5292e 100644
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
 
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
      clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
drivers/clk/sunxi/clk-sun9i-mmc.c new file +98 -0
new file mode 100644
index 0000000..7569625
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2013 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai      <[email protected]>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH              4
+
+#define SUN9I_MMC_GATE_BIT   16
+#define SUN9I_MMC_RESET_BIT  18
+
+struct sun9i_mmc_clk_data {
+     spinlock_t                      lock;
+     void __iomem                    *membase;
+     struct clk                      *clk;
+     struct reset_control            *reset;
+     struct clk_onecell_data         clk_data;
+     struct reset_controller_dev     rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+                           unsigned long id)
+{
+     struct sun9i_mmc_clk_data *data = container_of(rcdev,
+                                                    struct sun9i_mmc_clk_data,
+                                                    rcdev);
+     unsigned long flags;
+     void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+     u32 val;
+
+     spin_lock_irqsave(&data->lock, flags);
+
+     val = readl(reg);
+     writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+     spin_unlock_irqrestore(&data->lock, flags);
+
+     return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+                             unsigned long id)
+{
+     struct sun9i_mmc_clk_data *data = container_of(rcdev,
+                                                    struct sun9i_mmc_clk_data,
+                                                    rcdev);
+     unsigned long flags;
+     void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+     u32 val;
+
+     spin_lock_irqsave(&data->lock, flags);
+
+     val = readl(reg);
+     writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+     spin_unlock_irqrestore(&data->lock, flags);
+
+     return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+     .assert         = sun9i_mmc_reset_assert,
+     .deassert       = sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_clk_probe(struct platform_device *pdev)
+{
+     struct device_node *np = pdev->dev.of_node;
+     struct sun9i_mmc_clk_data *data;
+     struct clk_onecell_data *clk_data;
+     const char *clk_name = np->name;
+     const char *clk_parent;
+     struct resource *r;
+     int count, i, ret;
+
+     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+     if (!data)
+             return -ENOMEM;
Quoted 8 lines

drivers/clk/sunxi/clk-sun9i-mmc.c line 104

Quoted 6 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +6 -0
+
+     spin_lock_init(&data->lock);
+
+     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     /* one clock/reset pair per word */
+     count = (r->end - r->start + 1) / SUN9I_MMC_WIDTH;

div_round_up(resource_size(r), sizeof(u32)) ?

Will fix.

Quoted 27 lines
Quoted 27 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +27 -0
+     data->membase = devm_ioremap_resource(&pdev->dev, r);
+     if (IS_ERR(data->membase))
+             return PTR_ERR(data->membase);
+
+     clk_data = &data->clk_data;
+     clk_data->clk_num = count;
+     clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+                                   GFP_KERNEL);
+     if (!clk_data->clks)
+             return -ENOMEM;
+
+     clk_parent = of_clk_get_parent_name(np, 0);
+     if (!clk_parent)
+             return -EINVAL;
+
+     data->clk = devm_clk_get(&pdev->dev, NULL);
+     if (IS_ERR(data->clk)) {
+             dev_err(&pdev->dev, "Could not get clock\n");
+             return PTR_ERR(data->clk);
+     }
+
+     data->reset = devm_reset_control_get(&pdev->dev, NULL);
+     if (IS_ERR(data->reset)) {
+             dev_err(&pdev->dev, "Could not get reset control\n");
+             return PTR_ERR(data->reset);
+     }
+
Quoted 8 lines

drivers/clk/sunxi/clk-sun9i-mmc.c line 136

Quoted 5 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +5 -0
+     ret = clk_prepare_enable(data->clk);
+     if (ret) {
+             dev_err(&pdev->dev, "Clock enable err %d\n", ret);
+             return ret;
+     }

So that means that the clock will always be enabled, even if there's no downstream users?

Yes.

Quoted 2 lines

Having the either clk_prepare_enable (or clk_enable if you're in atomic context) in the assert/deassert seems more logical.

I'll try it out and see if it works. Didn't work so well with the USB clocks...

Quoted 86 lines
Quoted 86 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +86 -0
+     ret = reset_control_deassert(data->reset);
+     if (ret) {
+             dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+             goto err_reset;
+     }
+
+     for (i = 0; i < count; i++) {
+             of_property_read_string_index(np, "clock-output-names",
+                                           i, &clk_name);
+
+             clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+                                                   clk_parent, 0,
+                                                   data->membase + SUN9I_MMC_WIDTH * i,
+                                                   SUN9I_MMC_GATE_BIT, 0,
+                                                   &data->lock);
+
+             if (IS_ERR(clk_data->clks[i])) {
+                     ret = PTR_ERR(clk_data->clks[i]);
+                     goto err_clk_register;
+             }
+     }
+
+     ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+     if (ret)
+             goto err_clk_provider;
+
+     data->rcdev.owner = THIS_MODULE;
+     data->rcdev.nr_resets = count;
+     data->rcdev.ops = &sun9i_mmc_reset_ops;
+     data->rcdev.of_node = pdev->dev.of_node;
+
+     ret = reset_controller_register(&data->rcdev);
+     if (ret)
+             goto err_rc_reg;
+
+     platform_set_drvdata(pdev, data);
+
+     return 0;
+
+err_rc_reg:
+     of_clk_del_provider(np);
+
+err_clk_provider:
+     for (i = 0; i < count; i++)
+             clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+     reset_control_assert(data->reset);
+
+err_reset:
+     clk_disable_unprepare(data->clk);
+
+     return ret;
+}
+
+static int sun9i_a80_mmc_clk_remove(struct platform_device *pdev)
+{
+     struct device_node *np = pdev->dev.of_node;
+     struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+     struct clk_onecell_data *clk_data = &data->clk_data;
+     int i;
+
+     reset_controller_unregister(&data->rcdev);
+     of_clk_del_provider(np);
+     for (i = 0; i < clk_data->clk_num; i++)
+             clk_unregister(clk_data->clks[i]);
+
+     reset_control_assert(data->reset);
+     clk_disable_unprepare(data->clk);
+
+     return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_clk_dt_ids[] = {
+     { .compatible = "allwinner,sun9i-a80-mmc-clk" },
+     { /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_clk_driver = {
+     .driver = {
+             .name = "sun9i-a80-mmc-clk",
+             .of_match_table = sun9i_a80_mmc_clk_dt_ids,
+     },
+     .probe = sun9i_a80_mmc_clk_probe,
+     .remove = sun9i_a80_mmc_clk_remove,
+};
Quoted 8 lines

drivers/clk/sunxi/clk-sun9i-mmc.c line 228

Quoted 5 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +5 -0
+module_platform_driver(sun9i_a80_mmc_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");

What's the real benefit of enabling it as a platform driver? the reset framework is set up early enough that you can use OF_CLK_DECLARE.

This clock/reset block also requires a reset control de-asserted. The reset controllers are currently setup using platform devices. Are you suggesting I use "allwinner,sun6i-a31-ahb1-reset" instead? That would also imply having a .init_time callback for sun9i, and having sun6i_reset_init() before of_clk_init(). Kind of confusing (not sure this is the right word) for something not so critical.

Also we get to use devres, but that's just a bonus.

Thanks
ChenYu

#12 lore raw

PATCH 3/10 clk: sunxi: Add driver for A80 MMC config clocks/resets

Quoted 5 lines · Chen-Yu Tsai
Quoted 2 lines

Having the either clk_prepare_enable (or clk_enable if you're in atomic context) in the assert/deassert seems more logical.

I'll try it out and see if it works. Didn't work so well with the USB clocks...

If it doesn't, it would be good to know why, it really should work.

Quoted 95 lines
Quoted 86 lines
Quoted 86 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +86 -0
+     ret = reset_control_deassert(data->reset);
+     if (ret) {
+             dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+             goto err_reset;
+     }
+
+     for (i = 0; i < count; i++) {
+             of_property_read_string_index(np, "clock-output-names",
+                                           i, &clk_name);
+
+             clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+                                                   clk_parent, 0,
+                                                   data->membase + SUN9I_MMC_WIDTH * i,
+                                                   SUN9I_MMC_GATE_BIT, 0,
+                                                   &data->lock);
+
+             if (IS_ERR(clk_data->clks[i])) {
+                     ret = PTR_ERR(clk_data->clks[i]);
+                     goto err_clk_register;
+             }
+     }
+
+     ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+     if (ret)
+             goto err_clk_provider;
+
+     data->rcdev.owner = THIS_MODULE;
+     data->rcdev.nr_resets = count;
+     data->rcdev.ops = &sun9i_mmc_reset_ops;
+     data->rcdev.of_node = pdev->dev.of_node;
+
+     ret = reset_controller_register(&data->rcdev);
+     if (ret)
+             goto err_rc_reg;
+
+     platform_set_drvdata(pdev, data);
+
+     return 0;
+
+err_rc_reg:
+     of_clk_del_provider(np);
+
+err_clk_provider:
+     for (i = 0; i < count; i++)
+             clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+     reset_control_assert(data->reset);
+
+err_reset:
+     clk_disable_unprepare(data->clk);
+
+     return ret;
+}
+
+static int sun9i_a80_mmc_clk_remove(struct platform_device *pdev)
+{
+     struct device_node *np = pdev->dev.of_node;
+     struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+     struct clk_onecell_data *clk_data = &data->clk_data;
+     int i;
+
+     reset_controller_unregister(&data->rcdev);
+     of_clk_del_provider(np);
+     for (i = 0; i < clk_data->clk_num; i++)
+             clk_unregister(clk_data->clks[i]);
+
+     reset_control_assert(data->reset);
+     clk_disable_unprepare(data->clk);
+
+     return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_clk_dt_ids[] = {
+     { .compatible = "allwinner,sun9i-a80-mmc-clk" },
+     { /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_clk_driver = {
+     .driver = {
+             .name = "sun9i-a80-mmc-clk",
+             .of_match_table = sun9i_a80_mmc_clk_dt_ids,
+     },
+     .probe = sun9i_a80_mmc_clk_probe,
+     .remove = sun9i_a80_mmc_clk_remove,
+};
Quoted 8 lines

drivers/clk/sunxi/clk-sun9i-mmc.c line 228

Quoted 5 lines
drivers/clk/sunxi/clk-sun9i-mmc.c new file +5 -0
+module_platform_driver(sun9i_a80_mmc_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");

What's the real benefit of enabling it as a platform driver? the reset framework is set up early enough that you can use OF_CLK_DECLARE.

Quoted 8 lines

This clock/reset block also requires a reset control de-asserted. The reset controllers are currently setup using platform devices. Are you suggesting I use "allwinner,sun6i-a31-ahb1-reset" instead? That would also imply having a .init_time callback for sun9i, and having sun6i_reset_init() before of_clk_init(). Kind of confusing (not sure this is the right word) for something not so critical.

Also we get to use devres, but that's just a bonus.

Ok, it makes sense then.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/5602c9fc/attachment.sig>
#13 lore raw

PATCH 4/10 ARM: dts: sun9i: Add clock-indices property for bus gate clocks

In reply to Chen-Yu Tsai

of_clk_get_parent_name() uses the clock-indices property to resolve clock phandle arguments in case that the argument index does not match the clock-output-names sequence.

This is the case on sunxi, where we use the actual bit index as the argument to the phandle. Add the clock-indices property so that of_clk_get_parent_name() resolves the names correctly.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +10 -0
index 33d18dc..f3cac3a 100644
@@ -252,6 +252,9 @@
 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
 			reg = <0x06000580 0x4>;
 			clocks = <&ahb0>;
+			clock-indices = <0>, <1>, <3>, <5>, <8>, <12>, <13>,
+					<14>, <15>, <16>, <18>, <20>, <21>,
+					<22>, <23>;
 			clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
 					"ahb0_ss", "ahb0_sd", "ahb0_nand1",
 					"ahb0_nand0", "ahb0_sdram",
@@ -265,6 +268,7 @@
 			compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
 			reg = <0x06000584 0x4>;
 			clocks = <&ahb1>;
+			clock-indices = <0>, <1>, <17>, <21>, <22>, <23>, <24>;
 			clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
 					"ahb1_gmac", "ahb1_msgbox",
 					"ahb1_spinlock", "ahb1_hstimer",
@@ -276,6 +280,8 @@
 			compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
 			reg = <0x06000588 0x4>;
 			clocks = <&ahb2>;
+			clock-indices = <0>, <1>, <2>, <4>, <5>, <7>, <8>,
+					<11>;
 			clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
 					"ahb2_edp", "ahb2_csi", "ahb2_hdmi",
 					"ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
@@ -286,6 +292,8 @@
 			compatible = "allwinner,sun9i-a80-apb0-gates-clk";
 			reg = <0x06000590 0x4>;
 			clocks = <&apb0>;
+			clock-indices = <1>, <5>, <11>, <12>, <13>, <15>,
+					<17>, <18>, <19>;
 			clock-output-names = "apb0_spdif", "apb0_pio",
 					"apb0_ac97", "apb0_i2s0", "apb0_i2s1",
 					"apb0_lradc", "apb0_gpadc", "apb0_twd",
@@ -297,6 +305,8 @@
 			compatible = "allwinner,sun9i-a80-apb1-gates-clk";
 			reg = <0x06000594 0x4>;
 			clocks = <&apb1>;
+			clock-indices = <0>, <1>, <2>, <3>, <4>,
+					<16>, <17>, <18>, <19>, <20>, <21>;
 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
 					"apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
 					"apb1_uart0", "apb1_uart1",
Signature · 1 line
2.1.3
#14 lore raw

PATCH 5/10 ARM: dts: sun9i: Add mmc config clock nodes

In reply to Chen-Yu Tsai

Add the device tree nodes for the mmc config clock nodes.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +13 -0
index f3cac3a..f425d9d 100644
@@ -325,6 +325,19 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc_config_clk: clk at 01c23000 {
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x01c13000 0x10>;
+			clocks = <&ahb0_gates 8>;
+			clock-names = "ahb";
+			resets = <&ahb0_resets 8>;
+			reset-names = "ahb";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			clock-output-names = "mmc0_config", "mmc1_config",
+					     "mmc2_config", "mmc3_config";
+		};
+
 		gic: interrupt-controller at 01c41000 {
 			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
 			reg = <0x01c41000 0x1000>,
Signature · 1 line
2.1.3
#15 lore raw

PATCH 5/10 ARM: dts: sun9i: Add mmc config clock nodes

Hi,

Quoted 12 lines · Chen-Yu Tsai

Add the device tree nodes for the mmc config clock nodes.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +0 -0
index f3cac3a..f425d9d 100644

arch/arm/boot/dts/sun9i-a80.dtsi line 330

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +3 -0
@@ -325,6 +325,19 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc_config_clk: clk at 01c23000 {
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x01c13000 0x10>;

The reg and the unit-address don't match.

Also, this used to be defined in the clocks node for the USB case, it would be good to do the same here.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/c349f392/attachment.sig>
#16 lore raw

PATCH 5/10 ARM: dts: sun9i: Add mmc config clock nodes

Quoted 18 lines · Maxime Ripard

Hi,

Quoted 15 lines · Chen-Yu Tsai

Add the device tree nodes for the mmc config clock nodes.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +0 -0
index f3cac3a..f425d9d 100644
@@ -325,6 +325,19 @@
               */
              ranges = <0 0 0 0x20000000>;
 
Quoted 5 lines

arch/arm/boot/dts/sun9i-a80.dtsi line 330

Quoted 3 lines
arch/arm/boot/dts/sun9i-a80.dtsi +3 -0
+             mmc_config_clk: clk at 01c23000 {
+                     compatible = "allwinner,sun9i-a80-mmc-clk";
+                     reg = <0x01c13000 0x10>;

The reg and the unit-address don't match.

Will fix.

Quoted 2 lines

Also, this used to be defined in the clocks node for the USB case, it would be good to do the same here.

As it is a platform driver, it can't be under the clocks node, which doesn't instantiate platform devices. (That is, assuming you're ok with it being a platform driver.)

ChenYu

#17 lore raw

PATCH 5/10 ARM: dts: sun9i: Add mmc config clock nodes

Quoted 3 lines · Chen-Yu Tsai

As it is a platform driver, it can't be under the clocks node, which doesn't instantiate platform devices. (That is, assuming you're ok with it being a platform driver.)

That shouldn't have any impact on the DT itself, but yeah, you're right.

I guess we should just kill that clocks node for memory mapped clocks one day.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/386251cd/attachment.sig>
#18 lore raw

PATCH 6/10 ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi

In reply to Chen-Yu Tsai

The A80 has 4 mmc controllers.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 44 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +44 -0
index f425d9d..c766698 100644
@@ -325,6 +325,50 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc0: mmc at 01c0f000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&mmc_config_clk 0>, <&mmc0_clk>;
+			clock-names = "ahb", "mmc";
+			resets = <&mmc_config_clk 0>;
+			reset-names = "ahb";
+			interrupts = <0 60 4>;
+			status = "disabled";
+		};
+
+		mmc1: mmc at 01c10000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&mmc_config_clk 1>, <&mmc1_clk>;
+			clock-names = "ahb", "mmc";
+			resets = <&mmc_config_clk 1>;
+			reset-names = "ahb";
+			interrupts = <0 61 4>;
+			status = "disabled";
+		};
+
+		mmc2: mmc at 01c11000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c11000 0x1000>;
+			clocks = <&mmc_config_clk 2>, <&mmc2_clk>;
+			clock-names = "ahb", "mmc";
+			resets = <&mmc_config_clk 2>;
+			reset-names = "ahb";
+			interrupts = <0 62 4>;
+			status = "disabled";
+		};
+
+		mmc3: mmc at 01c12000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&mmc_config_clk 3>, <&mmc3_clk>;
+			clock-names = "ahb", "mmc";
+			resets = <&mmc_config_clk 3>;
+			reset-names = "ahb";
+			interrupts = <0 63 4>;
+			status = "disabled";
+		};
+
 		mmc_config_clk: clk at 01c23000 {
 			compatible = "allwinner,sun9i-a80-mmc-clk";
 			reg = <0x01c13000 0x10>;
Signature · 1 line
2.1.3
#19 lore raw

PATCH 7/10 ARM: dts: sun9i: Add pinmux setting for mmc0

In reply to Chen-Yu Tsai

mmc0 is only available on port F, and is always used with a 4 bit wide bus for the onboard micro-sd slot.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +8 -0
index c766698..f5b5645 100644
@@ -458,6 +458,14 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_pins: mmc0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3",
+						 "PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <2>;
+				allwinner,pull = <0>;
+			};
+
 			uart0_pins_a: uart0 at 0 {
 				allwinner,pins = "PH12", "PH13";
 				allwinner,function = "uart0";
Signature · 1 line
2.1.3
#20 lore raw

PATCH 7/10 ARM: dts: sun9i: Add pinmux setting for mmc0

Hi,

Quoted 14 lines · Chen-Yu Tsai

mmc0 is only available on port F, and is always used with a 4 bit wide bus for the onboard micro-sd slot.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +0 -0
index c766698..f5b5645 100644

arch/arm/boot/dts/sun9i-a80.dtsi line 463

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +3 -0
@@ -458,6 +458,14 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_pins: mmc0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3",
+						 "PF4","PF5";

A space after each comma please.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/c5769288/attachment.sig>
#21 lore raw

PATCH 8/10 ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board

In reply to Chen-Yu Tsai

Enable the micro-sd slot on the A80 Optimus Board, which is connected to mmc0. This adds the card-detect gpio and enables mmc0.

This patch also adds a 3V fixed regulator, which is the default I/O voltage level.

---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/boot/dts/sun9i-a80-optimus.dts +24 -0
index 506948f..02a4aa7 100644
@@ -59,6 +59,16 @@
 	};
 
 	soc {
+		mmc0: mmc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_optimus>;
+			vmmc-supply = <&reg_vcc3v0>;
+			bus-width = <4>;
+			cd-gpios = <&pio 7 18 0>; /* PH8 */
+			cd-inverted;
+			status = "okay";
+		};
+
 		pio: pinctrl at 06000800 {
 			i2c3_pins_a: i2c3 at 0 {
 				/* Enable internal pull-up */
@@ -72,6 +82,13 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_cd_pin_optimus: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH18";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <1>;
+			};
+
 			uart4_pins_a: uart4 at 0 {
 				/* Enable internal pull-up */
 				allwinner,pull = <1>;
@@ -116,4 +133,11 @@
 			gpios = <&pio 7 0 0>;
 		};
 	};
+
+	reg_vcc3v0: vcc3v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v0";
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+	};
 };
Signature · 1 line
2.1.3
#22 lore raw

PATCH 8/10 ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board

Hi,

Quoted 48 lines · Chen-Yu Tsai

Enable the micro-sd slot on the A80 Optimus Board, which is connected to mmc0. This adds the card-detect gpio and enables mmc0.

This patch also adds a 3V fixed regulator, which is the default I/O voltage level.

---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/boot/dts/sun9i-a80-optimus.dts +17 -0
index 506948f..02a4aa7 100644
@@ -59,6 +59,16 @@
 	};
 
 	soc {
+		mmc0: mmc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_optimus>;
+			vmmc-supply = <&reg_vcc3v0>;
+			bus-width = <4>;
+			cd-gpios = <&pio 7 18 0>; /* PH8 */
+			cd-inverted;
+			status = "okay";
+		};
+
 		pio: pinctrl at 06000800 {
 			i2c3_pins_a: i2c3 at 0 {
 				/* Enable internal pull-up */
@@ -72,6 +82,13 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_cd_pin_optimus: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH18";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <1>;
+			};
+
 			uart4_pins_a: uart4 at 0 {
 				/* Enable internal pull-up */
 				allwinner,pull = <1>;

arch/arm/boot/dts/sun9i-a80-optimus.dts line 142

Quoted 10 lines
arch/arm/boot/dts/sun9i-a80-optimus.dts +7 -0
@@ -116,4 +133,11 @@
 			gpios = <&pio 7 0 0>;
 		};
 	};
+
+	reg_vcc3v0: vcc3v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v0";
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+	};

There's already such a regulator in sunxi-common-regulators.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/9d729f61/attachment.sig>
#23 lore raw

PATCH 8/10 ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board

Quoted 55 lines · Maxime Ripard

Hi,

Quoted 52 lines · Chen-Yu Tsai

Enable the micro-sd slot on the A80 Optimus Board, which is connected to mmc0. This adds the card-detect gpio and enables mmc0.

This patch also adds a 3V fixed regulator, which is the default I/O voltage level.

---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/boot/dts/sun9i-a80-optimus.dts +18 -0
index 506948f..02a4aa7 100644
@@ -59,6 +59,16 @@
      };
 
      soc {
+             mmc0: mmc at 01c0f000 {
+                     pinctrl-names = "default";
+                     pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_optimus>;
+                     vmmc-supply = <&reg_vcc3v0>;
+                     bus-width = <4>;
+                     cd-gpios = <&pio 7 18 0>; /* PH8 */
+                     cd-inverted;
+                     status = "okay";
+             };
+
              pio: pinctrl at 06000800 {
                      i2c3_pins_a: i2c3 at 0 {
                              /* Enable internal pull-up */
@@ -72,6 +82,13 @@
                              allwinner,pull = <0>;
                      };
 
+                     mmc0_cd_pin_optimus: mmc0_cd_pin at 0 {
+                             allwinner,pins = "PH18";
+                             allwinner,function = "gpio_in";
+                             allwinner,drive = <0>;
+                             allwinner,pull = <1>;
+                     };
+
                      uart4_pins_a: uart4 at 0 {
                              /* Enable internal pull-up */
                              allwinner,pull = <1>;
@@ -116,4 +133,11 @@
                      gpios = <&pio 7 0 0>;
              };
      };
+
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80-optimus.dts line 142

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80-optimus.dts +6 -0
+     reg_vcc3v0: vcc3v0 {
+             compatible = "regulator-fixed";
+             regulator-name = "vcc3v0";
+             regulator-min-microvolt = <3000000>;
+             regulator-max-microvolt = <3000000>;
+     };

There's already such a regulator in sunxi-common-regulators.

I cannot include sunxi-common-regulators, not without a lot of work. sunxi-common-regulators includes a soc/pio node, but the addresses, and thus the node names are different. This results in:

ERROR (duplicate_label): Duplicate label 'pio' on
/soc at 01c00000/pinctrl at 01c20800 and /soc/pinctrl at 06000800

If we move to preprocessor-based includes and phandle referencing (&pio { .... })
to override/add nodes and properties, then it would work. But that is a lot of work
going through all of our DTs.

I'd prefer getting things working first, and do the rework later. As far as DT compatibility goes, there shouldn't be any difference in the DTB.

ChenYu

#24 lore raw

PATCH 8/10 ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board

Quoted 13 lines · Chen-Yu Tsai
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80-optimus.dts line 142

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80-optimus.dts +6 -0
+     reg_vcc3v0: vcc3v0 {
+             compatible = "regulator-fixed";
+             regulator-name = "vcc3v0";
+             regulator-min-microvolt = <3000000>;
+             regulator-max-microvolt = <3000000>;
+     };

There's already such a regulator in sunxi-common-regulators.

I cannot include sunxi-common-regulators, not without a lot of work. sunxi-common-regulators includes a soc/pio node, but the addresses, and thus the node names are different. This results in:

Quoted 8 lines

ERROR (duplicate_label): Duplicate label 'pio' on
/soc at 01c00000/pinctrl at 01c20800 and /soc/pinctrl at 06000800

If we move to preprocessor-based includes and phandle referencing (&pio { .... })
to override/add nodes and properties, then it would work. But that is a lot of work
going through all of our DTs.

Not really, you can just do so in sunxi-common-regulator. There's no need to do it everywhere else.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/de956048/attachment.sig>
#25 lore raw

PATCH 9/10 ARM: dts: sun9i: Add pinmux settings for mmc2

In reply to Chen-Yu Tsai

mmc2 is available on port C. Add a pinmux setting for usual 4 bit wide bus, as well as one with the 4 extra pins for 8 bit wide bus.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +15 -0
index f5b5645..fc866d8 100644
@@ -466,6 +466,21 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc2_pins: mmc2 {
+				allwinner,pins = "PC6","PC7","PC8","PC9",
+						 "PC10","PC11";
+				allwinner,function = "mmc2";
+				allwinner,drive = <2>;
+				allwinner,pull = <1>;
+			};
+
+			mmc2_8bit_pins: mmc2_8bit {
+				allwinner,pins = "PC12","PC13","PC14","PC15";
+				allwinner,function = "mmc2";
+				allwinner,drive = <2>;
+				allwinner,pull = <1>;
+			};
+
 			uart0_pins_a: uart0 at 0 {
 				allwinner,pins = "PH12", "PH13";
 				allwinner,function = "uart0";
Signature · 1 line
2.1.3
#26 lore raw

PATCH 9/10 ARM: dts: sun9i: Add pinmux settings for mmc2

Quoted 22 lines · Chen-Yu Tsai

mmc2 is available on port C. Add a pinmux setting for usual 4 bit wide bus, as well as one with the 4 extra pins for 8 bit wide bus.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +5 -0
index f5b5645..fc866d8 100644
@@ -466,6 +466,21 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc2_pins: mmc2 {
+				allwinner,pins = "PC6","PC7","PC8","PC9",
+						 "PC10","PC11";
+				allwinner,function = "mmc2";
+				allwinner,drive = <2>;

arch/arm/boot/dts/sun9i-a80.dtsi line 483

Quoted 10 lines
arch/arm/boot/dts/sun9i-a80.dtsi +10 -0
+				allwinner,pull = <1>;
+			};
+
+			mmc2_8bit_pins: mmc2_8bit {
+				allwinner,pins = "PC12","PC13","PC14","PC15";
+				allwinner,function = "mmc2";
+				allwinner,drive = <2>;
+				allwinner,pull = <1>;
+			};
+

Hmmm, how is that 8 bits? There's only 4 pins here.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/50e5d716/attachment.sig>
#27 lore raw

PATCH 9/10 ARM: dts: sun9i: Add pinmux settings for mmc2

Quoted 27 lines · Maxime Ripard
Quoted 26 lines · Chen-Yu Tsai

mmc2 is available on port C. Add a pinmux setting for usual 4 bit wide bus, as well as one with the 4 extra pins for 8 bit wide bus.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +9 -0
index f5b5645..fc866d8 100644
@@ -466,6 +466,21 @@
                              allwinner,pull = <0>;
                      };
 
+                     mmc2_pins: mmc2 {
+                             allwinner,pins = "PC6","PC7","PC8","PC9",
+                                              "PC10","PC11";
+                             allwinner,function = "mmc2";
+                             allwinner,drive = <2>;
+                             allwinner,pull = <1>;
+                     };
+
+                     mmc2_8bit_pins: mmc2_8bit {
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80.dtsi line 483

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +6 -0
+                             allwinner,pins = "PC12","PC13","PC14","PC15";
+                             allwinner,function = "mmc2";
+                             allwinner,drive = <2>;
+                             allwinner,pull = <1>;
+                     };
+

Hmmm, how is that 8 bits? There's only 4 pins here.

The 8bit setting only includes the upper 4 bits. Using both settings together you get an 8 bit bus, along with CMD and CLK pins, for a total of 10 pins.

Or is this the wrong way?

ChenYu

#28 lore raw

PATCH 9/10 ARM: dts: sun9i: Add pinmux settings for mmc2

Quoted 38 lines · Chen-Yu Tsai
Quoted 27 lines · Maxime Ripard
Quoted 26 lines · Chen-Yu Tsai

mmc2 is available on port C. Add a pinmux setting for usual 4 bit wide bus, as well as one with the 4 extra pins for 8 bit wide bus.

---
 arch/arm/boot/dts/sun9i-a80.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/arm/boot/dts/sun9i-a80.dtsi +9 -0
index f5b5645..fc866d8 100644
@@ -466,6 +466,21 @@
                              allwinner,pull = <0>;
                      };
 
+                     mmc2_pins: mmc2 {
+                             allwinner,pins = "PC6","PC7","PC8","PC9",
+                                              "PC10","PC11";
+                             allwinner,function = "mmc2";
+                             allwinner,drive = <2>;
+                             allwinner,pull = <1>;
+                     };
+
+                     mmc2_8bit_pins: mmc2_8bit {
Quoted 8 lines

arch/arm/boot/dts/sun9i-a80.dtsi line 483

Quoted 6 lines
arch/arm/boot/dts/sun9i-a80.dtsi +6 -0
+                             allwinner,pins = "PC12","PC13","PC14","PC15";
+                             allwinner,function = "mmc2";
+                             allwinner,drive = <2>;
+                             allwinner,pull = <1>;
+                     };
+

Hmmm, how is that 8 bits? There's only 4 pins here.

Quoted 5 lines

The 8bit setting only includes the upper 4 bits. Using both settings together you get an 8 bit bus, along with CMD and CLK pins, for a total of 10 pins.

Or is this the wrong way?

The way it's usually done is that you have two standalone nodes. Just like what's done for the UARTs for example.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141207/f30b618c/attachment-0001.sig>
#29 lore raw

PATCH 10/10 ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board

In reply to Chen-Yu Tsai

The A80 Optimus Board has a 16GB eMMC connected to mmc2, with 8 bit wide data bus.

---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm/boot/dts/sun9i-a80-optimus.dts +9 -0
index 02a4aa7..69b30dd 100644
@@ -69,6 +69,15 @@
 			status = "okay";
 		};
 
+		mmc2: mmc at 01c11000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc2_pins>, <&mmc2_8bit_pins>;
+			vmmc-supply = <&reg_vcc3v0>;
+			bus-width = <8>;
+			non-removable;
+			status = "okay";
+		};
+
 		pio: pinctrl at 06000800 {
 			i2c3_pins_a: i2c3 at 0 {
 				/* Enable internal pull-up */
Signature · 1 line
2.1.3