[U-Boot] [PATCH 0/6] sunxi: update sun8i-emac driver DT binding

The Ethernet MAC used in newer Allwinner SoCs (H3, A64, H5) is about to get an upstream Linux driver very soon (it's already lurking in -next). To support the different binding used for that, enhance our U-Boot driver to be able to cope with both DT descriptions. This series contains two parts: Patch 1 and 2 make it easier for more A64 boards to use Ethernet, by renaming the existing sun50i-a64-pine64-plus-u-boot.dtsi add-on file to use a more generic name and symlinking each board to. This remains a kludge for now until the new Linux DT gets merged in. Patches 3 till 6 now enhance the DT parsing routine in the EMAC driver to teach it to cope with both the old and new style binding: - Allow the new pinctrl bindings. - Find the syscon address referenced by a phandle in "syscon". - Find the PHY node referenced by "phy-handle" (not just "phy"). - Adjust the syscon address according to the binding used. - Determine usage of the internal PHY by using the MII protocol.
So this series prepares U-Boot for merging in new Linux DTs later, which will describe the EMAC and PHY using the new binding instead.
Cheers, Andre.
Andre Przywara (6): sunxi: A64: dts: replace EMAC .dtsi with symlink sunxi: A64: dts: add Ethernet support for BPi-M64 and OPi-Win libfdt: add fdtdec_lookup_phandle_index() sunxi: GPIO: introduce sunxi_gpio_setup_dt_pins() net: sun8i-emac: use new, generic GPIO setup routine net: sun8i-emac: add support for new DT binding
arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi | 1 + arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi | 1 + arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi | 51 +---------- arch/arm/dts/sun50i-a64-rgmii-emac.dtsi | 50 +++++++++++ arch/arm/include/asm/arch-sunxi/gpio.h | 3 + arch/arm/mach-sunxi/pinmux.c | 79 +++++++++++++++++ drivers/net/sun8i_emac.c | 105 +++++++++++------------ include/fdtdec.h | 12 +++ lib/fdtdec.c | 16 +++- 9 files changed, 211 insertions(+), 107 deletions(-) create mode 120000 arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi create mode 120000 arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi mode change 100644 => 120000 arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi create mode 100644 arch/arm/dts/sun50i-a64-rgmii-emac.dtsi

Currently we add the U-Boot specific Ethernet MAC DT nodes for the Pine64 via a board-specific add-on .dtsi. However these nodes and properties in there are actually pretty generic for all A64 boards which use a PHY connected via RGMII. Rename the add-on .dtsi to reflect this and make the Pine64 .dtsi a symlink to this new file. This simplifies letting other boards use the EMAC too.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi | 51 +------------------------ arch/arm/dts/sun50i-a64-rgmii-emac.dtsi | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 50 deletions(-) mode change 100644 => 120000 arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi create mode 100644 arch/arm/dts/sun50i-a64-rgmii-emac.dtsi
diff --git a/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi b/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi deleted file mode 100644 index 9c61bea..0000000 --- a/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi +++ /dev/null @@ -1,50 +0,0 @@ -/ { - aliases { - ethernet0 = &emac; - }; - - soc { - emac: ethernet@01c30000 { - compatible = "allwinner,sun50i-a64-emac"; - reg = <0x01c30000 0x2000>, <0x01c00030 0x4>; - reg-names = "emac", "syscon"; - interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; - resets = <&ccu RST_BUS_EMAC>; - reset-names = "ahb"; - clocks = <&ccu CLK_BUS_EMAC>; - clock-names = "ahb"; - #address-cells = <1>; - #size-cells = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&rgmii_pins>; - phy-mode = "rgmii"; - phy = <&phy1>; - status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; - }; - }; -}; - -&pio { - rmii_pins: rmii_pins { - allwinner,pins = "PD10", "PD11", "PD13", "PD14", - "PD17", "PD18", "PD19", "PD20", - "PD22", "PD23"; - allwinner,function = "emac"; - allwinner,drive = <3>; - allwinner,pull = <0>; - }; - - rgmii_pins: rgmii_pins { - allwinner,pins = "PD8", "PD9", "PD10", "PD11", - "PD12", "PD13", "PD15", - "PD16", "PD17", "PD18", "PD19", - "PD20", "PD21", "PD22", "PD23"; - allwinner,function = "emac"; - allwinner,drive = <3>; - allwinner,pull = <0>; - }; -}; diff --git a/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi b/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi new file mode 120000 index 0000000..350dc2b --- /dev/null +++ b/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi @@ -0,0 +1 @@ +sun50i-a64-rgmii-emac.dtsi \ No newline at end of file diff --git a/arch/arm/dts/sun50i-a64-rgmii-emac.dtsi b/arch/arm/dts/sun50i-a64-rgmii-emac.dtsi new file mode 100644 index 0000000..9c61bea --- /dev/null +++ b/arch/arm/dts/sun50i-a64-rgmii-emac.dtsi @@ -0,0 +1,50 @@ +/ { + aliases { + ethernet0 = &emac; + }; + + soc { + emac: ethernet@01c30000 { + compatible = "allwinner,sun50i-a64-emac"; + reg = <0x01c30000 0x2000>, <0x01c00030 0x4>; + reg-names = "emac", "syscon"; + interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; + resets = <&ccu RST_BUS_EMAC>; + reset-names = "ahb"; + clocks = <&ccu CLK_BUS_EMAC>; + clock-names = "ahb"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + phy-mode = "rgmii"; + phy = <&phy1>; + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; + }; +}; + +&pio { + rmii_pins: rmii_pins { + allwinner,pins = "PD10", "PD11", "PD13", "PD14", + "PD17", "PD18", "PD19", "PD20", + "PD22", "PD23"; + allwinner,function = "emac"; + allwinner,drive = <3>; + allwinner,pull = <0>; + }; + + rgmii_pins: rgmii_pins { + allwinner,pins = "PD8", "PD9", "PD10", "PD11", + "PD12", "PD13", "PD15", + "PD16", "PD17", "PD18", "PD19", + "PD20", "PD21", "PD22", "PD23"; + allwinner,function = "emac"; + allwinner,drive = <3>; + allwinner,pull = <0>; + }; +};

Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Currently we add the U-Boot specific Ethernet MAC DT nodes for the Pine64 via a board-specific add-on .dtsi. However these nodes and properties in there are actually pretty generic for all A64 boards which use a PHY connected via RGMII. Rename the add-on .dtsi to reflect this and make the Pine64 .dtsi a symlink to this new file. This simplifies letting other boards use the EMAC too.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi | 51 +------------------------ arch/arm/dts/sun50i-a64-rgmii-emac.dtsi | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 50 deletions(-) mode change 100644 => 120000 arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi create mode 100644 arch/arm/dts/sun50i-a64-rgmii-emac.dtsi
It seems odd to use the U-Boot dtsi feature to add code that should be in the kernel .dts also. Can we instead just #include it?
- Simon

Hi,
On 07/07/17 04:58, Simon Glass wrote:
Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Currently we add the U-Boot specific Ethernet MAC DT nodes for the Pine64 via a board-specific add-on .dtsi. However these nodes and properties in there are actually pretty generic for all A64 boards which use a PHY connected via RGMII. Rename the add-on .dtsi to reflect this and make the Pine64 .dtsi a symlink to this new file. This simplifies letting other boards use the EMAC too.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi | 51 +------------------------ arch/arm/dts/sun50i-a64-rgmii-emac.dtsi | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 50 deletions(-) mode change 100644 => 120000 arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi create mode 100644 arch/arm/dts/sun50i-a64-rgmii-emac.dtsi
It seems odd to use the U-Boot dtsi feature to add code that should be in the kernel .dts also. Can we instead just #include it?
This -u-boot.dtsi was just a preliminary kludge until the official Linux Ethernet support was merged. I was hoping for getting this still into the release, since it's an easy change and enables TFTP boot on the two boards (this patch here is just preparation for the actual patch 2/6).
So the Linux Ethernet driver happened to be merged yesterday. \O/ I promise to update U-Boot's DTs with the kernel one's once we have at least an -rc1 in the kernel (though this requires patch 6/6 in U-Boot). This will then see these rgmii-emac.dtsi and the symlinks go away.
Cheers, Andre.

On 7 July 2017 at 02:31, Andre Przywara andre.przywara@arm.com wrote:
Hi,
On 07/07/17 04:58, Simon Glass wrote:
Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Currently we add the U-Boot specific Ethernet MAC DT nodes for the Pine64 via a board-specific add-on .dtsi. However these nodes and properties in there are actually pretty generic for all A64 boards which use a PHY connected via RGMII. Rename the add-on .dtsi to reflect this and make the Pine64 .dtsi a symlink to this new file. This simplifies letting other boards use the EMAC too.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi | 51 +------------------------ arch/arm/dts/sun50i-a64-rgmii-emac.dtsi | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 50 deletions(-) mode change 100644 => 120000 arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi create mode 100644 arch/arm/dts/sun50i-a64-rgmii-emac.dtsi
It seems odd to use the U-Boot dtsi feature to add code that should be in the kernel .dts also. Can we instead just #include it?
This -u-boot.dtsi was just a preliminary kludge until the official Linux Ethernet support was merged. I was hoping for getting this still into the release, since it's an easy change and enables TFTP boot on the two boards (this patch here is just preparation for the actual patch 2/6).
So the Linux Ethernet driver happened to be merged yesterday. \O/ I promise to update U-Boot's DTs with the kernel one's once we have at least an -rc1 in the kernel (though this requires patch 6/6 in U-Boot). This will then see these rgmii-emac.dtsi and the symlinks go away.
OK I see, thanks.
Reviewed-by: Simon Glass sjg@chromium.org

Both the BananaPi-M64 and the OrangePi-Win use the same Gigabit Ethernet configuration as the Pine64. Use the new generic add-on .dtsi file and have symlinks for each board to enable TFTP boot on these boards.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi | 1 + arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi | 1 + 2 files changed, 2 insertions(+) create mode 120000 arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi create mode 120000 arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi
diff --git a/arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi b/arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi new file mode 120000 index 0000000..350dc2b --- /dev/null +++ b/arch/arm/dts/sun50i-a64-bananapi-m64-u-boot.dtsi @@ -0,0 +1 @@ +sun50i-a64-rgmii-emac.dtsi \ No newline at end of file diff --git a/arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi b/arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi new file mode 120000 index 0000000..350dc2b --- /dev/null +++ b/arch/arm/dts/sun50i-a64-orangepi-win-u-boot.dtsi @@ -0,0 +1 @@ +sun50i-a64-rgmii-emac.dtsi \ No newline at end of file

In some bindings a property points to multiple nodes, using a list of phandles. A prominent example are UART pinctrl nodes, which use one node to contain the RX/TX pins and another node to describe the lines used for the hardware handshake. The current fdtdec_lookup_phandle() helper function to chase a phandle is quite convienent, but can only lookup the first of those handles.
Introduce an extra function fdtdec_lookup_phandle_index() to take an index parameter and implement fdtdec_lookup_phandle() as a special case of that.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- include/fdtdec.h | 12 ++++++++++++ lib/fdtdec.c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/include/fdtdec.h b/include/fdtdec.h index eda2ffa..529e0fe 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -650,6 +650,18 @@ int fdtdec_get_chosen_node(const void *blob, const char *name); */ const char *fdtdec_get_compatible(enum fdt_compat_id id);
+/* Look up a phandle with a given index and follow it to its node. + * Then return the offset of that node. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param index index of the desired phandle in the list + * @return node offset if found, -ve error code on error + */ +int fdtdec_lookup_phandle_index(const void *blob, int node, + const char *prop_name, int index); + /* Look up a phandle and follow it to its node. Then return the offset * of that node. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 91503b8..e028a09 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -617,20 +617,28 @@ int fdtdec_prepare_fdt(void) return 0; }
-int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) +int fdtdec_lookup_phandle_index(const void *blob, int node, + const char *prop_name, int index) { const u32 *phandle; int lookup; + int length;
debug("%s: %s\n", __func__, prop_name); - phandle = fdt_getprop(blob, node, prop_name, NULL); - if (!phandle) + phandle = fdt_getprop(blob, node, prop_name, &length); + if (!phandle || index * 4 >= length) return -FDT_ERR_NOTFOUND;
- lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); + lookup = fdt_node_offset_by_phandle(blob, + fdt32_to_cpu(phandle[index])); return lookup; }
+int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) +{ + return fdtdec_lookup_phandle_index(blob, node, prop_name, 0); +} + /** * Look up a property in a node and check that it has a minimum length. *

Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
In some bindings a property points to multiple nodes, using a list of phandles. A prominent example are UART pinctrl nodes, which use one node to contain the RX/TX pins and another node to describe the lines used for the hardware handshake. The current fdtdec_lookup_phandle() helper function to chase a phandle is quite convienent, but can only lookup the first of those handles.
Introduce an extra function fdtdec_lookup_phandle_index() to take an index parameter and implement fdtdec_lookup_phandle() as a special case of that.
Signed-off-by: Andre Przywara andre.przywara@arm.com
include/fdtdec.h | 12 ++++++++++++ lib/fdtdec.c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-)
Can you please:
- Add a dev_read... version of this API - Also ofnode_...
so that we can support livetree.
Regards, Simon

On 07/07/17 04:58, Simon Glass wrote:
Hi Simon,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
In some bindings a property points to multiple nodes, using a list of phandles. A prominent example are UART pinctrl nodes, which use one node to contain the RX/TX pins and another node to describe the lines used for the hardware handshake. The current fdtdec_lookup_phandle() helper function to chase a phandle is quite convienent, but can only lookup the first of those handles.
Introduce an extra function fdtdec_lookup_phandle_index() to take an index parameter and implement fdtdec_lookup_phandle() as a special case of that.
Signed-off-by: Andre Przywara andre.przywara@arm.com
include/fdtdec.h | 12 ++++++++++++ lib/fdtdec.c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-)
Can you please:
- Add a dev_read... version of this API
- Also ofnode_...
Mmmh, I am not sure I follow here. I find that both dev_read_phandle_with_args() and ofnode_parse_phandle_with_args() take an index parameter already and from briefly looking at the code seem to do the right thing already. So I guess that's not what you meant? What am I missing?
Cheers, Andre.

Instead of hard-coding GPIO pins used for a certain peripheral, we should just use the pinctrl information from the DT. The sun8i-emac driver has some simple implementation of that, so let's just generalize this and copy the code to a more common location. On the way we add support for the new, generic pinctrl binding now used by all Allwinner SoCs.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- arch/arm/include/asm/arch-sunxi/gpio.h | 3 ++ arch/arm/mach-sunxi/pinmux.c | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 24f8520..b5a4b32 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -240,4 +240,7 @@ int axp_gpio_init(void); static inline int axp_gpio_init(void) { return 0; } #endif
+int sunxi_gpio_setup_dt_pins(const void * volatile fdt_blob, int node, + int mux_sel); + #endif /* _SUNXI_GPIO_H */ diff --git a/arch/arm/mach-sunxi/pinmux.c b/arch/arm/mach-sunxi/pinmux.c index b026f78..ae36fe9 100644 --- a/arch/arm/mach-sunxi/pinmux.c +++ b/arch/arm/mach-sunxi/pinmux.c @@ -9,6 +9,9 @@ #include <common.h> #include <asm/io.h> #include <asm/arch/gpio.h> +#include <fdtdec.h> +#include <fdt_support.h> +#include <dt-bindings/pinctrl/sun4i-a10.h>
void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val) { @@ -69,3 +72,79 @@ int sunxi_gpio_set_pull(u32 pin, u32 val)
return 0; } + +static int sunxi_gpio_setup_single_node(const void * volatile fdt_blob, + int offset, int mux_sel) +{ + int drive, pull, pin, i; + const char *pin_name; + + drive = fdt_getprop_u32_default_node(fdt_blob, offset, 0, + "drive-strength", ~0); + if (drive != ~0) { + if (drive <= 10) + drive = SUN4I_PINCTRL_10_MA; + else if (drive <= 20) + drive = SUN4I_PINCTRL_20_MA; + else if (drive <= 30) + drive = SUN4I_PINCTRL_30_MA; + else + drive = SUN4I_PINCTRL_40_MA; + } else { + drive = fdt_getprop_u32_default_node(fdt_blob, offset, 0, + "allwinner,drive", ~0); + } + + if (fdt_get_property(fdt_blob, offset, "bias-pull-up", NULL)) + pull = SUN4I_PINCTRL_PULL_UP; + else if (fdt_get_property(fdt_blob, offset, "bias-disable", NULL)) + pull = SUN4I_PINCTRL_NO_PULL; + else if (fdt_get_property(fdt_blob, offset, "bias-pull-down", NULL)) + pull = SUN4I_PINCTRL_PULL_DOWN; + else + pull = fdt_getprop_u32_default_node(fdt_blob, offset, 0, + "allwinner,pull", ~0); + + for (i = 0; ; i++) { + pin_name = fdt_stringlist_get(fdt_blob, offset, + "allwinner,pins", i, NULL); + if (!pin_name) { + pin_name = fdt_stringlist_get(fdt_blob, offset, + "pins", i, NULL); + if (!pin_name) + break; + } + pin = sunxi_name_to_gpio(pin_name); + if (pin < 0) + continue; + + sunxi_gpio_set_cfgpin(pin, mux_sel); + if (drive != ~0) + sunxi_gpio_set_drv(pin, drive); + if (pull != ~0) + sunxi_gpio_set_pull(pin, pull); + } + + return i; +} + +int sunxi_gpio_setup_dt_pins(const void * volatile fdt_blob, int node, + int mux_sel) +{ + int offset, pins = 0, idx; + + for (idx = 0; ; idx++) { + offset = fdtdec_lookup_phandle_index(fdt_blob, node, + "pinctrl-0", idx); + if (offset < 0) { + if (idx == 0) + return offset; + + return pins; + } + + pins += sunxi_gpio_setup_single_node(fdt_blob, offset, mux_sel); + } + + return pins; +}

Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Instead of hard-coding GPIO pins used for a certain peripheral, we should just use the pinctrl information from the DT. The sun8i-emac driver has some simple implementation of that, so let's just generalize this and copy the code to a more common location. On the way we add support for the new, generic pinctrl binding now used by all Allwinner SoCs.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/include/asm/arch-sunxi/gpio.h | 3 ++ arch/arm/mach-sunxi/pinmux.c | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
It looks like this should be done with a pinctrl driver, shouldn't it?
Regards, Simon

Hi Simon,
On 07/07/17 04:58, Simon Glass wrote:
Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Instead of hard-coding GPIO pins used for a certain peripheral, we should just use the pinctrl information from the DT. The sun8i-emac driver has some simple implementation of that, so let's just generalize this and copy the code to a more common location. On the way we add support for the new, generic pinctrl binding now used by all Allwinner SoCs.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/include/asm/arch-sunxi/gpio.h | 3 ++ arch/arm/mach-sunxi/pinmux.c | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
It looks like this should be done with a pinctrl driver, shouldn't it?
I knew you would say this ;-)
So technically you are right, but it looks like this is quite some work. And as patch 5/6 demonstrates, this code here was actually already mostly in, so this is basically just moving and generalisation.
The whole purpose of this series is to prepare for merging in the Linux 4.13-rc1 DTs and still have working Ethernet, so I wanted to keep the bar low on this.
I haven't looked in detail what it would take to have a proper Allwinner pinctrl DM driver, but the binding Linux uses is not "self-contained", as we still need SoC specific knowledge (namely into which actual mux value the "emac" string, for instance, translates to; and this is per SoC and pin). So that means pulling *a lot of* tables into U-Boot, which I am not sure is worth at this point. We might get away with some short-cuts, basically keeping our hard coded mux values around or just defining those that we actually need. But in general I consider this work more long term, and it should not halt the more important goal of having the Linux and U-Boot DTs in sync.
Cheers, Andre.

+Tom
On 7 July 2017 at 04:30, Andre Przywara andre.przywara@arm.com wrote:
Hi Simon,
On 07/07/17 04:58, Simon Glass wrote:
Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Instead of hard-coding GPIO pins used for a certain peripheral, we should just use the pinctrl information from the DT. The sun8i-emac driver has some simple implementation of that, so let's just generalize this and copy the code to a more common location. On the way we add support for the new, generic pinctrl binding now used by all Allwinner SoCs.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/include/asm/arch-sunxi/gpio.h | 3 ++ arch/arm/mach-sunxi/pinmux.c | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
It looks like this should be done with a pinctrl driver, shouldn't it?
I knew you would say this ;-)
So technically you are right, but it looks like this is quite some work. And as patch 5/6 demonstrates, this code here was actually already mostly in, so this is basically just moving and generalisation.
The whole purpose of this series is to prepare for merging in the Linux 4.13-rc1 DTs and still have working Ethernet, so I wanted to keep the bar low on this.
I haven't looked in detail what it would take to have a proper Allwinner pinctrl DM driver, but the binding Linux uses is not "self-contained", as we still need SoC specific knowledge (namely into which actual mux value the "emac" string, for instance, translates to; and this is per SoC and pin). So that means pulling *a lot of* tables into U-Boot, which I am not sure is worth at this point. We might get away with some short-cuts, basically keeping our hard coded mux values around or just defining those that we actually need. But in general I consider this work more long term, and it should not halt the more important goal of having the Linux and U-Boot DTs in sync.
With a due sense of foreboding and dread:
Reviewed-by: Simon Glass sjg@chromium.org
Cheers, Andre.

On 14 Jul 2017, at 15:50, Simon Glass sjg@chromium.org wrote:
+Tom
On 7 July 2017 at 04:30, Andre Przywara <andre.przywara@arm.com mailto:andre.przywara@arm.com> wrote:
Hi Simon,
On 07/07/17 04:58, Simon Glass wrote:
Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
Instead of hard-coding GPIO pins used for a certain peripheral, we should just use the pinctrl information from the DT. The sun8i-emac driver has some simple implementation of that, so let's just generalize this and copy the code to a more common location. On the way we add support for the new, generic pinctrl binding now used by all Allwinner SoCs.
Signed-off-by: Andre Przywara andre.przywara@arm.com
arch/arm/include/asm/arch-sunxi/gpio.h | 3 ++ arch/arm/mach-sunxi/pinmux.c | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
It looks like this should be done with a pinctrl driver, shouldn't it?
I knew you would say this ;-)
So technically you are right, but it looks like this is quite some work. And as patch 5/6 demonstrates, this code here was actually already mostly in, so this is basically just moving and generalisation.
The whole purpose of this series is to prepare for merging in the Linux 4.13-rc1 DTs and still have working Ethernet, so I wanted to keep the bar low on this.
I haven't looked in detail what it would take to have a proper Allwinner pinctrl DM driver, but the binding Linux uses is not "self-contained", as we still need SoC specific knowledge (namely into which actual mux value the "emac" string, for instance, translates to; and this is per SoC and pin). So that means pulling *a lot of* tables into U-Boot, which I am not sure is worth at this point. We might get away with some short-cuts, basically keeping our hard coded mux values around or just defining those that we actually need. But in general I consider this work more long term, and it should not halt the more important goal of having the Linux and U-Boot DTs in sync.
With a due sense of foreboding and dread:
Reviewed-by: Simon Glass <sjg@chromium.org mailto:sjg@chromium.org>
I had submitted a DM driver to do this a long time ago, which included these tables for the A64 (and had the necessary infrastructure to quickly add other boards).
This was still tight enough, even to fit into an AArch64 SPL stage.
So I don’t see the purpose of not doing a DM pinctrl for sunxi, as the tables can easily be shared between U-Boot and Linux—i.e. I had used the Linux tables verbatim and only added a few lines of wrapper for U-Boot.
Regards, Philipp.

Instead of open-coding the fairly generic pinmux setup in the sun8i-emac driver, let's just use the new common implementation of that. This has also the advantage of supporting the new, generic pinctrl bindings, so the driver can cope with the upstream Linux DTs.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- drivers/net/sun8i_emac.c | 54 +++++++----------------------------------------- 1 file changed, 8 insertions(+), 46 deletions(-)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 09bbb2c..af77134 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -451,50 +451,6 @@ static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr) return 0; }
-static int parse_phy_pins(struct udevice *dev) -{ - int offset; - const char *pin_name; - int drive, pull, i; - - offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), - "pinctrl-0"); - if (offset < 0) { - printf("WARNING: emac: cannot find pinctrl-0 node\n"); - return offset; - } - - drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, - "allwinner,drive", 4); - pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, - "allwinner,pull", 0); - for (i = 0; ; i++) { - int pin; - - pin_name = fdt_stringlist_get(gd->fdt_blob, offset, - "allwinner,pins", i, NULL); - if (!pin_name) - break; - if (pin_name[0] != 'P') - continue; - pin = (pin_name[1] - 'A') << 5; - if (pin >= 26 << 5) - continue; - pin += simple_strtol(&pin_name[2], NULL, 10); - - sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC); - sunxi_gpio_set_drv(pin, drive); - sunxi_gpio_set_pull(pin, pull); - } - - if (!i) { - printf("WARNING: emac: cannot find allwinner,pins property\n"); - return -2; - } - - return 0; -} - static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp) { u32 status, desc_num = priv->rx_currdescnum; @@ -816,8 +772,14 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
priv->interface = pdata->phy_interface;
- if (!priv->use_internal_phy) - parse_phy_pins(dev); + if (!priv->use_internal_phy) { + ret = sunxi_gpio_setup_dt_pins(gd->fdt_blob, dev_of_offset(dev), + SUN8I_GPD8_GMAC); + if (ret < 0) { + printf("%s: cannot setup pinmuxes\n", __func__); + return -EINVAL; + } + }
#ifdef CONFIG_DM_GPIO if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),

The Ethernet MAC used in newer Allwinner SoCs (H3, A64, H5) is about to get an upstream Linux driver very soon (it's already lurking in -next). This one uses a slightly different binding from the original one used by the U-Boot driver. The differences to the old binding are: - The "syscon" address is held in a separate node, referenced via a phandle in the "syscon" property. - The reference to the PHY is held in a property called "phy-handle", not "phy". - The PHY register is at offset 0x30 in the syscon device, not at 0. - The internal PHY is activated when a capable SoC selects MII mode.
Teach the U-Boot driver how to find its resources in a "new-style" DT, so that we can use a Linux kernel compatible DT for U-Boot as well. This keeps support for the old binding (for now?), to allow a smooth transition.
Signed-off-by: Andre Przywara andre.przywara@arm.com --- drivers/net/sun8i_emac.c | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index af77134..8320518 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -278,7 +278,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) int ret; u32 reg;
- reg = readl(priv->sysctl_reg); + reg = readl(priv->sysctl_reg + 0x30);
if (priv->variant == H3_EMAC) { ret = sun8i_emac_set_syscon_ephy(priv, ®); @@ -309,7 +309,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) return -EINVAL; }
- writel(reg, priv->sysctl_reg); + writel(reg, priv->sysctl_reg + 0x30);
return 0; } @@ -733,17 +733,50 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) #endif
pdata->iobase = devfdt_get_addr_name(dev, "emac"); + if (pdata->iobase == FDT_ADDR_T_NONE) + pdata->iobase = devfdt_get_addr(dev); + if (pdata->iobase == FDT_ADDR_T_NONE) { + debug("%s: Cannot find MAC base address\n", __func__); + return -EINVAL; + } + priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon"); + if (priv->sysctl_reg == FDT_ADDR_T_NONE) { + const fdt32_t *reg; + + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon"); + if (offset < 0) { + debug("%s: cannot find syscon node\n", __func__); + return -EINVAL; + } + reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL); + if (!reg) { + debug("%s: cannot find reg property in syscon node\n", + __func__); + return -EINVAL; + } + priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob, + offset, reg); + } else + priv->sysctl_reg -= 0x30; + if (priv->sysctl_reg == FDT_ADDR_T_NONE) { + debug("%s: Cannot find syscon base address\n", __func__); + return -EINVAL; + }
pdata->phy_interface = -1; priv->phyaddr = -1; priv->use_internal_phy = false;
- offset = fdtdec_lookup_phandle(gd->fdt_blob, node, - "phy"); - if (offset > 0) - priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", - -1); + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy"); + if (offset < 0) + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, + "phy-handle"); + if (offset < 0) { + debug("%s: Cannot find PHY address\n", __func__); + return -EINVAL; + } + priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
@@ -768,6 +801,10 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) if (fdt_getprop(gd->fdt_blob, node, "allwinner,use-internal-phy", NULL)) priv->use_internal_phy = true; + else { + if (pdata->phy_interface == PHY_INTERFACE_MODE_MII) + priv->use_internal_phy = true; + } }
priv->interface = pdata->phy_interface;

Hi Andre,
On 2 July 2017 at 18:59, Andre Przywara andre.przywara@arm.com wrote:
The Ethernet MAC used in newer Allwinner SoCs (H3, A64, H5) is about to get an upstream Linux driver very soon (it's already lurking in -next). This one uses a slightly different binding from the original one used by the U-Boot driver. The differences to the old binding are:
- The "syscon" address is held in a separate node, referenced via a phandle in the "syscon" property.
- The reference to the PHY is held in a property called "phy-handle", not "phy".
- The PHY register is at offset 0x30 in the syscon device, not at 0.
- The internal PHY is activated when a capable SoC selects MII mode.
Teach the U-Boot driver how to find its resources in a "new-style" DT, so that we can use a Linux kernel compatible DT for U-Boot as well. This keeps support for the old binding (for now?), to allow a smooth transition.
Signed-off-by: Andre Przywara andre.przywara@arm.com
drivers/net/sun8i_emac.c | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index af77134..8320518 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -278,7 +278,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) int ret; u32 reg;
reg = readl(priv->sysctl_reg);
reg = readl(priv->sysctl_reg + 0x30); if (priv->variant == H3_EMAC) { ret = sun8i_emac_set_syscon_ephy(priv, ®);
@@ -309,7 +309,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) return -EINVAL; }
writel(reg, priv->sysctl_reg);
writel(reg, priv->sysctl_reg + 0x30); return 0;
} @@ -733,17 +733,50 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) #endif
pdata->iobase = devfdt_get_addr_name(dev, "emac");
if (pdata->iobase == FDT_ADDR_T_NONE)
pdata->iobase = devfdt_get_addr(dev);
if (pdata->iobase == FDT_ADDR_T_NONE) {
debug("%s: Cannot find MAC base address\n", __func__);
return -EINVAL;
}
priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon");
Can we use a syscon driver for this instead?
Then there is syscon_get_first_range().
[...]
Regards, Simon
participants (4)
-
Andre Przywara
-
André Przywara
-
Dr. Philipp Tomsich
-
Simon Glass