[U-Boot] [PATCH v1 00/11] sunxi: DM drivers for CLK, RESET and PINCTRL

This provides DM drivers for CLK, RESET and PINCTRL for sunxi with initial enablement and testing done on the sun50iw1p1 (A64). As the sun6i, sun8i and sun9i platforms are similar enough, these should be easily added on top of this framework.
To make switching over easier, the necessary changes in the MMC drivers and sun8i_emac are also contained as individual changes in this set.
At this point, I'd like to see sunxi move towards a TPL approach as the SRAM area used by the BROM for loading the SPL is too small for both FIT and DM... yet most Allwinner SoCs have largish SRAM areas that could be used for a TPL (even one that could use config data to set up the DRAM according to a specific board's requirements). If we could get that point, we should be able to get rid of most of the chip and board-specific (i.e. watch for low-fying #ifdef's) pinconfig code in board/sunxi/board.c.
This changeset was tested against the A64-uQ7 (with our DTS, which is to date only available from our public git repositories) for the following devices: * MMC0 (uSD slot) and MMC2 (on-module eMMC) * Ethernet (sun8i_emac) * SPI (SPI DM driver from the A31-uQ7 tree, will post separately) * GPIO
The sunxi I2C driver still needs to be converted to make use of these changes.
Philipp Tomsich (11): spl: dm: Undefine DM_MMC, DM_MMC_OPS and BLK, if SPL_DM is not defined sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi and tie back into GPIO sun50i: dts: add gpiobank nodes to the pinctrl nodes sun50i: dts: update DTS to avoid warnings sunxi: add module reset (UCLASS_RESET) support for sunxi sunxi: add clock driver (UCLASS_CLK) support for sunxi sunxi: Scan DT tree node '/clocks' on sunxi boards sun8i_emac: update to work with pinctrl-sunxi, reset-sunxi and clk-sunxi sunxi_mmc: convert to a device-model driver dts: sun50i: update mmc pin configuration and add mmc2_8bit_pins sun50i: dts: add spi0 and spi1 nodes and pinconfig
arch/arm/dts/sun50i-a64.dtsi | 171 +++++- board/sunxi/board.c | 20 +- .../pinctrl/allwinner,pinctrl.txt | 130 +++++ drivers/clk/Makefile | 1 + drivers/clk/sunxi/Makefile | 7 + drivers/clk/sunxi/clk-sunxi-gate.c | 92 ++++ drivers/clk/sunxi/clk-sunxi-mod.c | 232 +++++++++ drivers/clk/sunxi/clk-sunxi-pll.c | 120 +++++ drivers/gpio/sunxi_gpio.c | 94 +++- drivers/mmc/sunxi_mmc.c | 344 +++++++++++- drivers/net/sun8i_emac.c | 45 +- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/sunxi/Makefile | 10 + drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c | 92 ++++ drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 577 +++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 309 +++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ drivers/reset/Kconfig | 9 + drivers/reset/Makefile | 1 + drivers/reset/reset-sunxi.c | 105 ++++ include/config_uncmd_spl.h | 4 + scripts/Makefile.uncmd_spl | 4 + 23 files changed, 2632 insertions(+), 58 deletions(-) create mode 100644 doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt create mode 100644 drivers/clk/sunxi/Makefile create mode 100644 drivers/clk/sunxi/clk-sunxi-gate.c create mode 100644 drivers/clk/sunxi/clk-sunxi-mod.c create mode 100644 drivers/clk/sunxi/clk-sunxi-pll.c create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h create mode 100644 drivers/reset/reset-sunxi.c

CONFIG_DM_MMC, CONFIG_DM_MMC_OPS and CONFIG_BLK depend on CONFIG_DM (CONFIG_SPL_DM); if either is enabled, but CONFIG_SPL_DM is disabled, we also need to undef them.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- include/config_uncmd_spl.h | 4 ++++ scripts/Makefile.uncmd_spl | 4 ++++ 2 files changed, 8 insertions(+)
diff --git a/include/config_uncmd_spl.h b/include/config_uncmd_spl.h index 3c1499c..06498a4 100644 --- a/include/config_uncmd_spl.h +++ b/include/config_uncmd_spl.h @@ -1,25 +1,29 @@ /* * (C) Copyright 2012 * Ilya Yanok, ilya.yanok@gmail.com * * SPDX-License-Identifier: GPL-2.0+ */
#ifndef __CONFIG_UNCMD_SPL_H__ #define __CONFIG_UNCMD_SPL_H__
#ifdef CONFIG_SPL_BUILD /* SPL needs only BOOTP + TFTP so undefine other stuff to save space */
#ifndef CONFIG_SPL_DM #undef CONFIG_DM_SERIAL #undef CONFIG_DM_GPIO #undef CONFIG_DM_I2C #undef CONFIG_DM_SPI +#undef CONFIG_DM_MMC +#undef CONFIG_DM_MMC_OPS +/* CONFIG_BLK also depends on DM */ +#undef CONFIG_BLK #endif
#undef CONFIG_DM_WARN #undef CONFIG_DM_STDIO
#endif /* CONFIG_SPL_BUILD */ #endif /* __CONFIG_UNCMD_SPL_H__ */ diff --git a/scripts/Makefile.uncmd_spl b/scripts/Makefile.uncmd_spl index 15d0836..99b9dee 100644 --- a/scripts/Makefile.uncmd_spl +++ b/scripts/Makefile.uncmd_spl @@ -12,6 +12,10 @@ CONFIG_DM_GPIO= CONIFG_DM_I2C= CONFIG_DM_SPI= CONFIG_DM_SPI_FLASH= +CONFIG_DM_MMC= +CONFIG_DM_MMC_OPS= +# CONFIG_BLK also depends on CONFIG_DM +CONFIG_BLK= endif
endif

This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are: * implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it * defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms: - As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device. - For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure. * lifts and reuses the pinctrl-sunxi.h and pinctrl-sun50i-a64.c files from Linux (thanks to Maxime and Andre) and adds a pinctrl-sun50i-a64-r.c (to be picked up for inclusion into Linux again)
The active DM tree at runtime (with this enabled) should look similar to the following:
pinctrl [ + ] | |-- pinctrl@1c20800 gpio [ + ] | | |-- gpiob@24 gpio [ + ] | | |-- gpioc@48 gpio [ + ] | | |-- gpiod@6c gpio [ + ] | | |-- gpioe@90 gpio [ + ] | | |-- gpiof@b4 gpio [ + ] | | |-- gpiog@d8 gpio [ + ] | | |-- gpioh@fc pinconfig [ + ] | | |-- uart0_pins_a pinconfig [ ] | | |-- uart0_pins_b pinconfig [ ] | | |-- uart1_2pins pinconfig [ ] | | |-- uart1_4pins pinconfig [ ] | | |-- uart2_2pins pinconfig [ ] | | |-- uart2_4 pinconfig [ ] | | |-- uart3 pinconfig [ ] | | |-- uart3_2 pinconfig [ ] | | |-- uart3_4 pinconfig [ ] | | |-- uart4_2 pinconfig [ ] | | |-- uart4_4 pinconfig [ + ] | | |-- mmc0 pinconfig [ + ] | | |-- mmc0_cd_pin pinconfig [ ] | | |-- mmc1 pinconfig [ ] | | |-- mmc2 pinconfig [ + ] | | |-- mmc2_8bit pinconfig [ ] | | |-- i2c0_pins pinconfig [ ] | | |-- i2c1_pins pinconfig [ ] | | |-- i2c2_pins pinconfig [ ] | | |-- rmii_pins pinconfig [ + ] | | |-- rgmii_pins pinconfig [ + ] | | |-- spi0_pins pinconfig [ ] | | |-- spi1_pins pinconfig [ + ] | | |-- led_pins_sdio pinconfig [ + ] | | |-- ethphy_reset_pin gpio [ + ] | | `-- gpiobridge pinctrl [ + ] | |-- pinctrl@01f02c00 gpio [ + ] | | |-- gpiol@0 pinconfig [ + ] | | |-- led_pins_power gpio [ + ] | | `-- gpiobridge
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- .../pinctrl/allwinner,pinctrl.txt | 130 +++++ drivers/gpio/sunxi_gpio.c | 97 +++- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/sunxi/Makefile | 10 + drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c | 92 ++++ drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 577 +++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 326 ++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 9 files changed, 1553 insertions(+), 2 deletions(-) create mode 100644 doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h
diff --git a/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt new file mode 100644 index 0000000..e536ea3 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,130 @@ +* Allwinner Pinmux Controller + +Allwinner integrates multiple banks (of 32 pins each) of pin-muxing, +GPIO functionality and (optional) external interrupt functionality +into a single controller. + +For each configurable pad (certain driver-cells, such as the IO from +integrated USB PHYs or DRAM, have a fixed function and can not be +configured), the muxing options (input, output or one of the several +functions) can be selected. + +The Allwinner pinctrl node contains a description of the pinctrl block +(i.e. including GPIO and external interrupt capability, if available) +and subnodes describing individual GPIO banks and pin-configuration. + +Properties for the pinctrl node: + - compatible: should be "allwinner,sun50i-pinctrl" + - reg: address and length of the register set for the device. + - interrupts: interrupt for the device + - clocks: A phandle to the reference clock for this device + +Properties for the pinconfig sub-nodes: + - allwinner,pins: a list of pins (e.g. "PH2", "PH3") to configure + - allwinner,function: the name of pinmux function (e.g. "mmc2") + - drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA + - bias-pull-up + - bias-pull-down + - bias-disable (default) + +Deprecated properties for the pinconfig sub-nodes: + - allwinner,drive: one of <SUN4I_PINCTRL_10_MA>, <SUN4I_PINCTRL_20_MA>, + <SUN4I_PINCTRL_30_MA> or <SUN4I_PINCTRL_40_MA> + - allwinner,pull: one of <SUN4I_PINCTRL_NO_PULL>, <SUN4I_PINCTRL_PULL_UP> + or <SUN4I_PINCTRL_PULL_DOWN> + +Properties for the gpio sub-nodes: + - compatible: should be "allwinner,sunxi-gpiobank" + - allwinner,gpiobank-name: the name of the bank (e.g. <'A'>, <'B'>, ...) + - reg: offsets (within the address range of the enclosing pinctrl + node's address space) and length of the registers, where + * The first entry points to the mux/gpio registers. + * An (optional) second entry points to the extint registers. + Note, that the second entry should be provided, if the + interrupt property is present. + - interrupt: the interrupt used for external interrupt signalling + (should be one of the interrupts specified in the + enclosing pinctrl node) + +Example: + + pio: pinctrl@1c20800 { + compatible = "allwinner,sun50i-a64-pinctrl"; + reg = <0x01c20800 0x400>; + + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&bus_gates 69>; + + gpio-controller; + #gpio-cells = <3>; + + interrupt-controller; + #interrupt-cells = <2>; + + #address-cells = <1>; + #size-cells = <1>; + + /* The A64 does not have bank A and leaves a hole in the + address space where it normally would be */ + + gpiob: gpiob@24 { + compatible = "allwinner,sunxi-gpiobank"; + allwinner,gpiobank-name = <'B'>; + reg = < 0x24 0x24 >, < 0x200 0x1c >; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpioc: gpioc@48 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x48 0x24 >; + allwinner,gpiobank-name = <'C'>; + }; + + gpiod: gpiod@6c { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x6c 0x24 >; + allwinner,gpiobank-name = <'D'>; + }; + + gpioe: gpioe@90 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x90 0x24 >; + allwinner,gpiobank-name = <'E'>; + }; + + gpiof: gpiof@b4 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xb4 0x24 >; + allwinner,gpiobank-name = <'F'>; + }; + + gpiog: gpiog@d8 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xd8 0x24 >, < 0x220 0x1c >; + allwinner,gpiobank-name = <'G'>; + interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpioh: gpioh@fc { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xfc 0x24 >, < 0x220 0x1c >; + allwinner,gpiobank-name = <'H'>; + interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0_pins_a: uart0_pins_a { + allwinner,pins = "PB8", "PB9"; + allwinner,function = "uart0"; + allwinner,drive = <SUN4I_PINCTRL_10_MA>; + allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + }; + + uart0_pins_b: uart0_pins_b { + allwinner,pins = "PF2", "PF3"; + allwinner,function = "uart0"; + allwinner,drive = <SUN4I_PINCTRL_10_MA>; + allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + }; + }; diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 2b7bc7f..6cf2be4 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -344,36 +344,129 @@ static const struct sunxi_gpio_soc_data soc_data_l_3 = { static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun4i-a10-pinctrl", a_all), ID("allwinner,sun5i-a10s-pinctrl", a_all), ID("allwinner,sun5i-a13-pinctrl", a_all), ID("allwinner,sun6i-a31-pinctrl", a_all), ID("allwinner,sun6i-a31s-pinctrl", a_all), ID("allwinner,sun7i-a20-pinctrl", a_all), ID("allwinner,sun8i-a23-pinctrl", a_all), ID("allwinner,sun8i-a33-pinctrl", a_all), ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), +#if !defined(CONFIG_SUNXI_PINCTRL) /* This is not strictly correct for the A64, as it is missing * bank 'A'. Yet, the register layout in the pinctrl block is * backward compatible and any accesses to the registers that * normally control bank 'A' will have no adverse effect. */ - ID("allwinner,sun50i-a64-pinctrl", a_all), + ID("allwinner,sun50i-a64-pinctrl", a_all), +#endif ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3), - ID("allwinner,sun50i-a64-r-pinctrl", l_1), +#if !defined(CONFIG_SUNXI_PINCTRL) + ID("allwinner,sun50i-a64-r-pinctrl", l_1), +#endif { } };
U_BOOT_DRIVER(gpio_sunxi) = { .name = "gpio_sunxi", .id = UCLASS_GPIO, .ops = &gpio_sunxi_ops, .of_match = sunxi_gpio_ids, .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, }; + +#if defined(CONFIG_SUNXI_PINCTRL) + +/* When we use the sunxi pinctrl infrastructure, we have two issues that + * are resolved by the gpiobank and gpiobrige drivers: + * + * - We need to have a UCLASS_GPIO device bound to the pinctrl-nodes for + * translating between gpio entries (e.g. <&pio 3 24 GPIO_ACTIVE_LOW>;) + * in the DT and actual gpio banks. This is done using the gpiobridge + * driver, which provides only a lookup/translation mechanism. + * This mechanism lives in pinctrl-sunxi.c + * + * - We introduce a generic gpiobank device, which resolves the need to + * have distinct soc_data structure for each device and avoids having + * to share data structures and config data between this file and the + * sunxi pinctrl (the other option would be to have the soc_data info + * visible in pinctrl-sunxi.c (or merge it into this file) and bind a + * gpio_sunxi device that is set up with the appropriate soc_data) to + * the same node as the pinctrl device. + */ + +static int gpiobank_sunxi_probe(struct udevice *dev) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int bank_name; + int bank; + fdt_addr_t offset; + fdt_size_t size; + fdt_addr_t base; + + debug("%s: %s", __func__, dev->name); + + /* At this time we are only interested in index 0 (the PIO registers) + and we ignore index 1 (the external interrupt control), even if + present and an interrupt property exists... */ + offset = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, + dev->of_offset, + "reg", 0, &size, + false); + if (offset == FDT_ADDR_T_NONE) { + error("%s: missing 'reg' for offset into parent device\n", + dev->name); + return -EINVAL; + } + + bank_name = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "allwinner,gpiobank-name", -EINVAL); + if (bank_name == -EINVAL) { + error("%s: missing 'allwinner,gpiobank-name'\n", dev->name); + return -EINVAL; + } + + base = dev_get_addr(dev->parent); + if (base == FDT_ADDR_T_NONE) { + error("%s: parent '%s' does not have a valid base address\n", + dev->name, dev->parent->name); + return -EINVAL; + } + + bank = bank_name - 'A'; + + plat->regs = (void *)(base + offset); + plat->gpio_count = SUNXI_GPIOS_PER_BANK; + plat->bank_name = gpio_bank_name(bank); + + /* Tell the uclass how many GPIOs we have */ + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + + return 0; +} + +static const struct udevice_id sunxi_gpiobank_ids[] = { + { .compatible = "allwinner,sunxi-gpiobank", }, + {} +}; + +U_BOOT_DRIVER(gpiobank_sunxi) = { + .name = "gpiobank_sunxi", + .id = UCLASS_GPIO, + .ops = &gpio_sunxi_ops, + .of_match = sunxi_gpiobank_ids, + .platdata_auto_alloc_size = sizeof(struct sunxi_gpio_platdata), + .probe = gpiobank_sunxi_probe, +}; + +#endif /* CONFIG_SUNXI_PINCTRL */ + #endif diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..064a682 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,16 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config SUNXI_PINCTRL + bool "Allwinner Axx pin-control and pin-mux driver" + depends on DM && ARCH_SUNXI + default y + help + Supports pin multiplexing control, drive-strength and bias control on + Allwinner Axx SoCs. The driver is controlled by a device tree node which + contains both the GPIO definitions and the pin control functions for + each multiplex function. + endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..da27a91 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,18 +1,20 @@ # # SPDX-License-Identifier: GPL-2.0+ #
obj-y += pinctrl-uclass.o obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ obj-$(CONFIG_ARCH_ATH79) += ath79/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/ + +obj-$(CONFIG_ARCH_SUNXI) += sunxi/ \ No newline at end of file diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile new file mode 100644 index 0000000..11549ec --- /dev/null +++ b/drivers/pinctrl/sunxi/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_SUNXI_PINCTRL) += pinctrl-sunxi.o +ifdef CONFIG_SUNXI_PINCTRL +obj-$(CONFIG_MACH_SUN50I) += pinctrl-sun50i-a64.o pinctrl-sun50i-a64-r.o +endif diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c new file mode 100644 index 0000000..864d1ec --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c @@ -0,0 +1,92 @@ +/* + * Allwinner A64 SoCs pinctrl driver. + * + * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH. + * + * Based on pinctrl-sun7i-a20.c, which is: + * Copyright (C) 2014 Maxime Ripard maxime.ripard@free-electrons.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin a64_r_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_rsb"), /* SCK */ + SUNXI_FUNCTION(0x3, "s_i2c"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_rsb"), /* SDA */ + SUNXI_FUNCTION(0x3, "s_i2c"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_uart"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_uart"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_jtag"), /* MS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_jtag"), /* CK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_jtag"), /* DO */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_jtag"), /* DI */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_i2c"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_i2c"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_pwm"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_cir"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* EINT12 */ +}; + +const struct sunxi_pinctrl_desc a64_r_pinctrl_data = { + .pins = a64_r_pins, + .npins = ARRAY_SIZE(a64_r_pins), + .pin_base = PL_BASE, + .irq_banks = 1, +}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c new file mode 100644 index 0000000..7abea03 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c @@ -0,0 +1,577 @@ +/* + * Allwinner A64 SoCs pinctrl driver. + * + * Copyright (C) 2016 - ARM Ltd. + * Author: Andre Przywara andre.przywara@arm.com + * + * Based on pinctrl-sun7i-a20.c, which is: + * Copyright (C) 2014 Maxime Ripard maxime.ripard@free-electrons.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin a64_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* TX */ + SUNXI_FUNCTION(0x4, "jtag"), /* MS0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RX */ + SUNXI_FUNCTION(0x4, "jtag"), /* CK0 */ + SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RTS */ + SUNXI_FUNCTION(0x4, "jtag"), /* DO0 */ + SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* CTS */ + SUNXI_FUNCTION(0x3, "i2s0"), /* MCLK */ + SUNXI_FUNCTION(0x4, "jtag"), /* DI0 */ + SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif2"), /* SYNC */ + SUNXI_FUNCTION(0x3, "i2s0"), /* SYNC */ + SUNXI_FUNCTION(0x5, "sim"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif2"), /* BCLK */ + SUNXI_FUNCTION(0x3, "i2s0"), /* BCLK */ + SUNXI_FUNCTION(0x5, "sim"), /* DATA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif2"), /* DOUT */ + SUNXI_FUNCTION(0x3, "i2s0"), /* DOUT */ + SUNXI_FUNCTION(0x5, "sim"), /* RST */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif2"), /* DIN */ + SUNXI_FUNCTION(0x3, "i2s0"), /* DIN */ + SUNXI_FUNCTION(0x5, "sim"), /* DET */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "uart0"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "uart0"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NWE */ + SUNXI_FUNCTION(0x4, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NALE */ + SUNXI_FUNCTION(0x3, "mmc2"), /* DS */ + SUNXI_FUNCTION(0x4, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */ + SUNXI_FUNCTION(0x4, "spi0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */ + SUNXI_FUNCTION(0x4, "spi0")), /* CS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRE# */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* NRB1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */ + SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */ + SUNXI_FUNCTION(0x3, "mmc2")), /* RST */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION(0x4, "spi1"), /* CS */ + SUNXI_FUNCTION(0x5, "ccir")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION(0x4, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x5, "ccir")), /* DE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "uart4"), /* TX */ + SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x5, "ccir")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "uart4"), /* RX */ + SUNXI_FUNCTION(0x4, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x5, "ccir")), /* VSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "uart4"), /* RTS */ + SUNXI_FUNCTION(0x5, "ccir")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "uart4"), /* CTS */ + SUNXI_FUNCTION(0x5, "ccir")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */ + SUNXI_FUNCTION(0x4, "emac"), /* ERXD3 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */ + SUNXI_FUNCTION(0x4, "emac"), /* ERXD2 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */ + SUNXI_FUNCTION(0x4, "emac")), /* ERXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */ + SUNXI_FUNCTION(0x4, "emac")), /* ERXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VP0 */ + SUNXI_FUNCTION(0x4, "emac")), /* ERXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VN0 */ + SUNXI_FUNCTION(0x4, "emac")), /* ERXCTL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VP1 */ + SUNXI_FUNCTION(0x4, "emac")), /* ENULL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VN1 */ + SUNXI_FUNCTION(0x4, "emac"), /* ETXD3 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VP2 */ + SUNXI_FUNCTION(0x4, "emac"), /* ETXD2 */ + SUNXI_FUNCTION(0x5, "ccir")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VN2 */ + SUNXI_FUNCTION(0x4, "emac")), /* ETXD1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VPC */ + SUNXI_FUNCTION(0x4, "emac")), /* ETXD0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* DE */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VNC */ + SUNXI_FUNCTION(0x4, "emac")), /* ETXCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VP3 */ + SUNXI_FUNCTION(0x4, "emac")), /* ETXCTL */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "lvds0"), /* VN3 */ + SUNXI_FUNCTION(0x4, "emac")), /* ECLKIN */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */ + SUNXI_FUNCTION(0x4, "emac")), /* EMDC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x4, "emac")), /* EMDIO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* PCK */ + SUNXI_FUNCTION(0x4, "ts0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* CK */ + SUNXI_FUNCTION(0x4, "ts0")), /* ERR */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "ts0")), /* SYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* VSYNC */ + SUNXI_FUNCTION(0x4, "ts0")), /* DVLD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D0 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D1 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D2 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D3 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D4 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D5 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D6 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0"), /* D7 */ + SUNXI_FUNCTION(0x4, "ts0")), /* D7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pll"), /* LOCK_DBG */ + SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x3, "jtag")), /* MSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x3, "jtag")), /* DI1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x3, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x3, "jtag")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x3, "jtag")), /* CK1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart1"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart1"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif3"), /* SYNC */ + SUNXI_FUNCTION(0x3, "i2s1"), /* SYNC */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif3"), /* BCLK */ + SUNXI_FUNCTION(0x3, "i2s1"), /* BCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)), /* EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif3"), /* DOUT */ + SUNXI_FUNCTION(0x3, "i2s1"), /* DOUT */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)), /* EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "aif3"), /* DIN */ + SUNXI_FUNCTION(0x3, "i2s1"), /* DIN */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)), /* EINT13 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart3"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart3"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spdif"), /* OUT */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mic"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mic"), /* DATA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* EINT11 */ +}; + +const struct sunxi_pinctrl_desc a64_pinctrl_data = { + .pins = a64_pins, + .npins = ARRAY_SIZE(a64_pins), + .irq_banks = 3, +}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c new file mode 100644 index 0000000..36579b1 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,326 @@ +/* + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH + * + * In parts based on linux/drivers/pinctrl/pinctrl-sunxi.c, which is + * Copyright (C) 2012 Maxime Ripard + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/gpio.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/gpio/gpio.h> +#include "pinctrl-sunxi.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_pctrl_priv { + void *base; +}; + +static int sunxi_pctrl_parse_drive_prop(const void *blob, int node) +{ + int val; + + /* Try the new style binding */ + val = fdtdec_get_int(blob, node, "drive-strength", -EINVAL); + if (val >= 0) { + /* We can't go below 10mA ... */ + if (val < 10) + return -EINVAL; + + /* ... and only up to 40 mA ... */ + if (val > 40) + val = 40; + + /* by steps of 10 mA */ + return rounddown(val, 10); + } + + /* And then fall back to the old binding */ + val = fdtdec_get_int(blob, node, "allwinner,drive", -EINVAL); + if (val < 0) + return -EINVAL; + + return (val + 1) * 10; +} + +static int sunxi_pctrl_parse_bias_prop(const void *blob, int node) +{ + /* Try the new style binding */ + if (fdtdec_get_bool(blob, node, "bias-pull-up")) + return SUN4I_PINCTRL_PULL_UP; + + if (fdtdec_get_bool(blob, node, "bias-pull-down")) + return SUN4I_PINCTRL_PULL_DOWN; + + if (fdtdec_get_bool(blob, node, "bias-disable")) + return SUN4I_PINCTRL_NO_PULL; + + /* And fall back to the old binding */ + return fdtdec_get_int(blob, node, "allwinner,pull", -EINVAL); +} + +static const struct sunxi_desc_pin *sunxi_pctrl_pin_by_name(struct udevice *dev, + const char *name) +{ + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + int i; + + for (i = 0; i < data->npins; ++i) + if (!strcmp(data->pins[i].pin.name, name)) + return &data->pins[i]; + + return NULL; +} + +static int sunxi_pctrl_muxval_by_name(const struct sunxi_desc_pin *pin, + const char *name) +{ + const struct sunxi_desc_function *func; + + if (!pin) + return -EINVAL; + + for (func = pin->functions; func->name; func++) + if (!strcmp(func->name, name)) + return func->muxval; + + return -ENOENT; +} + +static void sunxi_pctrl_set_function(struct udevice *dev, + unsigned pin, int function) +{ + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + u32 val, mask; + + if (function < 0) + return; + + pin -= data->pin_base; + mask = MUX_PINS_MASK << sunxi_mux_offset(pin); + val = function << sunxi_mux_offset(pin); + clrsetbits_le32(priv->base + sunxi_mux_reg(pin), mask, val); +} + +static void sunxi_pctrl_set_dlevel(struct udevice *dev, + unsigned pin, int dlevel) +{ + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + u32 val, mask; + + if (dlevel < 0) + return; + + pin -= data->pin_base; + mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin); + val = dlevel << sunxi_dlevel_offset(pin); + clrsetbits_le32(priv->base + sunxi_dlevel_reg(pin), mask, val); +} + +static void sunxi_pctrl_set_bias(struct udevice *dev, + unsigned pin, int bias) +{ + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + u32 val, mask; + + if (bias < 0) + return; + + pin -= data->pin_base; + mask = PULL_PINS_MASK << sunxi_pull_offset(pin); + val = bias << sunxi_pull_offset(pin); + clrsetbits_le32(priv->base + sunxi_pull_reg(pin), mask, val); +} + +static int sunxi_pctrl_set_state(struct udevice *dev, struct udevice *config) +{ + const char *pins; + const char *function; + int flen; + int len, curr_len; + int drive, bias; + int muxval; + + debug("%s: %s %s\n", __func__, dev->name, config->name); + + pins = fdt_getprop(gd->fdt_blob, config->of_offset, + "allwinner,pins", &len); + if (!pins) { + debug("%s: missing allwinner,pins property in node %s\n", + dev->name, config->name); + return -EINVAL; + } + + function = fdt_getprop(gd->fdt_blob, config->of_offset, + "allwinner,function", &flen); + if (!function) { + debug("%s: missing allwinner,function property in node %s\n", + dev->name, config->name); + return -EINVAL; + } + + drive = sunxi_pctrl_parse_drive_prop(gd->fdt_blob, config->of_offset); + bias = sunxi_pctrl_parse_bias_prop(gd->fdt_blob, config->of_offset); + + debug("%s: function %s, drive %d, bias %d\n", + config->name, function, drive, bias); + + /* Iterate through the pins and configure each */ + while (len && (curr_len = strnlen(pins, len))) { + const struct sunxi_desc_pin *pin; + + if (curr_len == len) { + error("%s: unterminated string?", __func__); + break; + } + + pin = sunxi_pctrl_pin_by_name(dev, pins); + if (pin) { + muxval = sunxi_pctrl_muxval_by_name(pin, function); + + sunxi_pctrl_set_function(dev, pin->pin.number, muxval); + sunxi_pctrl_set_dlevel(dev, pin->pin.number, drive); + sunxi_pctrl_set_bias(dev, pin->pin.number, bias); + } else { + debug("%s: could not find pin %s\n", dev->name, pins); + } + + /* advance */ + pins += (curr_len + 1); + len -= (curr_len + 1); + } + + return 0; +} + +static int sunxi_pctrl_probe(struct udevice *dev) +{ + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); +#if CONFIG_DM_GPIO + struct udevice *gpiobridge; +#endif + fdt_addr_t addr_base; + fdt_size_t size; + + addr_base = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, + dev->of_offset, + "reg", 0, &size, + false); + if (addr_base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (void *)addr_base; + +#if CONFIG_DM_GPIO + device_bind_driver_to_node(dev, "sunxi_pctrl_gpiobridge", + "gpiobridge", dev->of_offset, &gpiobridge); + + /* The new device will have been created with no driver data, + so we need to set it here, as it contains the pin_base of + the gpio-group. */ + if (gpiobridge) + gpiobridge->driver_data = dev_get_driver_data(dev); +#endif + + return 0; +} + +static struct pinctrl_ops sunxi_pctrl_ops = { + .set_state = sunxi_pctrl_set_state, +}; + +#if defined(CONFIG_MACH_SUN50I) +extern const struct sunxi_pinctrl_desc a64_pinctrl_data; +extern const struct sunxi_pinctrl_desc a64_r_pinctrl_data; +#endif + +static const struct udevice_id sunxi_pctrl_ids[] = { +#if defined(CONFIG_MACH_SUN50I) + { .compatible = "allwinner,sun50i-a64-pinctrl", + .data = (ulong)&a64_pinctrl_data }, + { .compatible = "allwinner,sun50i-a64-r-pinctrl", + .data = (ulong)&a64_r_pinctrl_data }, +#endif + { } +}; + +U_BOOT_DRIVER(pinctrl_sunxi) = { + .name = "sunxi_pctrl", + .id = UCLASS_PINCTRL, + .of_match = sunxi_pctrl_ids, + .priv_auto_alloc_size = sizeof(struct sunxi_pctrl_priv), + .ops = &sunxi_pctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = sunxi_pctrl_probe, +}; + + +#if defined(CONFIG_DM_GPIO) +/* The gpiobridge exists to translate <&pio 3 24 GPIO_ACTIVE_LOW> into the + underlying GPIO bank. It needs to access/understand the driver-data for + the pinctrl device, so it lives here instead of in sunxi_gpio.c ... */ + +static int sunxi_gpiobridge_xlate(struct udevice *dev, struct gpio_desc *desc, + struct fdtdec_phandle_args *args) +{ + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + struct udevice *gpiobank; + char name[3] = {'P', 'A', '\0' }; + + if (!data) { + debug("%s: no driver_data\n", dev->name); + return -ENOENT; + } + + /* Naming on each pinctrl may start with an offset (e.g. R_PIO + usually starts at 'PL'). */ + name[1] += data->pin_base / PINS_PER_BANK; + /* Now add the bank-number within this pinctrl */ + name[1] += args->args[0]; + + for (uclass_first_device(UCLASS_GPIO, &gpiobank); + gpiobank; + uclass_next_device(&gpiobank)) { + int count; + const char *bank_name = gpio_get_bank_info(gpiobank, &count); + + if (bank_name && !strcmp(bank_name, name)) { + desc->dev = gpiobank; + desc->offset = args->args[1]; + desc->flags = args->args[2] & (GPIO_ACTIVE_LOW ? + GPIOD_ACTIVE_LOW : 0); + return 0; + } + } + + return -ENOENT; +} + +static const struct dm_gpio_ops gpiobridge_sunxi_ops = { + .xlate = sunxi_gpiobridge_xlate, +}; + +U_BOOT_DRIVER(gpiobridge_sunxi) = { + .name = "sunxi_pctrl_gpiobridge", + .id = UCLASS_GPIO, + .ops = &gpiobridge_sunxi_ops, +}; +#endif /* DM_GPIO */ diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h new file mode 100644 index 0000000..8508626 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -0,0 +1,311 @@ +/* + * Allwinner A1X SoCs pinctrl driver. + * + * Copyright (C) 2012 Maxime Ripard + * + * Maxime Ripard maxime.ripard@free-electrons.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __PINCTRL_SUNXI_H +#define __PINCTRL_SUNXI_H + +#define PA_BASE 0 +#define PB_BASE 32 +#define PC_BASE 64 +#define PD_BASE 96 +#define PE_BASE 128 +#define PF_BASE 160 +#define PG_BASE 192 +#define PH_BASE 224 +#define PI_BASE 256 +#define PL_BASE 352 +#define PM_BASE 384 +#define PN_BASE 416 + +#ifdef __UBOOT__ +/* Convenience macro to define a single named or anonymous pin descriptor */ +#define PINCTRL_PIN(a, b) { .number = a, .name = b } + +/** + * struct pinctrl_pin_desc - boards/machines provide information on their + * pins, pads or other muxable units in this struct + * @number: unique pin number from the global pin number space + * @name: a name for this pin + * @drv_data: driver-defined per-pin data. pinctrl core does not touch this + */ +struct pinctrl_pin_desc { + unsigned number; + const char *name; +#ifndef __UBOOT__ + void *drv_data; +#endif +}; +#endif + +#define SUNXI_PINCTRL_PIN(bank, pin) \ + PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin) + +#define SUNXI_PIN_NAME_MAX_LEN 5 + +#define BANK_MEM_SIZE 0x24 +#define MUX_REGS_OFFSET 0x0 +#define DATA_REGS_OFFSET 0x10 +#define DLEVEL_REGS_OFFSET 0x14 +#define PULL_REGS_OFFSET 0x1c + +#define PINS_PER_BANK 32 +#define MUX_PINS_PER_REG 8 +#define MUX_PINS_BITS 4 +#define MUX_PINS_MASK 0x0f +#define DATA_PINS_PER_REG 32 +#define DATA_PINS_BITS 1 +#define DATA_PINS_MASK 0x01 +#define DLEVEL_PINS_PER_REG 16 +#define DLEVEL_PINS_BITS 2 +#define DLEVEL_PINS_MASK 0x03 +#define PULL_PINS_PER_REG 16 +#define PULL_PINS_BITS 2 +#define PULL_PINS_MASK 0x03 + +#define IRQ_PER_BANK 32 + +#define IRQ_CFG_REG 0x200 +#define IRQ_CFG_IRQ_PER_REG 8 +#define IRQ_CFG_IRQ_BITS 4 +#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1) +#define IRQ_CTRL_REG 0x210 +#define IRQ_CTRL_IRQ_PER_REG 32 +#define IRQ_CTRL_IRQ_BITS 1 +#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1) +#define IRQ_STATUS_REG 0x214 +#define IRQ_STATUS_IRQ_PER_REG 32 +#define IRQ_STATUS_IRQ_BITS 1 +#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1) + +#define IRQ_MEM_SIZE 0x20 + +#define IRQ_EDGE_RISING 0x00 +#define IRQ_EDGE_FALLING 0x01 +#define IRQ_LEVEL_HIGH 0x02 +#define IRQ_LEVEL_LOW 0x03 +#define IRQ_EDGE_BOTH 0x04 + +#define SUN4I_FUNC_INPUT 0 +#define SUN4I_FUNC_IRQ 6 + +struct sunxi_desc_function { + const char *name; + u8 muxval; + u8 irqbank; + u8 irqnum; +}; + +struct sunxi_desc_pin { + struct pinctrl_pin_desc pin; + struct sunxi_desc_function *functions; +}; + +struct sunxi_pinctrl_desc { + const struct sunxi_desc_pin *pins; + int npins; + unsigned pin_base; + unsigned irq_banks; + unsigned irq_bank_base; + bool irq_read_needs_mux; +}; + +struct sunxi_pinctrl_function { + const char *name; + const char **groups; + unsigned ngroups; +}; + +struct sunxi_pinctrl_group { + const char *name; + unsigned long config; + unsigned pin; +}; + +#ifndef __UBOOT__ +struct sunxi_pinctrl { + void __iomem *membase; + struct gpio_chip *chip; + const struct sunxi_pinctrl_desc *desc; + struct device *dev; + struct irq_domain *domain; + struct sunxi_pinctrl_function *functions; + unsigned nfunctions; + struct sunxi_pinctrl_group *groups; + unsigned ngroups; + int *irq; + unsigned *irq_array; + spinlock_t lock; + struct pinctrl_dev *pctl_dev; +}; +#endif + +#define SUNXI_PIN(_pin, ...) \ + { \ + .pin = _pin, \ + .functions = (struct sunxi_desc_function[]){ \ + __VA_ARGS__, { } }, \ + } + +#define SUNXI_FUNCTION(_val, _name) \ + { \ + .name = _name, \ + .muxval = _val, \ + } + +#define SUNXI_FUNCTION_IRQ(_val, _irq) \ + { \ + .name = "irq", \ + .muxval = _val, \ + .irqnum = _irq, \ + } + +#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq) \ + { \ + .name = "irq", \ + .muxval = _val, \ + .irqbank = _bank, \ + .irqnum = _irq, \ + } + +/* + * The sunXi PIO registers are organized as is: + * 0x00 - 0x0c Muxing values. + * 8 pins per register, each pin having a 4bits value + * 0x10 Pin values + * 32 bits per register, each pin corresponding to one bit + * 0x14 - 0x18 Drive level + * 16 pins per register, each pin having a 2bits value + * 0x1c - 0x20 Pull-Up values + * 16 pins per register, each pin having a 2bits value + * + * This is for the first bank. Each bank will have the same layout, + * with an offset being a multiple of 0x24. + * + * The following functions calculate from the pin number the register + * and the bit offset that we should access. + */ +static inline u32 sunxi_mux_reg(u16 pin) +{ + u8 bank = pin / PINS_PER_BANK; + u32 offset = bank * BANK_MEM_SIZE; + offset += MUX_REGS_OFFSET; + offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04; + return round_down(offset, 4); +} + +static inline u32 sunxi_mux_offset(u16 pin) +{ + u32 pin_num = pin % MUX_PINS_PER_REG; + return pin_num * MUX_PINS_BITS; +} + +static inline u32 sunxi_data_reg(u16 pin) +{ + u8 bank = pin / PINS_PER_BANK; + u32 offset = bank * BANK_MEM_SIZE; + offset += DATA_REGS_OFFSET; + offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04; + return round_down(offset, 4); +} + +static inline u32 sunxi_data_offset(u16 pin) +{ + u32 pin_num = pin % DATA_PINS_PER_REG; + return pin_num * DATA_PINS_BITS; +} + +static inline u32 sunxi_dlevel_reg(u16 pin) +{ + u8 bank = pin / PINS_PER_BANK; + u32 offset = bank * BANK_MEM_SIZE; + offset += DLEVEL_REGS_OFFSET; + offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04; + return round_down(offset, 4); +} + +static inline u32 sunxi_dlevel_offset(u16 pin) +{ + u32 pin_num = pin % DLEVEL_PINS_PER_REG; + return pin_num * DLEVEL_PINS_BITS; +} + +static inline u32 sunxi_pull_reg(u16 pin) +{ + u8 bank = pin / PINS_PER_BANK; + u32 offset = bank * BANK_MEM_SIZE; + offset += PULL_REGS_OFFSET; + offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04; + return round_down(offset, 4); +} + +static inline u32 sunxi_pull_offset(u16 pin) +{ + u32 pin_num = pin % PULL_PINS_PER_REG; + return pin_num * PULL_PINS_BITS; +} + +static inline u32 sunxi_irq_cfg_reg(u16 irq, unsigned bank_base) +{ + u8 bank = irq / IRQ_PER_BANK; + u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04; + + return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg; +} + +static inline u32 sunxi_irq_cfg_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG; + return irq_num * IRQ_CFG_IRQ_BITS; +} + +static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base) +{ + return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE; +} + +static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base) +{ + u8 bank = irq / IRQ_PER_BANK; + + return sunxi_irq_ctrl_reg_from_bank(bank, bank_base); +} + +static inline u32 sunxi_irq_ctrl_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG; + return irq_num * IRQ_CTRL_IRQ_BITS; +} + +static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base) +{ + return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE; +} + +static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base) +{ + u8 bank = irq / IRQ_PER_BANK; + + return sunxi_irq_status_reg_from_bank(bank, bank_base); +} + +static inline u32 sunxi_irq_status_offset(u16 irq) +{ + u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG; + return irq_num * IRQ_STATUS_IRQ_BITS; +} + +#ifndef __UBOOT__ +int sunxi_pinctrl_init(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc); +#endif + +#endif /* __PINCTRL_SUNXI_H */

On Sat, Feb 18, 2017 at 1:52 AM, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are:
- implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it
- defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms:
- As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device.
- For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure.
Why is the new binding and driver necessary? The existing driver in U-boot is already DM enabled and properly xlates GPIO phandles to its child GPIO banks. I specifically fixed this in commit 4694dc56e974 ("sunxi: gpio: Add .xlate function for gpio phandle resolution").
You are also not using the new gpiobank nodes anywhere in your dts changes.
- lifts and reuses the pinctrl-sunxi.h and pinctrl-sun50i-a64.c files from Linux (thanks to Maxime and Andre) and adds a pinctrl-sun50i-a64-r.c (to be picked up for inclusion into Linux again)
The active DM tree at runtime (with this enabled) should look similar to the following:
pinctrl [ + ] | |-- pinctrl@1c20800 gpio [ + ] | | |-- gpiob@24 gpio [ + ] | | |-- gpioc@48 gpio [ + ] | | |-- gpiod@6c gpio [ + ] | | |-- gpioe@90 gpio [ + ] | | |-- gpiof@b4 gpio [ + ] | | |-- gpiog@d8 gpio [ + ] | | |-- gpioh@fc pinconfig [ + ] | | |-- uart0_pins_a pinconfig [ ] | | |-- uart0_pins_b pinconfig [ ] | | |-- uart1_2pins pinconfig [ ] | | |-- uart1_4pins pinconfig [ ] | | |-- uart2_2pins pinconfig [ ] | | |-- uart2_4 pinconfig [ ] | | |-- uart3 pinconfig [ ] | | |-- uart3_2 pinconfig [ ] | | |-- uart3_4 pinconfig [ ] | | |-- uart4_2 pinconfig [ ] | | |-- uart4_4 pinconfig [ + ] | | |-- mmc0 pinconfig [ + ] | | |-- mmc0_cd_pin pinconfig [ ] | | |-- mmc1 pinconfig [ ] | | |-- mmc2 pinconfig [ + ] | | |-- mmc2_8bit pinconfig [ ] | | |-- i2c0_pins pinconfig [ ] | | |-- i2c1_pins pinconfig [ ] | | |-- i2c2_pins pinconfig [ ] | | |-- rmii_pins pinconfig [ + ] | | |-- rgmii_pins pinconfig [ + ] | | |-- spi0_pins pinconfig [ ] | | |-- spi1_pins pinconfig [ + ] | | |-- led_pins_sdio pinconfig [ + ] | | |-- ethphy_reset_pin gpio [ + ] | | `-- gpiobridge pinctrl [ + ] | |-- pinctrl@01f02c00 gpio [ + ] | | |-- gpiol@0 pinconfig [ + ] | | |-- led_pins_power gpio [ + ] | | `-- gpiobridge
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
.../pinctrl/allwinner,pinctrl.txt | 130 +++++ drivers/gpio/sunxi_gpio.c | 97 +++- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/sunxi/Makefile | 10 + drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c | 92 ++++ drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 577 +++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 326 ++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 9 files changed, 1553 insertions(+), 2 deletions(-) create mode 100644 doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h
diff --git a/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt new file mode 100644 index 0000000..e536ea3 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,130 @@ +* Allwinner Pinmux Controller
+Allwinner integrates multiple banks (of 32 pins each) of pin-muxing, +GPIO functionality and (optional) external interrupt functionality +into a single controller.
+For each configurable pad (certain driver-cells, such as the IO from +integrated USB PHYs or DRAM, have a fixed function and can not be +configured), the muxing options (input, output or one of the several +functions) can be selected.
+The Allwinner pinctrl node contains a description of the pinctrl block +(i.e. including GPIO and external interrupt capability, if available) +and subnodes describing individual GPIO banks and pin-configuration.
+Properties for the pinctrl node:
- compatible: should be "allwinner,sun50i-pinctrl"
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- clocks: A phandle to the reference clock for this device
+Properties for the pinconfig sub-nodes:
- allwinner,pins: a list of pins (e.g. "PH2", "PH3") to configure
- allwinner,function: the name of pinmux function (e.g. "mmc2")
- drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA
- bias-pull-up
- bias-pull-down
- bias-disable (default)
+Deprecated properties for the pinconfig sub-nodes:
- allwinner,drive: one of <SUN4I_PINCTRL_10_MA>, <SUN4I_PINCTRL_20_MA>,
<SUN4I_PINCTRL_30_MA> or <SUN4I_PINCTRL_40_MA>
- allwinner,pull: one of <SUN4I_PINCTRL_NO_PULL>, <SUN4I_PINCTRL_PULL_UP>
or <SUN4I_PINCTRL_PULL_DOWN>
+Properties for the gpio sub-nodes:
- compatible: should be "allwinner,sunxi-gpiobank"
- allwinner,gpiobank-name: the name of the bank (e.g. <'A'>, <'B'>, ...)
- reg: offsets (within the address range of the enclosing pinctrl
node's address space) and length of the registers, where
* The first entry points to the mux/gpio registers.
* An (optional) second entry points to the extint registers.
Note, that the second entry should be provided, if the
interrupt property is present.
- interrupt: the interrupt used for external interrupt signalling
(should be one of the interrupts specified in the
enclosing pinctrl node)
+Example:
pio: pinctrl@1c20800 {
compatible = "allwinner,sun50i-a64-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bus_gates 69>;
gpio-controller;
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
/* The A64 does not have bank A and leaves a hole in the
address space where it normally would be */
gpiob: gpiob@24 {
compatible = "allwinner,sunxi-gpiobank";
allwinner,gpiobank-name = <'B'>;
reg = < 0x24 0x24 >, < 0x200 0x1c >;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
};
gpioc: gpioc@48 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x48 0x24 >;
allwinner,gpiobank-name = <'C'>;
};
gpiod: gpiod@6c {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x6c 0x24 >;
allwinner,gpiobank-name = <'D'>;
};
gpioe: gpioe@90 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x90 0x24 >;
allwinner,gpiobank-name = <'E'>;
};
gpiof: gpiof@b4 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xb4 0x24 >;
allwinner,gpiobank-name = <'F'>;
};
gpiog: gpiog@d8 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xd8 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'G'>;
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
gpioh: gpioh@fc {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xfc 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'H'>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
};
uart0_pins_a: uart0_pins_a {
allwinner,pins = "PB8", "PB9";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
uart0_pins_b: uart0_pins_b {
allwinner,pins = "PF2", "PF3";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 2b7bc7f..6cf2be4 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -344,36 +344,129 @@ static const struct sunxi_gpio_soc_data soc_data_l_3 = { static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun4i-a10-pinctrl", a_all), ID("allwinner,sun5i-a10s-pinctrl", a_all), ID("allwinner,sun5i-a13-pinctrl", a_all), ID("allwinner,sun6i-a31-pinctrl", a_all), ID("allwinner,sun6i-a31s-pinctrl", a_all), ID("allwinner,sun7i-a20-pinctrl", a_all), ID("allwinner,sun8i-a23-pinctrl", a_all), ID("allwinner,sun8i-a33-pinctrl", a_all), ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), +#if !defined(CONFIG_SUNXI_PINCTRL) /* This is not strictly correct for the A64, as it is missing * bank 'A'. Yet, the register layout in the pinctrl block is * backward compatible and any accesses to the registers that * normally control bank 'A' will have no adverse effect. */
ID("allwinner,sun50i-a64-pinctrl", a_all),
ID("allwinner,sun50i-a64-pinctrl", a_all),
+#endif ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3),
ID("allwinner,sun50i-a64-r-pinctrl", l_1),
+#if !defined(CONFIG_SUNXI_PINCTRL)
ID("allwinner,sun50i-a64-r-pinctrl", l_1),
+#endif { } };
U_BOOT_DRIVER(gpio_sunxi) = { .name = "gpio_sunxi", .id = UCLASS_GPIO, .ops = &gpio_sunxi_ops, .of_match = sunxi_gpio_ids, .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, };
+#if defined(CONFIG_SUNXI_PINCTRL)
+/* When we use the sunxi pinctrl infrastructure, we have two issues that
- are resolved by the gpiobank and gpiobrige drivers:
- We need to have a UCLASS_GPIO device bound to the pinctrl-nodes for
- translating between gpio entries (e.g. <&pio 3 24 GPIO_ACTIVE_LOW>;)
- in the DT and actual gpio banks. This is done using the gpiobridge
- driver, which provides only a lookup/translation mechanism.
- This mechanism lives in pinctrl-sunxi.c
- We introduce a generic gpiobank device, which resolves the need to
- have distinct soc_data structure for each device and avoids having
- to share data structures and config data between this file and the
- sunxi pinctrl (the other option would be to have the soc_data info
- visible in pinctrl-sunxi.c (or merge it into this file) and bind a
- gpio_sunxi device that is set up with the appropriate soc_data) to
- the same node as the pinctrl device.
Pushing hardware internals into the DT is not preferred.
Since the pinctrl and gpio drivers actually driver the same hardware block, just in different ways, and there should be some locking between the two, I think it would make sense to merge the two.
You can also get away with not having soc_data by just registering the full set of GPIO banks and pins (we aren't counting extra pins anyway).
Moreover I think the gpiobank issue is just a limitation of U-boot's GPIO implementation.
Regards ChenYu
- */
+static int gpiobank_sunxi_probe(struct udevice *dev) +{
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
int bank_name;
int bank;
fdt_addr_t offset;
fdt_size_t size;
fdt_addr_t base;
debug("%s: %s", __func__, dev->name);
/* At this time we are only interested in index 0 (the PIO registers)
and we ignore index 1 (the external interrupt control), even if
present and an interrupt property exists... */
offset = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob,
dev->of_offset,
"reg", 0, &size,
false);
if (offset == FDT_ADDR_T_NONE) {
error("%s: missing 'reg' for offset into parent device\n",
dev->name);
return -EINVAL;
}
bank_name = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"allwinner,gpiobank-name", -EINVAL);
if (bank_name == -EINVAL) {
error("%s: missing 'allwinner,gpiobank-name'\n", dev->name);
return -EINVAL;
}
base = dev_get_addr(dev->parent);
if (base == FDT_ADDR_T_NONE) {
error("%s: parent '%s' does not have a valid base address\n",
dev->name, dev->parent->name);
return -EINVAL;
}
bank = bank_name - 'A';
plat->regs = (void *)(base + offset);
plat->gpio_count = SUNXI_GPIOS_PER_BANK;
plat->bank_name = gpio_bank_name(bank);
/* Tell the uclass how many GPIOs we have */
uc_priv->gpio_count = plat->gpio_count;
uc_priv->bank_name = plat->bank_name;
return 0;
+}
+static const struct udevice_id sunxi_gpiobank_ids[] = {
{ .compatible = "allwinner,sunxi-gpiobank", },
{}
+};
+U_BOOT_DRIVER(gpiobank_sunxi) = {
.name = "gpiobank_sunxi",
.id = UCLASS_GPIO,
.ops = &gpio_sunxi_ops,
.of_match = sunxi_gpiobank_ids,
.platdata_auto_alloc_size = sizeof(struct sunxi_gpio_platdata),
.probe = gpiobank_sunxi_probe,
+};
+#endif /* CONFIG_SUNXI_PINCTRL */
#endif diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..064a682 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,16 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config SUNXI_PINCTRL
bool "Allwinner Axx pin-control and pin-mux driver"
depends on DM && ARCH_SUNXI
default y
help
Supports pin multiplexing control, drive-strength and bias control on
Allwinner Axx SoCs. The driver is controlled by a device tree node which
contains both the GPIO definitions and the pin control functions for
each multiplex function.
endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..da27a91 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,18 +1,20 @@ # # SPDX-License-Identifier: GPL-2.0+ #
obj-y += pinctrl-uclass.o obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ obj-$(CONFIG_ARCH_ATH79) += ath79/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/ \ No newline at end of file diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile new file mode 100644 index 0000000..11549ec --- /dev/null +++ b/drivers/pinctrl/sunxi/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_SUNXI_PINCTRL) += pinctrl-sunxi.o +ifdef CONFIG_SUNXI_PINCTRL +obj-$(CONFIG_MACH_SUN50I) += pinctrl-sun50i-a64.o pinctrl-sun50i-a64-r.o +endif diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c new file mode 100644 index 0000000..864d1ec --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c @@ -0,0 +1,92 @@ +/*
- Allwinner A64 SoCs pinctrl driver.
- Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH.
- Based on pinctrl-sun7i-a20.c, which is:
- Copyright (C) 2014 Maxime Ripard maxime.ripard@free-electrons.com
- This file is licensed under the terms of the GNU General Public
- License version 2. This program is licensed "as is" without any
- warranty of any kind, whether express or implied.
- */
+#include <common.h>
+#include "pinctrl-sunxi.h"
+static const struct sunxi_desc_pin a64_r_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_rsb"), /* SCK */
SUNXI_FUNCTION(0x3, "s_i2c"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_rsb"), /* SDA */
SUNXI_FUNCTION(0x3, "s_i2c"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_uart"), /* TX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_uart"), /* RX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* MS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* CK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* DO */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_jtag"), /* DI */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_i2c"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_i2c"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_pwm"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* EINT10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "s_cir"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* EINT11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* EINT12 */
+};
+const struct sunxi_pinctrl_desc a64_r_pinctrl_data = {
.pins = a64_r_pins,
.npins = ARRAY_SIZE(a64_r_pins),
.pin_base = PL_BASE,
.irq_banks = 1,
+}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c new file mode 100644 index 0000000..7abea03 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c @@ -0,0 +1,577 @@ +/*
- Allwinner A64 SoCs pinctrl driver.
- Copyright (C) 2016 - ARM Ltd.
- Author: Andre Przywara andre.przywara@arm.com
- Based on pinctrl-sun7i-a20.c, which is:
- Copyright (C) 2014 Maxime Ripard maxime.ripard@free-electrons.com
- This file is licensed under the terms of the GNU General Public
- License version 2. This program is licensed "as is" without any
- warranty of any kind, whether express or implied.
- */
+#include <common.h>
+#include "pinctrl-sunxi.h"
+static const struct sunxi_desc_pin a64_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart2"), /* TX */
SUNXI_FUNCTION(0x4, "jtag"), /* MS0 */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* EINT0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart2"), /* RX */
SUNXI_FUNCTION(0x4, "jtag"), /* CK0 */
SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* EINT1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
SUNXI_FUNCTION(0x4, "jtag"), /* DO0 */
SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* EINT2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
SUNXI_FUNCTION(0x3, "i2s0"), /* MCLK */
SUNXI_FUNCTION(0x4, "jtag"), /* DI0 */
SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif2"), /* SYNC */
SUNXI_FUNCTION(0x3, "i2s0"), /* SYNC */
SUNXI_FUNCTION(0x5, "sim"), /* CLK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* EINT4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif2"), /* BCLK */
SUNXI_FUNCTION(0x3, "i2s0"), /* BCLK */
SUNXI_FUNCTION(0x5, "sim"), /* DATA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* EINT5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif2"), /* DOUT */
SUNXI_FUNCTION(0x3, "i2s0"), /* DOUT */
SUNXI_FUNCTION(0x5, "sim"), /* RST */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* EINT6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif2"), /* DIN */
SUNXI_FUNCTION(0x3, "i2s0"), /* DIN */
SUNXI_FUNCTION(0x5, "sim"), /* DET */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* EINT7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x4, "uart0"), /* TX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* EINT8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x4, "uart0"), /* RX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* EINT9 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NWE */
SUNXI_FUNCTION(0x4, "spi0")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NALE */
SUNXI_FUNCTION(0x3, "mmc2"), /* DS */
SUNXI_FUNCTION(0x4, "spi0")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */
SUNXI_FUNCTION(0x4, "spi0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */
SUNXI_FUNCTION(0x4, "spi0")), /* CS */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NRE# */
SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */
SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0")), /* NRB1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */
SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */
SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
SUNXI_FUNCTION(0x3, "uart3"), /* TX */
SUNXI_FUNCTION(0x4, "spi1"), /* CS */
SUNXI_FUNCTION(0x5, "ccir")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
SUNXI_FUNCTION(0x3, "uart3"), /* RX */
SUNXI_FUNCTION(0x4, "spi1"), /* CLK */
SUNXI_FUNCTION(0x5, "ccir")), /* DE */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
SUNXI_FUNCTION(0x3, "uart4"), /* TX */
SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */
SUNXI_FUNCTION(0x5, "ccir")), /* HSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
SUNXI_FUNCTION(0x3, "uart4"), /* RX */
SUNXI_FUNCTION(0x4, "spi1"), /* MISO */
SUNXI_FUNCTION(0x5, "ccir")), /* VSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
SUNXI_FUNCTION(0x3, "uart4"), /* RTS */
SUNXI_FUNCTION(0x5, "ccir")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
SUNXI_FUNCTION(0x3, "uart4"), /* CTS */
SUNXI_FUNCTION(0x5, "ccir")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
SUNXI_FUNCTION(0x5, "ccir")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
SUNXI_FUNCTION(0x5, "ccir")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
SUNXI_FUNCTION(0x4, "emac"), /* ERXD3 */
SUNXI_FUNCTION(0x5, "ccir")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
SUNXI_FUNCTION(0x4, "emac"), /* ERXD2 */
SUNXI_FUNCTION(0x5, "ccir")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
SUNXI_FUNCTION(0x4, "emac")), /* ERXD1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
SUNXI_FUNCTION(0x4, "emac")), /* ERXD0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VP0 */
SUNXI_FUNCTION(0x4, "emac")), /* ERXCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VN0 */
SUNXI_FUNCTION(0x4, "emac")), /* ERXCTL */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VP1 */
SUNXI_FUNCTION(0x4, "emac")), /* ENULL */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VN1 */
SUNXI_FUNCTION(0x4, "emac"), /* ETXD3 */
SUNXI_FUNCTION(0x5, "ccir")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VP2 */
SUNXI_FUNCTION(0x4, "emac"), /* ETXD2 */
SUNXI_FUNCTION(0x5, "ccir")), /* D7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
SUNXI_FUNCTION(0x3, "lvds0"), /* VN2 */
SUNXI_FUNCTION(0x4, "emac")), /* ETXD1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
SUNXI_FUNCTION(0x3, "lvds0"), /* VPC */
SUNXI_FUNCTION(0x4, "emac")), /* ETXD0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
SUNXI_FUNCTION(0x3, "lvds0"), /* VNC */
SUNXI_FUNCTION(0x4, "emac")), /* ETXCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
SUNXI_FUNCTION(0x3, "lvds0"), /* VP3 */
SUNXI_FUNCTION(0x4, "emac")), /* ETXCTL */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
SUNXI_FUNCTION(0x3, "lvds0"), /* VN3 */
SUNXI_FUNCTION(0x4, "emac")), /* ECLKIN */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "pwm"), /* PWM0 */
SUNXI_FUNCTION(0x4, "emac")), /* EMDC */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x4, "emac")), /* EMDIO */
SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out")),
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* PCK */
SUNXI_FUNCTION(0x4, "ts0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* CK */
SUNXI_FUNCTION(0x4, "ts0")), /* ERR */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* HSYNC */
SUNXI_FUNCTION(0x4, "ts0")), /* SYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* VSYNC */
SUNXI_FUNCTION(0x4, "ts0")), /* DVLD */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D0 */
SUNXI_FUNCTION(0x4, "ts0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D1 */
SUNXI_FUNCTION(0x4, "ts0")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D2 */
SUNXI_FUNCTION(0x4, "ts0")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D3 */
SUNXI_FUNCTION(0x4, "ts0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D4 */
SUNXI_FUNCTION(0x4, "ts0")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D5 */
SUNXI_FUNCTION(0x4, "ts0")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D6 */
SUNXI_FUNCTION(0x4, "ts0")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0"), /* D7 */
SUNXI_FUNCTION(0x4, "ts0")), /* D7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "csi0")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "pll"), /* LOCK_DBG */
SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out")),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out")),
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
SUNXI_FUNCTION(0x3, "jtag")), /* MSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
SUNXI_FUNCTION(0x3, "jtag")), /* DI1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
SUNXI_FUNCTION(0x3, "uart0")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
SUNXI_FUNCTION(0x3, "jtag")), /* DO1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
SUNXI_FUNCTION(0x4, "uart0")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
SUNXI_FUNCTION(0x3, "jtag")), /* CK1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out")),
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* EINT0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* EINT1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* EINT2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* EINT4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* EINT5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart1"), /* TX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* EINT6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart1"), /* RX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* EINT7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart1"), /* RTS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)), /* EINT8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart1"), /* CTS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)), /* EINT9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif3"), /* SYNC */
SUNXI_FUNCTION(0x3, "i2s1"), /* SYNC */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)), /* EINT10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif3"), /* BCLK */
SUNXI_FUNCTION(0x3, "i2s1"), /* BCLK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)), /* EINT11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif3"), /* DOUT */
SUNXI_FUNCTION(0x3, "i2s1"), /* DOUT */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)), /* EINT12 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "aif3"), /* DIN */
SUNXI_FUNCTION(0x3, "i2s1"), /* DIN */
SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)), /* EINT13 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "i2c0"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* EINT0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "i2c0"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* EINT1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "i2c1"), /* SCK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* EINT2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "i2c1"), /* SDA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart3"), /* TX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* EINT4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart3"), /* RX */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* EINT5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart3"), /* RTS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* EINT6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "uart3"), /* CTS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* EINT7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "spdif"), /* OUT */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* EINT8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* EINT9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mic"), /* CLK */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* EINT10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "mic"), /* DATA */
SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* EINT11 */
+};
+const struct sunxi_pinctrl_desc a64_pinctrl_data = {
.pins = a64_pins,
.npins = ARRAY_SIZE(a64_pins),
.irq_banks = 3,
+}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c new file mode 100644 index 0000000..36579b1 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,326 @@ +/*
- (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
- In parts based on linux/drivers/pinctrl/pinctrl-sunxi.c, which is
- Copyright (C) 2012 Maxime Ripard
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/gpio.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/gpio/gpio.h> +#include "pinctrl-sunxi.h"
+DECLARE_GLOBAL_DATA_PTR;
+struct sunxi_pctrl_priv {
void *base;
+};
+static int sunxi_pctrl_parse_drive_prop(const void *blob, int node) +{
int val;
/* Try the new style binding */
val = fdtdec_get_int(blob, node, "drive-strength", -EINVAL);
if (val >= 0) {
/* We can't go below 10mA ... */
if (val < 10)
return -EINVAL;
/* ... and only up to 40 mA ... */
if (val > 40)
val = 40;
/* by steps of 10 mA */
return rounddown(val, 10);
}
/* And then fall back to the old binding */
val = fdtdec_get_int(blob, node, "allwinner,drive", -EINVAL);
if (val < 0)
return -EINVAL;
return (val + 1) * 10;
+}
+static int sunxi_pctrl_parse_bias_prop(const void *blob, int node) +{
/* Try the new style binding */
if (fdtdec_get_bool(blob, node, "bias-pull-up"))
return SUN4I_PINCTRL_PULL_UP;
if (fdtdec_get_bool(blob, node, "bias-pull-down"))
return SUN4I_PINCTRL_PULL_DOWN;
if (fdtdec_get_bool(blob, node, "bias-disable"))
return SUN4I_PINCTRL_NO_PULL;
/* And fall back to the old binding */
return fdtdec_get_int(blob, node, "allwinner,pull", -EINVAL);
+}
+static const struct sunxi_desc_pin *sunxi_pctrl_pin_by_name(struct udevice *dev,
const char *name)
+{
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
int i;
for (i = 0; i < data->npins; ++i)
if (!strcmp(data->pins[i].pin.name, name))
return &data->pins[i];
return NULL;
+}
+static int sunxi_pctrl_muxval_by_name(const struct sunxi_desc_pin *pin,
const char *name)
+{
const struct sunxi_desc_function *func;
if (!pin)
return -EINVAL;
for (func = pin->functions; func->name; func++)
if (!strcmp(func->name, name))
return func->muxval;
return -ENOENT;
+}
+static void sunxi_pctrl_set_function(struct udevice *dev,
unsigned pin, int function)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (function < 0)
return;
pin -= data->pin_base;
mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
val = function << sunxi_mux_offset(pin);
clrsetbits_le32(priv->base + sunxi_mux_reg(pin), mask, val);
+}
+static void sunxi_pctrl_set_dlevel(struct udevice *dev,
unsigned pin, int dlevel)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (dlevel < 0)
return;
pin -= data->pin_base;
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
val = dlevel << sunxi_dlevel_offset(pin);
clrsetbits_le32(priv->base + sunxi_dlevel_reg(pin), mask, val);
+}
+static void sunxi_pctrl_set_bias(struct udevice *dev,
unsigned pin, int bias)
+{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
u32 val, mask;
if (bias < 0)
return;
pin -= data->pin_base;
mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
val = bias << sunxi_pull_offset(pin);
clrsetbits_le32(priv->base + sunxi_pull_reg(pin), mask, val);
+}
+static int sunxi_pctrl_set_state(struct udevice *dev, struct udevice *config) +{
const char *pins;
const char *function;
int flen;
int len, curr_len;
int drive, bias;
int muxval;
debug("%s: %s %s\n", __func__, dev->name, config->name);
pins = fdt_getprop(gd->fdt_blob, config->of_offset,
"allwinner,pins", &len);
if (!pins) {
debug("%s: missing allwinner,pins property in node %s\n",
dev->name, config->name);
return -EINVAL;
}
function = fdt_getprop(gd->fdt_blob, config->of_offset,
"allwinner,function", &flen);
if (!function) {
debug("%s: missing allwinner,function property in node %s\n",
dev->name, config->name);
return -EINVAL;
}
drive = sunxi_pctrl_parse_drive_prop(gd->fdt_blob, config->of_offset);
bias = sunxi_pctrl_parse_bias_prop(gd->fdt_blob, config->of_offset);
debug("%s: function %s, drive %d, bias %d\n",
config->name, function, drive, bias);
/* Iterate through the pins and configure each */
while (len && (curr_len = strnlen(pins, len))) {
const struct sunxi_desc_pin *pin;
if (curr_len == len) {
error("%s: unterminated string?", __func__);
break;
}
pin = sunxi_pctrl_pin_by_name(dev, pins);
if (pin) {
muxval = sunxi_pctrl_muxval_by_name(pin, function);
sunxi_pctrl_set_function(dev, pin->pin.number, muxval);
sunxi_pctrl_set_dlevel(dev, pin->pin.number, drive);
sunxi_pctrl_set_bias(dev, pin->pin.number, bias);
} else {
debug("%s: could not find pin %s\n", dev->name, pins);
}
/* advance */
pins += (curr_len + 1);
len -= (curr_len + 1);
}
return 0;
+}
+static int sunxi_pctrl_probe(struct udevice *dev) +{
struct sunxi_pctrl_priv *priv = dev_get_priv(dev);
+#if CONFIG_DM_GPIO
struct udevice *gpiobridge;
+#endif
fdt_addr_t addr_base;
fdt_size_t size;
addr_base = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob,
dev->of_offset,
"reg", 0, &size,
false);
if (addr_base == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = (void *)addr_base;
+#if CONFIG_DM_GPIO
device_bind_driver_to_node(dev, "sunxi_pctrl_gpiobridge",
"gpiobridge", dev->of_offset, &gpiobridge);
/* The new device will have been created with no driver data,
so we need to set it here, as it contains the pin_base of
the gpio-group. */
if (gpiobridge)
gpiobridge->driver_data = dev_get_driver_data(dev);
+#endif
return 0;
+}
+static struct pinctrl_ops sunxi_pctrl_ops = {
.set_state = sunxi_pctrl_set_state,
+};
+#if defined(CONFIG_MACH_SUN50I) +extern const struct sunxi_pinctrl_desc a64_pinctrl_data; +extern const struct sunxi_pinctrl_desc a64_r_pinctrl_data; +#endif
+static const struct udevice_id sunxi_pctrl_ids[] = { +#if defined(CONFIG_MACH_SUN50I)
{ .compatible = "allwinner,sun50i-a64-pinctrl",
.data = (ulong)&a64_pinctrl_data },
{ .compatible = "allwinner,sun50i-a64-r-pinctrl",
.data = (ulong)&a64_r_pinctrl_data },
+#endif
{ }
+};
+U_BOOT_DRIVER(pinctrl_sunxi) = {
.name = "sunxi_pctrl",
.id = UCLASS_PINCTRL,
.of_match = sunxi_pctrl_ids,
.priv_auto_alloc_size = sizeof(struct sunxi_pctrl_priv),
.ops = &sunxi_pctrl_ops,
.bind = dm_scan_fdt_dev,
.probe = sunxi_pctrl_probe,
+};
+#if defined(CONFIG_DM_GPIO) +/* The gpiobridge exists to translate <&pio 3 24 GPIO_ACTIVE_LOW> into the
- underlying GPIO bank. It needs to access/understand the driver-data for
- the pinctrl device, so it lives here instead of in sunxi_gpio.c ... */
+static int sunxi_gpiobridge_xlate(struct udevice *dev, struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
+{
const struct sunxi_pinctrl_desc *data =
(struct sunxi_pinctrl_desc *)dev_get_driver_data(dev);
struct udevice *gpiobank;
char name[3] = {'P', 'A', '\0' };
if (!data) {
debug("%s: no driver_data\n", dev->name);
return -ENOENT;
}
/* Naming on each pinctrl may start with an offset (e.g. R_PIO
usually starts at 'PL'). */
name[1] += data->pin_base / PINS_PER_BANK;
/* Now add the bank-number within this pinctrl */
name[1] += args->args[0];
for (uclass_first_device(UCLASS_GPIO, &gpiobank);
gpiobank;
uclass_next_device(&gpiobank)) {
int count;
const char *bank_name = gpio_get_bank_info(gpiobank, &count);
if (bank_name && !strcmp(bank_name, name)) {
desc->dev = gpiobank;
desc->offset = args->args[1];
desc->flags = args->args[2] & (GPIO_ACTIVE_LOW ?
GPIOD_ACTIVE_LOW : 0);
return 0;
}
}
return -ENOENT;
+}
+static const struct dm_gpio_ops gpiobridge_sunxi_ops = {
.xlate = sunxi_gpiobridge_xlate,
+};
+U_BOOT_DRIVER(gpiobridge_sunxi) = {
.name = "sunxi_pctrl_gpiobridge",
.id = UCLASS_GPIO,
.ops = &gpiobridge_sunxi_ops,
+}; +#endif /* DM_GPIO */ diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h new file mode 100644 index 0000000..8508626 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -0,0 +1,311 @@ +/*
- Allwinner A1X SoCs pinctrl driver.
- Copyright (C) 2012 Maxime Ripard
- Maxime Ripard maxime.ripard@free-electrons.com
- This file is licensed under the terms of the GNU General Public
- License version 2. This program is licensed "as is" without any
- warranty of any kind, whether express or implied.
- */
+#ifndef __PINCTRL_SUNXI_H +#define __PINCTRL_SUNXI_H
+#define PA_BASE 0 +#define PB_BASE 32 +#define PC_BASE 64 +#define PD_BASE 96 +#define PE_BASE 128 +#define PF_BASE 160 +#define PG_BASE 192 +#define PH_BASE 224 +#define PI_BASE 256 +#define PL_BASE 352 +#define PM_BASE 384 +#define PN_BASE 416
+#ifdef __UBOOT__ +/* Convenience macro to define a single named or anonymous pin descriptor */ +#define PINCTRL_PIN(a, b) { .number = a, .name = b }
+/**
- struct pinctrl_pin_desc - boards/machines provide information on their
- pins, pads or other muxable units in this struct
- @number: unique pin number from the global pin number space
- @name: a name for this pin
- @drv_data: driver-defined per-pin data. pinctrl core does not touch this
- */
+struct pinctrl_pin_desc {
unsigned number;
const char *name;
+#ifndef __UBOOT__
void *drv_data;
+#endif +}; +#endif
+#define SUNXI_PINCTRL_PIN(bank, pin) \
PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin)
+#define SUNXI_PIN_NAME_MAX_LEN 5
+#define BANK_MEM_SIZE 0x24 +#define MUX_REGS_OFFSET 0x0 +#define DATA_REGS_OFFSET 0x10 +#define DLEVEL_REGS_OFFSET 0x14 +#define PULL_REGS_OFFSET 0x1c
+#define PINS_PER_BANK 32 +#define MUX_PINS_PER_REG 8 +#define MUX_PINS_BITS 4 +#define MUX_PINS_MASK 0x0f +#define DATA_PINS_PER_REG 32 +#define DATA_PINS_BITS 1 +#define DATA_PINS_MASK 0x01 +#define DLEVEL_PINS_PER_REG 16 +#define DLEVEL_PINS_BITS 2 +#define DLEVEL_PINS_MASK 0x03 +#define PULL_PINS_PER_REG 16 +#define PULL_PINS_BITS 2 +#define PULL_PINS_MASK 0x03
+#define IRQ_PER_BANK 32
+#define IRQ_CFG_REG 0x200 +#define IRQ_CFG_IRQ_PER_REG 8 +#define IRQ_CFG_IRQ_BITS 4 +#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1) +#define IRQ_CTRL_REG 0x210 +#define IRQ_CTRL_IRQ_PER_REG 32 +#define IRQ_CTRL_IRQ_BITS 1 +#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1) +#define IRQ_STATUS_REG 0x214 +#define IRQ_STATUS_IRQ_PER_REG 32 +#define IRQ_STATUS_IRQ_BITS 1 +#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
+#define IRQ_MEM_SIZE 0x20
+#define IRQ_EDGE_RISING 0x00 +#define IRQ_EDGE_FALLING 0x01 +#define IRQ_LEVEL_HIGH 0x02 +#define IRQ_LEVEL_LOW 0x03 +#define IRQ_EDGE_BOTH 0x04
+#define SUN4I_FUNC_INPUT 0 +#define SUN4I_FUNC_IRQ 6
+struct sunxi_desc_function {
const char *name;
u8 muxval;
u8 irqbank;
u8 irqnum;
+};
+struct sunxi_desc_pin {
struct pinctrl_pin_desc pin;
struct sunxi_desc_function *functions;
+};
+struct sunxi_pinctrl_desc {
const struct sunxi_desc_pin *pins;
int npins;
unsigned pin_base;
unsigned irq_banks;
unsigned irq_bank_base;
bool irq_read_needs_mux;
+};
+struct sunxi_pinctrl_function {
const char *name;
const char **groups;
unsigned ngroups;
+};
+struct sunxi_pinctrl_group {
const char *name;
unsigned long config;
unsigned pin;
+};
+#ifndef __UBOOT__ +struct sunxi_pinctrl {
void __iomem *membase;
struct gpio_chip *chip;
const struct sunxi_pinctrl_desc *desc;
struct device *dev;
struct irq_domain *domain;
struct sunxi_pinctrl_function *functions;
unsigned nfunctions;
struct sunxi_pinctrl_group *groups;
unsigned ngroups;
int *irq;
unsigned *irq_array;
spinlock_t lock;
struct pinctrl_dev *pctl_dev;
+}; +#endif
+#define SUNXI_PIN(_pin, ...) \
{ \
.pin = _pin, \
.functions = (struct sunxi_desc_function[]){ \
__VA_ARGS__, { } }, \
}
+#define SUNXI_FUNCTION(_val, _name) \
{ \
.name = _name, \
.muxval = _val, \
}
+#define SUNXI_FUNCTION_IRQ(_val, _irq) \
{ \
.name = "irq", \
.muxval = _val, \
.irqnum = _irq, \
}
+#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq) \
{ \
.name = "irq", \
.muxval = _val, \
.irqbank = _bank, \
.irqnum = _irq, \
}
+/*
- The sunXi PIO registers are organized as is:
- 0x00 - 0x0c Muxing values.
8 pins per register, each pin having a 4bits value
- 0x10 Pin values
32 bits per register, each pin corresponding to one bit
- 0x14 - 0x18 Drive level
16 pins per register, each pin having a 2bits value
- 0x1c - 0x20 Pull-Up values
16 pins per register, each pin having a 2bits value
- This is for the first bank. Each bank will have the same layout,
- with an offset being a multiple of 0x24.
- The following functions calculate from the pin number the register
- and the bit offset that we should access.
- */
+static inline u32 sunxi_mux_reg(u16 pin) +{
u8 bank = pin / PINS_PER_BANK;
u32 offset = bank * BANK_MEM_SIZE;
offset += MUX_REGS_OFFSET;
offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
return round_down(offset, 4);
+}
+static inline u32 sunxi_mux_offset(u16 pin) +{
u32 pin_num = pin % MUX_PINS_PER_REG;
return pin_num * MUX_PINS_BITS;
+}
+static inline u32 sunxi_data_reg(u16 pin) +{
u8 bank = pin / PINS_PER_BANK;
u32 offset = bank * BANK_MEM_SIZE;
offset += DATA_REGS_OFFSET;
offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
return round_down(offset, 4);
+}
+static inline u32 sunxi_data_offset(u16 pin) +{
u32 pin_num = pin % DATA_PINS_PER_REG;
return pin_num * DATA_PINS_BITS;
+}
+static inline u32 sunxi_dlevel_reg(u16 pin) +{
u8 bank = pin / PINS_PER_BANK;
u32 offset = bank * BANK_MEM_SIZE;
offset += DLEVEL_REGS_OFFSET;
offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
return round_down(offset, 4);
+}
+static inline u32 sunxi_dlevel_offset(u16 pin) +{
u32 pin_num = pin % DLEVEL_PINS_PER_REG;
return pin_num * DLEVEL_PINS_BITS;
+}
+static inline u32 sunxi_pull_reg(u16 pin) +{
u8 bank = pin / PINS_PER_BANK;
u32 offset = bank * BANK_MEM_SIZE;
offset += PULL_REGS_OFFSET;
offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
return round_down(offset, 4);
+}
+static inline u32 sunxi_pull_offset(u16 pin) +{
u32 pin_num = pin % PULL_PINS_PER_REG;
return pin_num * PULL_PINS_BITS;
+}
+static inline u32 sunxi_irq_cfg_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04;
return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg;
+}
+static inline u32 sunxi_irq_cfg_offset(u16 irq) +{
u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG;
return irq_num * IRQ_CFG_IRQ_BITS;
+}
+static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base) +{
return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
return sunxi_irq_ctrl_reg_from_bank(bank, bank_base);
+}
+static inline u32 sunxi_irq_ctrl_offset(u16 irq) +{
u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG;
return irq_num * IRQ_CTRL_IRQ_BITS;
+}
+static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base) +{
return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base) +{
u8 bank = irq / IRQ_PER_BANK;
return sunxi_irq_status_reg_from_bank(bank, bank_base);
+}
+static inline u32 sunxi_irq_status_offset(u16 irq) +{
u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG;
return irq_num * IRQ_STATUS_IRQ_BITS;
+}
+#ifndef __UBOOT__ +int sunxi_pinctrl_init(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc);
+#endif
+#endif /* __PINCTRL_SUNXI_H */
1.9.1

Chen,
On 21 Feb 2017, at 04:48, Chen-Yu Tsai wens@csie.org wrote:
On Sat, Feb 18, 2017 at 1:52 AM, Philipp Tomsich <philipp.tomsich@theobroma-systems.com mailto:philipp.tomsich@theobroma-systems.com> wrote:
This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are:
- implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it
- defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms:
- As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device.
- For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure.
Why is the new binding and driver necessary? The existing driver in U-boot is already DM enabled and properly xlates GPIO phandles to its child GPIO banks. I specifically fixed this in commit 4694dc56e974 ("sunxi: gpio: Add .xlate function for gpio phandle resolution”).
The problem is that all GPIO is referenced to the pinctrl-node. As we need to provide a pinctrl driver (so the configuration of pins can go through that) for the pinconfig to work, the GPIOs are then referenced to that node.
We had considered multiple solutions (a) the one we’ve chosen, which avoids having to provide additional data outside the device-tree to track the number of banks and bank-size (b) binding the existing gpio driver to the same node (but as the driverdata needs to be matched as well, we’d need to select this based on the compatible string and have a tighter coupling between the drivers than strictly necessary) (c) dynamically creating gpio subnodes (just as done by the top-level sunxi_gpio instances) for each of the banks from within the pinctrl driver
Another reason why we felt the gpiobank to be helpful is that it allows us to easily describe where the register sets (i.e. PIO and IRQ) are for each bank.
You are also not using the new gpiobank nodes anywhere in your dts changes.
The DTS change is in the same patch as the the pinctrl driver: http://lists.denx.de/pipermail/u-boot/2017-February/281637.html http://lists.denx.de/pipermail/u-boot/2017-February/281637.html
I had generated this with full function context, which makes the diff in the DTS hard to spot.
+#if defined(CONFIG_SUNXI_PINCTRL)
+/* When we use the sunxi pinctrl infrastructure, we have two issues that
- are resolved by the gpiobank and gpiobrige drivers:
- We need to have a UCLASS_GPIO device bound to the pinctrl-nodes for
- translating between gpio entries (e.g. <&pio 3 24 GPIO_ACTIVE_LOW>;)
- in the DT and actual gpio banks. This is done using the gpiobridge
- driver, which provides only a lookup/translation mechanism.
- This mechanism lives in pinctrl-sunxi.c
- We introduce a generic gpiobank device, which resolves the need to
- have distinct soc_data structure for each device and avoids having
- to share data structures and config data between this file and the
- sunxi pinctrl (the other option would be to have the soc_data info
- visible in pinctrl-sunxi.c (or merge it into this file) and bind a
- gpio_sunxi device that is set up with the appropriate soc_data) to
- the same node as the pinctrl device.
Pushing hardware internals into the DT is not preferred.
That’s exactly the point: the current DT format encapsulates the internal grouping of the hardware blocks into larger address-decoding groups. For the case of pinctrl and GPIO, the actual structure looks as follows: + “bunch of registers” + N x [pinctrl functionality for a pin-group] + N x [irq-control for a pin-group] + N x [GPIO functionality for a pin-group]
So if I were asked to model this from scratch, I’d use a regmap-device for the PIO and R_PIO address spaces and then reference the pinctrl and gpio functionality back to it (hiding the internals of how each bank assigns bits and where).
Since the pinctrl and gpio drivers actually driver the same hardware block, just in different ways, and there should be some locking between the two, I think it would make sense to merge the two.
You can also get away with not having soc_data by just registering the full set of GPIO banks and pins (we aren't counting extra pins anyway).
Merging the pinctrl and gpio drivers is going to be tricky, as a driver can only have a single class.
The more immediate solution would be to simply derive the appropriate driver data for the existing gpio class and manually bind a driver to the node (see option “b” from above).
This will then require sharing the (internal) driver data structure from the gpio-driver with pinctrl and populating it from the pinctrl probe… i.e. we had this in an earlier version of the changes, but it looked messy.
Before we revert to this model, I’ll wait if a consensus emerges from the discussion here.
Regards, Philipp.

On Tue, Feb 21, 2017 at 5:39 PM, Dr. Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
Chen,
It's ChenYu. :)
On 21 Feb 2017, at 04:48, Chen-Yu Tsai wens@csie.org wrote:
On Sat, Feb 18, 2017 at 1:52 AM, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are:
- implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it
- defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms:
- As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device.
- For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure.
Why is the new binding and driver necessary? The existing driver in U-boot is already DM enabled and properly xlates GPIO phandles to its child GPIO banks. I specifically fixed this in commit 4694dc56e974 ("sunxi: gpio: Add .xlate function for gpio phandle resolution”).
The problem is that all GPIO is referenced to the pinctrl-node. As we need to provide a pinctrl driver (so the configuration of pins can go through that) for the pinconfig to work, the GPIOs are then referenced to that node.
We had considered multiple solutions (a) the one we’ve chosen, which avoids having to provide additional data outside the device-tree to track the number of banks and bank-size
You already have this data in the pinctrl driver.
(b) binding the existing gpio driver to the same node (but as the driverdata needs to be matched as well, we’d need to select this based on the compatible string and have a tighter coupling between the drivers than strictly necessary)
They really should be the same driver. They control the same piece of hardware, just exporting different functions to the 2 subsystems. There should be proper locking between the 2, as Allwinner's hardware cannot simultaneously mux a pin to some function and provide GPIO functionality. The user should not be able to request a GPIO on a pin that is already claimed by a UART or MMC card.
(c) dynamically creating gpio subnodes (just as done by the top-level sunxi_gpio instances) for each of the banks from within the pinctrl driver
Another reason why we felt the gpiobank to be helpful is that it allows us to easily describe where the register sets (i.e. PIO and IRQ) are for each bank.
These are always at fixed multiple offsets in Allwinner's design though. The driver can always calculate which registers it needs to access from the pin name/number. IRQ bank relations are also encoded in the pinctrl tables you imported. Everything needed is available in code.
You are also not using the new gpiobank nodes anywhere in your dts changes.
The DTS change is in the same patch as the the pinctrl driver: http://lists.denx.de/pipermail/u-boot/2017-February/281637.html
I had generated this with full function context, which makes the diff in the DTS hard to spot.
What I meant was you are not actually referencing them. Since you can do without them, what's the point of adding them, beyond making the driver slightly easier to write?
+#if defined(CONFIG_SUNXI_PINCTRL)
+/* When we use the sunxi pinctrl infrastructure, we have two issues that
- are resolved by the gpiobank and gpiobrige drivers:
- We need to have a UCLASS_GPIO device bound to the pinctrl-nodes for
- translating between gpio entries (e.g. <&pio 3 24 GPIO_ACTIVE_LOW>;)
- in the DT and actual gpio banks. This is done using the gpiobridge
- driver, which provides only a lookup/translation mechanism.
- This mechanism lives in pinctrl-sunxi.c
- We introduce a generic gpiobank device, which resolves the need to
- have distinct soc_data structure for each device and avoids having
- to share data structures and config data between this file and the
- sunxi pinctrl (the other option would be to have the soc_data info
- visible in pinctrl-sunxi.c (or merge it into this file) and bind a
- gpio_sunxi device that is set up with the appropriate soc_data) to
- the same node as the pinctrl device.
Pushing hardware internals into the DT is not preferred.
That’s exactly the point: the current DT format encapsulates the internal grouping of the hardware blocks into larger address-decoding groups. For the case of pinctrl and GPIO, the actual structure looks as follows:
- “bunch of registers”
- N x [pinctrl functionality for a pin-group]
- N x [irq-control for a pin-group]
- N x [GPIO functionality for a pin-group]
Which are part of the same hardware block, which exposes N x M pins with varying functionality.
So if I were asked to model this from scratch, I’d use a regmap-device for the PIO and R_PIO address spaces and then reference the pinctrl and gpio functionality back to it (hiding the internals of how each bank assigns bits and where).
However we have an existing binding that should be followed, unless something is seriously wrong with it, then it should be fixed. Also, AFAIK U-boot sunxi treats the kernel as the canonical source for device tree files and bindings.
Since the pinctrl and gpio drivers actually driver the same hardware block, just in different ways, and there should be some locking between the two, I think it would make sense to merge the two.
You can also get away with not having soc_data by just registering the full set of GPIO banks and pins (we aren't counting extra pins anyway).
Merging the pinctrl and gpio drivers is going to be tricky, as a driver can only have a single class.
The more immediate solution would be to simply derive the appropriate driver data for the existing gpio class and manually bind a driver to the node (see option “b” from above).
This will then require sharing the (internal) driver data structure from the gpio-driver with pinctrl and populating it from the pinctrl probe… i.e. we had this in an earlier version of the changes, but it looked messy.
The Linux kernel driver also has pinctrl and gpio in the same driver. However the difference is that the kernel probes device tree nodes as platform devices, and the device driver then registers pinctrl and gpio functions.
The U-boot model is a simplified one assuming that one device only has one function, which is not always true. You're going to run into the same issue with the CCU, which provides clocks and reset controls.
Regards ChenYu
Before we revert to this model, I’ll wait if a consensus emerges from the discussion here.
Regards, Philipp.

ChenYu,
On 22 Feb 2017, at 07:07, Chen-Yu Tsai wens@csie.org wrote:
(b) binding the existing gpio driver to the same node (but as the driverdata needs to be matched as well, we’d need to select this based on the compatible string and have a tighter coupling between the drivers than strictly necessary)
They really should be the same driver. They control the same piece of hardware, just exporting different functions to the 2 subsystems. There should be proper locking between the 2, as Allwinner's hardware cannot simultaneously mux a pin to some function and provide GPIO functionality. The user should not be able to request a GPIO on a pin that is already claimed by a UART or MMC card.
This is already being revised, although (with the user being able to change the function assignment via mw.l — which we use a lot during bringup ourselves) the data used by the driver might get modified hardware (as we fetch the latest info directly from the hardware at all times).
Stay tuned for v2...
(c) dynamically creating gpio subnodes (just as done by the top-level sunxi_gpio instances) for each of the banks from within the pinctrl driver
Another reason why we felt the gpiobank to be helpful is that it allows us to easily describe where the register sets (i.e. PIO and IRQ) are for each bank.
These are always at fixed multiple offsets in Allwinner's design though. The driver can always calculate which registers it needs to access from the pin name/number. IRQ bank relations are also encoded in the pinctrl tables you imported. Everything needed is available in code.
I have to disagree on the ext-interrupt aspect of the pinctrl. E.g. on the A31, we had ext-interrupt for PA at 0x200 and PB at 0x200, while it’s now
Doesn’t really matter at this point though, as a new version with the changes requested by you and Maxime will be coming shortly.
This will then require sharing the (internal) driver data structure from the gpio-driver with pinctrl and populating it from the pinctrl probe… i.e. we had this in an earlier version of the changes, but it looked messy.
The Linux kernel driver also has pinctrl and gpio in the same driver. However the difference is that the kernel probes device tree nodes as platform devices, and the device driver then registers pinctrl and gpio functions.
The U-boot model is a simplified one assuming that one device only has one function, which is not always true. You're going to run into the same issue with the CCU, which provides clocks and reset controls.
I fully agree, but didn’t want to open a question regarding whether the device tree parsing and driver instantiation in U-Boot should be extended in a similar way (i.e. continue looking for drivers that match a node beyond the first match) at this stage.
We might in fact want to propose both solutions now, as we may need to have a discussion about this...
Regards, Philipp.

Hi Philipp,
On Fri, Feb 17, 2017 at 06:52:39PM +0100, Philipp Tomsich wrote:
This change adds a full device-model pinctrl driver for sunxi (tested with sun50iw1p1) based on the support available in Linux.
Details are:
- implements a driver for pinctrl devices and assigns sun50i-a64-pinctrl and sun50i-a64-r-pinctrl to it
- defines and implements a binding for sunxi-style GPIO banks (to make it easier to describe controllers like the A64 which may not start at 'A') and provide the necessary translation mechanisms:
- As all our gpio-reference point back to either <&pio ..> or <&r_pio ..> the device framework will try to access a UCLASS_GPIO device bound to the same node id as the pinctrl device to perform it's of_xlate lookup. For this, we provide a 'gpiobridge' driver (which needs to access the platdata of the pinctrl device) and which can then map accesses to an actual GPIO bank device.
- For the individual GPIO banks, we use a new driver (which shares most of its ops with the existing sunxi_gpio driver, except probe and bind) and provides configuration without any platdata structure.
- lifts and reuses the pinctrl-sunxi.h and pinctrl-sun50i-a64.c files from Linux (thanks to Maxime and Andre) and adds a pinctrl-sun50i-a64-r.c (to be picked up for inclusion into Linux again)
The active DM tree at runtime (with this enabled) should look similar to the following:
pinctrl [ + ] | |-- pinctrl@1c20800 gpio [ + ] | | |-- gpiob@24 gpio [ + ] | | |-- gpioc@48 gpio [ + ] | | |-- gpiod@6c gpio [ + ] | | |-- gpioe@90 gpio [ + ] | | |-- gpiof@b4 gpio [ + ] | | |-- gpiog@d8 gpio [ + ] | | |-- gpioh@fc pinconfig [ + ] | | |-- uart0_pins_a pinconfig [ ] | | |-- uart0_pins_b pinconfig [ ] | | |-- uart1_2pins pinconfig [ ] | | |-- uart1_4pins pinconfig [ ] | | |-- uart2_2pins pinconfig [ ] | | |-- uart2_4 pinconfig [ ] | | |-- uart3 pinconfig [ ] | | |-- uart3_2 pinconfig [ ] | | |-- uart3_4 pinconfig [ ] | | |-- uart4_2 pinconfig [ ] | | |-- uart4_4 pinconfig [ + ] | | |-- mmc0 pinconfig [ + ] | | |-- mmc0_cd_pin pinconfig [ ] | | |-- mmc1 pinconfig [ ] | | |-- mmc2 pinconfig [ + ] | | |-- mmc2_8bit pinconfig [ ] | | |-- i2c0_pins pinconfig [ ] | | |-- i2c1_pins pinconfig [ ] | | |-- i2c2_pins pinconfig [ ] | | |-- rmii_pins pinconfig [ + ] | | |-- rgmii_pins pinconfig [ + ] | | |-- spi0_pins pinconfig [ ] | | |-- spi1_pins pinconfig [ + ] | | |-- led_pins_sdio pinconfig [ + ] | | |-- ethphy_reset_pin gpio [ + ] | | `-- gpiobridge pinctrl [ + ] | |-- pinctrl@01f02c00 gpio [ + ] | | |-- gpiol@0 pinconfig [ + ] | | |-- led_pins_power gpio [ + ] | | `-- gpiobridge
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
.../pinctrl/allwinner,pinctrl.txt | 130 +++++ drivers/gpio/sunxi_gpio.c | 97 +++- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/sunxi/Makefile | 10 + drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c | 92 ++++ drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 577 +++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 326 ++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 9 files changed, 1553 insertions(+), 2 deletions(-) create mode 100644 doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64-r.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h
diff --git a/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt new file mode 100644 index 0000000..e536ea3 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,130 @@ +* Allwinner Pinmux Controller
+Allwinner integrates multiple banks (of 32 pins each) of pin-muxing, +GPIO functionality and (optional) external interrupt functionality +into a single controller.
+For each configurable pad (certain driver-cells, such as the IO from +integrated USB PHYs or DRAM, have a fixed function and can not be +configured), the muxing options (input, output or one of the several +functions) can be selected.
+The Allwinner pinctrl node contains a description of the pinctrl block +(i.e. including GPIO and external interrupt capability, if available) +and subnodes describing individual GPIO banks and pin-configuration.
+Properties for the pinctrl node:
- compatible: should be "allwinner,sun50i-pinctrl"
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- clocks: A phandle to the reference clock for this device
+Properties for the pinconfig sub-nodes:
- allwinner,pins: a list of pins (e.g. "PH2", "PH3") to configure
- allwinner,function: the name of pinmux function (e.g. "mmc2")
- drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA
- bias-pull-up
- bias-pull-down
- bias-disable (default)
+Deprecated properties for the pinconfig sub-nodes:
- allwinner,drive: one of <SUN4I_PINCTRL_10_MA>, <SUN4I_PINCTRL_20_MA>,
<SUN4I_PINCTRL_30_MA> or <SUN4I_PINCTRL_40_MA>
- allwinner,pull: one of <SUN4I_PINCTRL_NO_PULL>, <SUN4I_PINCTRL_PULL_UP>
or <SUN4I_PINCTRL_PULL_DOWN>
+Properties for the gpio sub-nodes:
- compatible: should be "allwinner,sunxi-gpiobank"
- allwinner,gpiobank-name: the name of the bank (e.g. <'A'>, <'B'>, ...)
- reg: offsets (within the address range of the enclosing pinctrl
node's address space) and length of the registers, where
- The first entry points to the mux/gpio registers.
- An (optional) second entry points to the extint registers.
Note, that the second entry should be provided, if the
interrupt property is present.
- interrupt: the interrupt used for external interrupt signalling
(should be one of the interrupts specified in the
enclosing pinctrl node)
+Example:
- pio: pinctrl@1c20800 {
compatible = "allwinner,sun50i-a64-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bus_gates 69>;
gpio-controller;
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
/* The A64 does not have bank A and leaves a hole in the
address space where it normally would be */
gpiob: gpiob@24 {
compatible = "allwinner,sunxi-gpiobank";
allwinner,gpiobank-name = <'B'>;
reg = < 0x24 0x24 >, < 0x200 0x1c >;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
};
gpioc: gpioc@48 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x48 0x24 >;
allwinner,gpiobank-name = <'C'>;
};
gpiod: gpiod@6c {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x6c 0x24 >;
allwinner,gpiobank-name = <'D'>;
};
gpioe: gpioe@90 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0x90 0x24 >;
allwinner,gpiobank-name = <'E'>;
};
gpiof: gpiof@b4 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xb4 0x24 >;
allwinner,gpiobank-name = <'F'>;
};
gpiog: gpiog@d8 {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xd8 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'G'>;
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
gpioh: gpioh@fc {
compatible = "allwinner,sunxi-gpiobank";
reg = < 0xfc 0x24 >, < 0x220 0x1c >;
allwinner,gpiobank-name = <'H'>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
};
uart0_pins_a: uart0_pins_a {
allwinner,pins = "PB8", "PB9";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
uart0_pins_b: uart0_pins_b {
allwinner,pins = "PF2", "PF3";
allwinner,function = "uart0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- };
Unfortunately, we're using the DT bindings coming from Linux, and this is not the bindings used there. For every new bindings, this should be submitted, reviewed and accepted first by the DT maintainers there.
In this case, there's no particular need to make that addition in the first place, since we can use some other means to implement that.
Maxime

To sync up with use of a pinctrl-driver and to have individual gpiobank nodes (to easier model controllers that have gaps in the use of bank numbering), this updates the DTS.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- arch/arm/dts/sun50i-a64.dtsi | 73 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index 24406d0..efed838 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -1,697 +1,762 @@ /* * Copyright (C) 2016 ARM Ltd. * based on the Allwinner H3 dtsi: * Copyright (C) 2015 Jens Kuske jenskuske@gmail.com * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual * licensing only applies to this file, and not this project as a * whole. * * a) This file 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 file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Or, alternatively, * * b) Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h>
/ { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>;
cpus { #address-cells = <1>; #size-cells = <0>;
cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0>; enable-method = "psci"; };
cpu@1 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <1>; enable-method = "psci"; };
cpu@2 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <2>; enable-method = "psci"; };
cpu@3 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <3>; enable-method = "psci"; }; };
psci { compatible = "arm,psci-0.2"; method = "smc"; };
memory { device_type = "memory"; reg = <0x40000000 0>; };
gic: interrupt-controller@1c81000 { compatible = "arm,gic-400"; interrupt-controller; #interrupt-cells = <3>; #address-cells = <0>;
reg = <0x01c81000 0x1000>, <0x01c82000 0x2000>, <0x01c84000 0x2000>, <0x01c86000 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
clocks { #address-cells = <1>; #size-cells = <1>; ranges;
osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "osc24M"; };
osc32k: osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; clock-output-names = "osc32k"; };
pll1: pll1_clk@1c20000 { #clock-cells = <0>; compatible = "allwinner,sun8i-a23-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; clock-output-names = "pll1"; };
pll6: pll6_clk@1c20028 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c20028 0x4>; clocks = <&osc24M>; clock-output-names = "pll6", "pll6x2"; };
pll6d2: pll6d2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; clock-div = <2>; clock-mult = <1>; clocks = <&pll6 0>; clock-output-names = "pll6d2"; };
pll7: pll7_clk@1c2002c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c2002c 0x4>; clocks = <&osc24M>; clock-output-names = "pll7", "pll7x2"; };
cpu: cpu_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; reg = <0x01c20050 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; clock-output-names = "cpu"; critical-clocks = <0>; };
axi: axi_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; clock-output-names = "axi"; };
ahb1: ahb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-ahb1-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; clock-output-names = "ahb1"; };
ahb2: ahb2_clk@1c2005c { #clock-cells = <0>; compatible = "allwinner,sun8i-h3-ahb2-clk"; reg = <0x01c2005c 0x4>; clocks = <&ahb1>, <&pll6d2>; clock-output-names = "ahb2"; };
apb1: apb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; clock-output-names = "apb1"; };
apb2: apb2_clk@1c20058 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6 1>, <&pll6 1>; clock-output-names = "apb2"; };
bus_gates: bus_gates_clk@1c20060 { #clock-cells = <1>; compatible = "allwinner,sun50i-a64-bus-gates-clk", "allwinner,sunxi-multi-bus-gates-clk"; reg = <0x01c20060 0x14>; ahb1_parent { clocks = <&ahb1>; clock-indices = <1>, <5>, <6>, <8>, <9>, <10>, <13>, <14>, <18>, <19>, <20>, <21>, <23>, <24>, <25>, <28>, <32>, <35>, <36>, <37>, <40>, <43>, <44>, <52>, <53>, <54>, <135>; clock-output-names = "bus_mipidsi", "bus_ce", "bus_dma", "bus_mmc0", "bus_mmc1", "bus_mmc2", "bus_nand", "bus_sdram", "bus_ts", "bus_hstimer", "bus_spi0", "bus_spi1", "bus_otg", "bus_otg_ehci0", "bus_ehci0", "bus_otg_ohci0", "bus_ve", "bus_lcd0", "bus_lcd1", "bus_deint", "bus_csi", "bus_hdmi", "bus_de", "bus_gpu", "bus_msgbox", "bus_spinlock", "bus_dbg"; }; ahb2_parent { clocks = <&ahb2>; clock-indices = <17>, <29>; clock-output-names = "bus_gmac", "bus_ohci0"; }; apb1_parent { clocks = <&apb1>; clock-indices = <64>, <65>, <69>, <72>, <76>, <77>, <78>; clock-output-names = "bus_codec", "bus_spdif", "bus_pio", "bus_ths", "bus_i2s0", "bus_i2s1", "bus_i2s2"; }; abp2_parent { clocks = <&apb2>; clock-indices = <96>, <97>, <98>, <101>, <112>, <113>, <114>, <115>, <116>; clock-output-names = "bus_i2c0", "bus_i2c1", "bus_i2c2", "bus_scr", "bus_uart0", "bus_uart1", "bus_uart2", "bus_uart3", "bus_uart4"; }; };
mmc0_clk: mmc0_clk@1c20088 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc0"; };
mmc1_clk: mmc1_clk@1c2008c { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc1"; };
mmc2_clk: mmc2_clk@1c20090 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc2"; }; };
soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges;
mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; clocks = <&bus_gates 8>, <&mmc0_clk>, <&mmc0_clk>, <&mmc0_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 8>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc1: mmc@1c10000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; clocks = <&bus_gates 9>, <&mmc1_clk>, <&mmc1_clk>, <&mmc1_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 9>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc2: mmc@1c11000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; clocks = <&bus_gates 10>, <&mmc2_clk>, <&mmc2_clk>, <&mmc2_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 10>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 69>; + gpio-controller; #gpio-cells = <3>; + interrupt-controller; #interrupt-cells = <2>;
- uart0_pins_a: uart0@0 { + #address-cells = <1>; + #size-cells = <1>; + + /* The A64 does not have bank A and leaves a hole in the + address space where it normally would be */ + + gpiob: gpiob@24 { + compatible = "allwinner,sunxi-gpiobank"; + allwinner,gpiobank-name = <'B'>; + reg = < 0x24 0x24 >, < 0x200 0x1c >; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpioc: gpioc@48 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x48 0x24 >; + allwinner,gpiobank-name = <'C'>; + }; + + gpiod: gpiod@6c { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x6c 0x24 >; + allwinner,gpiobank-name = <'D'>; + }; + + gpioe: gpioe@90 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0x90 0x24 >; + allwinner,gpiobank-name = <'E'>; + }; + + gpiof: gpiof@b4 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xb4 0x24 >; + allwinner,gpiobank-name = <'F'>; + }; + + gpiog: gpiog@d8 { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xd8 0x24 >, < 0x220 0x1c >; + allwinner,gpiobank-name = <'G'>; + interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpioh: gpioh@fc { + compatible = "allwinner,sunxi-gpiobank"; + reg = < 0xfc 0x24 >, < 0x220 0x1c >; + allwinner,gpiobank-name = <'H'>; + interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart0_pins_b: uart0@1 { allwinner,pins = "PF2", "PF3"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_2pins: uart1_2@0 { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_4pins: uart1_4@0 { allwinner,pins = "PG6", "PG7", "PG8", "PG9"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_2pins: uart2_2@0 { allwinner,pins = "PB0", "PB1"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_4pins: uart2_4@0 { allwinner,pins = "PB0", "PB1", "PB2", "PB3"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_pins_a: uart3@0 { allwinner,pins = "PD0", "PD1"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_2pins_b: uart3_2@1 { allwinner,pins = "PH4", "PH5"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_4pins_b: uart3_4@1 { allwinner,pins = "PH4", "PH5", "PH6", "PH7"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_2pins: uart4_2@0 { allwinner,pins = "PD2", "PD3"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_4pins: uart4_4@0 { allwinner,pins = "PD2", "PD3", "PD4", "PD5"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
mmc0_pins: mmc0@0 { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
mmc0_default_cd_pin: mmc0_cd_pin@0 { allwinner,pins = "PF6"; allwinner,function = "gpio_in"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_PULL_UP>; };
mmc1_pins: mmc1@0 { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
mmc2_pins: mmc2@0 { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c0_pins: i2c0_pins { allwinner,pins = "PH0", "PH1"; allwinner,function = "i2c0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c1_pins: i2c1_pins { allwinner,pins = "PH2", "PH3"; allwinner,function = "i2c1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c2_pins: i2c2_pins { allwinner,pins = "PE14", "PE15"; allwinner,function = "i2c2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
rmii_pins: rmii_pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; allwinner,function = "emac"; allwinner,drive = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
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 = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; };
r_pio: pinctrl@01f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; - interrupt-controller; - #interrupt-cells = <3>; - #size-cells = <0>; #gpio-cells = <3>; + + interrupt-controller; + #interrupt-cells = <2>; + + #address-cells = <1>; + #size-cells = <1>; + + gpiol: gpiol@0 { + compatible = "allwinner,sunxi-gpiobank"; + allwinner,gpiobank-name = <'L'>; + reg = < 0x0 0x24 >, < 0x200 0x1c >; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + }; };
ahb_rst: reset@1c202c0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202c0 0xc>; };
apb1_rst: reset@1c202d0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d0 0x4>; };
apb2_rst: reset@1c202d8 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d8 0x4>; };
uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 112>; resets = <&apb2_rst 16>; status = "disabled"; };
uart1: serial@1c28400 { compatible = "snps,dw-apb-uart"; reg = <0x01c28400 0x400>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 113>; resets = <&apb2_rst 17>; status = "disabled"; };
uart2: serial@1c28800 { compatible = "snps,dw-apb-uart"; reg = <0x01c28800 0x400>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 114>; resets = <&apb2_rst 18>; status = "disabled"; };
uart3: serial@1c28c00 { compatible = "snps,dw-apb-uart"; reg = <0x01c28c00 0x400>; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 115>; resets = <&apb2_rst 19>; status = "disabled"; };
uart4: serial@1c29000 { compatible = "snps,dw-apb-uart"; reg = <0x01c29000 0x400>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 116>; resets = <&apb2_rst 20>; status = "disabled"; };
rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; };
i2c0: i2c@1c2ac00 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 96>; resets = <&apb2_rst 0>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c1: i2c@1c2b000 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b000 0x400>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 97>; resets = <&apb2_rst 1>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c2: i2c@1c2b400 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b400 0x400>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 98>; resets = <&apb2_rst 2>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
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 = <&ahb_rst 17>; reset-names = "ahb"; clocks = <&bus_gates 17>; clock-names = "ahb"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
usbphy: phy@1c1b810 { compatible = "allwinner,sun50i-a64-usb-phy", "allwinner,sun8i-a33-usb-phy"; reg = <0x01c1b810 0x14>, <0x01c1b800 0x4>; reg-names = "phy_ctrl", "pmu1"; status = "disabled"; #phy-cells = <1>; };
ehci1: usb@01c1b000 { compatible = "allwinner,sun50i-a64-ehci", "generic-ehci"; reg = <0x01c1b000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled"; };
ohci1: usb@01c1b400 { compatible = "allwinner,sun50i-a64-ohci", "generic-ohci"; reg = <0x01c1b400 0x100>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "enabled"; }; }; };

Nodes that don't contain a reg-entry should not have an @xxx name attached. To silence the dt-compiler warnings, we update the DTS.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- arch/arm/dts/sun50i-a64.dtsi | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index efed838..d592bf2 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -1,762 +1,762 @@ /* * Copyright (C) 2016 ARM Ltd. * based on the Allwinner H3 dtsi: * Copyright (C) 2015 Jens Kuske jenskuske@gmail.com * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual * licensing only applies to this file, and not this project as a * whole. * * a) This file 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 file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Or, alternatively, * * b) Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h>
/ { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>;
cpus { #address-cells = <1>; #size-cells = <0>;
cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0>; enable-method = "psci"; };
cpu@1 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <1>; enable-method = "psci"; };
cpu@2 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <2>; enable-method = "psci"; };
cpu@3 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <3>; enable-method = "psci"; }; };
psci { compatible = "arm,psci-0.2"; method = "smc"; };
- memory { + memory: memory@40000000 { device_type = "memory"; reg = <0x40000000 0>; };
gic: interrupt-controller@1c81000 { compatible = "arm,gic-400"; interrupt-controller; #interrupt-cells = <3>; #address-cells = <0>;
reg = <0x01c81000 0x1000>, <0x01c82000 0x2000>, <0x01c84000 0x2000>, <0x01c86000 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
clocks { #address-cells = <1>; #size-cells = <1>; ranges;
osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "osc24M"; };
osc32k: osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; clock-output-names = "osc32k"; };
pll1: pll1_clk@1c20000 { #clock-cells = <0>; compatible = "allwinner,sun8i-a23-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; clock-output-names = "pll1"; };
pll6: pll6_clk@1c20028 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c20028 0x4>; clocks = <&osc24M>; clock-output-names = "pll6", "pll6x2"; };
pll6d2: pll6d2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; clock-div = <2>; clock-mult = <1>; clocks = <&pll6 0>; clock-output-names = "pll6d2"; };
pll7: pll7_clk@1c2002c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c2002c 0x4>; clocks = <&osc24M>; clock-output-names = "pll7", "pll7x2"; };
cpu: cpu_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; reg = <0x01c20050 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; clock-output-names = "cpu"; critical-clocks = <0>; };
axi: axi_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; clock-output-names = "axi"; };
ahb1: ahb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-ahb1-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; clock-output-names = "ahb1"; };
ahb2: ahb2_clk@1c2005c { #clock-cells = <0>; compatible = "allwinner,sun8i-h3-ahb2-clk"; reg = <0x01c2005c 0x4>; clocks = <&ahb1>, <&pll6d2>; clock-output-names = "ahb2"; };
apb1: apb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; clock-output-names = "apb1"; };
apb2: apb2_clk@1c20058 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6 1>, <&pll6 1>; clock-output-names = "apb2"; };
bus_gates: bus_gates_clk@1c20060 { #clock-cells = <1>; compatible = "allwinner,sun50i-a64-bus-gates-clk", "allwinner,sunxi-multi-bus-gates-clk"; reg = <0x01c20060 0x14>; ahb1_parent { clocks = <&ahb1>; clock-indices = <1>, <5>, <6>, <8>, <9>, <10>, <13>, <14>, <18>, <19>, <20>, <21>, <23>, <24>, <25>, <28>, <32>, <35>, <36>, <37>, <40>, <43>, <44>, <52>, <53>, <54>, <135>; clock-output-names = "bus_mipidsi", "bus_ce", "bus_dma", "bus_mmc0", "bus_mmc1", "bus_mmc2", "bus_nand", "bus_sdram", "bus_ts", "bus_hstimer", "bus_spi0", "bus_spi1", "bus_otg", "bus_otg_ehci0", "bus_ehci0", "bus_otg_ohci0", "bus_ve", "bus_lcd0", "bus_lcd1", "bus_deint", "bus_csi", "bus_hdmi", "bus_de", "bus_gpu", "bus_msgbox", "bus_spinlock", "bus_dbg"; }; ahb2_parent { clocks = <&ahb2>; clock-indices = <17>, <29>; clock-output-names = "bus_gmac", "bus_ohci0"; }; apb1_parent { clocks = <&apb1>; clock-indices = <64>, <65>, <69>, <72>, <76>, <77>, <78>; clock-output-names = "bus_codec", "bus_spdif", "bus_pio", "bus_ths", "bus_i2s0", "bus_i2s1", "bus_i2s2"; }; abp2_parent { clocks = <&apb2>; clock-indices = <96>, <97>, <98>, <101>, <112>, <113>, <114>, <115>, <116>; clock-output-names = "bus_i2c0", "bus_i2c1", "bus_i2c2", "bus_scr", "bus_uart0", "bus_uart1", "bus_uart2", "bus_uart3", "bus_uart4"; }; };
mmc0_clk: mmc0_clk@1c20088 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc0"; };
mmc1_clk: mmc1_clk@1c2008c { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc1"; };
mmc2_clk: mmc2_clk@1c20090 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc2"; }; };
soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges;
mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; clocks = <&bus_gates 8>, <&mmc0_clk>, <&mmc0_clk>, <&mmc0_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 8>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc1: mmc@1c10000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; clocks = <&bus_gates 9>, <&mmc1_clk>, <&mmc1_clk>, <&mmc1_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 9>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc2: mmc@1c11000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; clocks = <&bus_gates 10>, <&mmc2_clk>, <&mmc2_clk>, <&mmc2_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 10>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 69>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
/* The A64 does not have bank A and leaves a hole in the address space where it normally would be */
gpiob: gpiob@24 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'B'>; reg = < 0x24 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; };
gpioc: gpioc@48 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x48 0x24 >; allwinner,gpiobank-name = <'C'>; };
gpiod: gpiod@6c { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x6c 0x24 >; allwinner,gpiobank-name = <'D'>; };
gpioe: gpioe@90 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x90 0x24 >; allwinner,gpiobank-name = <'E'>; };
gpiof: gpiof@b4 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xb4 0x24 >; allwinner,gpiobank-name = <'F'>; };
gpiog: gpiog@d8 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xd8 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'G'>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; };
gpioh: gpioh@fc { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xfc 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'H'>; interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; };
uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart0_pins_b: uart0@1 { + uart0_pins_b: uart0_pins_b { allwinner,pins = "PF2", "PF3"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart1_2pins: uart1_2@0 { + uart1_2pins: uart1_2pins { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart1_4pins: uart1_4@0 { + uart1_4pins: uart1_4pins { allwinner,pins = "PG6", "PG7", "PG8", "PG9"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart2_2pins: uart2_2@0 { + uart2_2pins: uart2_2pins { allwinner,pins = "PB0", "PB1"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart2_4pins: uart2_4@0 { + uart2_4pins: uart2_4pins { allwinner,pins = "PB0", "PB1", "PB2", "PB3"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_pins_a: uart3@0 { + uart3_pins_a: uart3_pins_a { allwinner,pins = "PD0", "PD1"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_2pins_b: uart3_2@1 { + uart3_2pins_b: uart3_2pins_b { allwinner,pins = "PH4", "PH5"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart3_4pins_b: uart3_4@1 { + uart3_4pins_b: uart3_4pins_b { allwinner,pins = "PH4", "PH5", "PH6", "PH7"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart4_2pins: uart4_2@0 { + uart4_2pins: uart4_2pins { allwinner,pins = "PD2", "PD3"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- uart4_4pins: uart4_4@0 { + uart4_4pins: uart4_4pins { allwinner,pins = "PD2", "PD3", "PD4", "PD5"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc0_pins: mmc0@0 { + mmc0_pins: mmc0_pins { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc0_default_cd_pin: mmc0_cd_pin@0 { + mmc0_default_cd_pin: mmc0_cd_pin { allwinner,pins = "PF6"; allwinner,function = "gpio_in"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_PULL_UP>; };
- mmc1_pins: mmc1@0 { + mmc1_pins: mmc1_pins { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
- mmc2_pins: mmc2@0 { + mmc2_pins: mmc2_pins { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c0_pins: i2c0_pins { allwinner,pins = "PH0", "PH1"; allwinner,function = "i2c0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c1_pins: i2c1_pins { allwinner,pins = "PH2", "PH3"; allwinner,function = "i2c1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c2_pins: i2c2_pins { allwinner,pins = "PE14", "PE15"; allwinner,function = "i2c2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
rmii_pins: rmii_pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; allwinner,function = "emac"; allwinner,drive = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
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 = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; };
r_pio: pinctrl@01f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
gpiol: gpiol@0 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'L'>; reg = < 0x0 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; }; };
ahb_rst: reset@1c202c0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202c0 0xc>; };
apb1_rst: reset@1c202d0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d0 0x4>; };
apb2_rst: reset@1c202d8 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d8 0x4>; };
uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 112>; resets = <&apb2_rst 16>; status = "disabled"; };
uart1: serial@1c28400 { compatible = "snps,dw-apb-uart"; reg = <0x01c28400 0x400>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 113>; resets = <&apb2_rst 17>; status = "disabled"; };
uart2: serial@1c28800 { compatible = "snps,dw-apb-uart"; reg = <0x01c28800 0x400>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 114>; resets = <&apb2_rst 18>; status = "disabled"; };
uart3: serial@1c28c00 { compatible = "snps,dw-apb-uart"; reg = <0x01c28c00 0x400>; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 115>; resets = <&apb2_rst 19>; status = "disabled"; };
uart4: serial@1c29000 { compatible = "snps,dw-apb-uart"; reg = <0x01c29000 0x400>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 116>; resets = <&apb2_rst 20>; status = "disabled"; };
rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; };
i2c0: i2c@1c2ac00 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 96>; resets = <&apb2_rst 0>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c1: i2c@1c2b000 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b000 0x400>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 97>; resets = <&apb2_rst 1>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c2: i2c@1c2b400 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b400 0x400>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 98>; resets = <&apb2_rst 2>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
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 = <&ahb_rst 17>; reset-names = "ahb"; clocks = <&bus_gates 17>; clock-names = "ahb"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
usbphy: phy@1c1b810 { compatible = "allwinner,sun50i-a64-usb-phy", "allwinner,sun8i-a33-usb-phy"; reg = <0x01c1b810 0x14>, <0x01c1b800 0x4>; reg-names = "phy_ctrl", "pmu1"; status = "disabled"; #phy-cells = <1>; };
ehci1: usb@01c1b000 { compatible = "allwinner,sun50i-a64-ehci", "generic-ehci"; reg = <0x01c1b000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled"; };
ohci1: usb@01c1b400 { compatible = "allwinner,sun50i-a64-ohci", "generic-ohci"; reg = <0x01c1b400 0x100>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "enabled"; }; }; };

Hi,
On Fri, Feb 17, 2017 at 06:52:41PM +0100, Philipp Tomsich wrote:
Nodes that don't contain a reg-entry should not have an @xxx name attached. To silence the dt-compiler warnings, we update the DTS.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Can you submit it to Linux as well?
arch/arm/dts/sun50i-a64.dtsi | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index efed838..d592bf2 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -1,762 +1,762 @@ /*
- Copyright (C) 2016 ARM Ltd.
- based on the Allwinner H3 dtsi:
- Copyright (C) 2015 Jens Kuske jenskuske@gmail.com
- This file is dual-licensed: you can use it either under the terms
- of the GPL or the X11 license, at your option. Note that this dual
- licensing only applies to this file, and not this project as a
- whole.
- a) This file 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 file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- Or, alternatively,
- b) Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h>
/ { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>;
cpus { #address-cells = <1>; #size-cells = <0>;
cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0>; enable-method = "psci"; }; cpu@1 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <1>; enable-method = "psci"; }; cpu@2 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <2>; enable-method = "psci"; }; cpu@3 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <3>; enable-method = "psci"; };
};
psci { compatible = "arm,psci-0.2"; method = "smc"; };
- memory {
memory: memory@40000000 { device_type = "memory"; reg = <0x40000000 0>; };
gic: interrupt-controller@1c81000 { compatible = "arm,gic-400"; interrupt-controller; #interrupt-cells = <3>; #address-cells = <0>;
reg = <0x01c81000 0x1000>, <0x01c82000 0x2000>, <0x01c84000 0x2000>, <0x01c86000 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
clocks { #address-cells = <1>; #size-cells = <1>; ranges;
osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "osc24M"; };
osc32k: osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; clock-output-names = "osc32k"; };
pll1: pll1_clk@1c20000 { #clock-cells = <0>; compatible = "allwinner,sun8i-a23-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; clock-output-names = "pll1"; };
pll6: pll6_clk@1c20028 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c20028 0x4>; clocks = <&osc24M>; clock-output-names = "pll6", "pll6x2"; };
pll6d2: pll6d2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; clock-div = <2>; clock-mult = <1>; clocks = <&pll6 0>; clock-output-names = "pll6d2"; };
pll7: pll7_clk@1c2002c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c2002c 0x4>; clocks = <&osc24M>; clock-output-names = "pll7", "pll7x2"; };
cpu: cpu_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; reg = <0x01c20050 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; clock-output-names = "cpu"; critical-clocks = <0>; };
axi: axi_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; clock-output-names = "axi"; };
ahb1: ahb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-ahb1-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; clock-output-names = "ahb1"; };
ahb2: ahb2_clk@1c2005c { #clock-cells = <0>; compatible = "allwinner,sun8i-h3-ahb2-clk"; reg = <0x01c2005c 0x4>; clocks = <&ahb1>, <&pll6d2>; clock-output-names = "ahb2"; };
apb1: apb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; clock-output-names = "apb1"; };
apb2: apb2_clk@1c20058 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6 1>, <&pll6 1>; clock-output-names = "apb2"; };
bus_gates: bus_gates_clk@1c20060 { #clock-cells = <1>; compatible = "allwinner,sun50i-a64-bus-gates-clk", "allwinner,sunxi-multi-bus-gates-clk"; reg = <0x01c20060 0x14>; ahb1_parent { clocks = <&ahb1>; clock-indices = <1>, <5>, <6>, <8>, <9>, <10>, <13>, <14>, <18>, <19>, <20>, <21>, <23>, <24>, <25>, <28>, <32>, <35>, <36>, <37>, <40>, <43>, <44>, <52>, <53>, <54>, <135>; clock-output-names = "bus_mipidsi", "bus_ce", "bus_dma", "bus_mmc0", "bus_mmc1", "bus_mmc2", "bus_nand", "bus_sdram", "bus_ts", "bus_hstimer", "bus_spi0", "bus_spi1", "bus_otg", "bus_otg_ehci0", "bus_ehci0", "bus_otg_ohci0", "bus_ve", "bus_lcd0", "bus_lcd1", "bus_deint", "bus_csi", "bus_hdmi", "bus_de", "bus_gpu", "bus_msgbox", "bus_spinlock", "bus_dbg"; }; ahb2_parent { clocks = <&ahb2>; clock-indices = <17>, <29>; clock-output-names = "bus_gmac", "bus_ohci0"; }; apb1_parent { clocks = <&apb1>; clock-indices = <64>, <65>, <69>, <72>, <76>, <77>, <78>; clock-output-names = "bus_codec", "bus_spdif", "bus_pio", "bus_ths", "bus_i2s0", "bus_i2s1", "bus_i2s2"; }; abp2_parent { clocks = <&apb2>; clock-indices = <96>, <97>, <98>, <101>, <112>, <113>, <114>, <115>, <116>; clock-output-names = "bus_i2c0", "bus_i2c1", "bus_i2c2", "bus_scr", "bus_uart0", "bus_uart1", "bus_uart2", "bus_uart3", "bus_uart4"; }; };
mmc0_clk: mmc0_clk@1c20088 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc0"; };
mmc1_clk: mmc1_clk@1c2008c { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc1"; };
mmc2_clk: mmc2_clk@1c20090 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc2"; }; };
soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges;
mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; clocks = <&bus_gates 8>, <&mmc0_clk>, <&mmc0_clk>, <&mmc0_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 8>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc1: mmc@1c10000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; clocks = <&bus_gates 9>, <&mmc1_clk>, <&mmc1_clk>, <&mmc1_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 9>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc2: mmc@1c11000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; clocks = <&bus_gates 10>, <&mmc2_clk>, <&mmc2_clk>, <&mmc2_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 10>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 69>; gpio-controller; #gpio-cells = <3>; interrupt-controller; #interrupt-cells = <2>; #address-cells = <1>; #size-cells = <1>; /* The A64 does not have bank A and leaves a hole in the address space where it normally would be */ gpiob: gpiob@24 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'B'>; reg = < 0x24 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; }; gpioc: gpioc@48 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x48 0x24 >; allwinner,gpiobank-name = <'C'>; }; gpiod: gpiod@6c { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x6c 0x24 >; allwinner,gpiobank-name = <'D'>; }; gpioe: gpioe@90 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x90 0x24 >; allwinner,gpiobank-name = <'E'>; }; gpiof: gpiof@b4 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xb4 0x24 >; allwinner,gpiobank-name = <'F'>; }; gpiog: gpiog@d8 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xd8 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'G'>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; }; gpioh: gpioh@fc { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xfc 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'H'>; interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; }; uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart0_pins_b: uart0@1 {
uart0_pins_b: uart0_pins_b {
Unfortunately, underscores are also going to generate warnings in the next dtc versions. Can you use dashes instead?
Thanks, Maxime

In order to have the device model describe the module reset bits on sunxi (well, at least for anything newer than sun6i), we need a (rather simple) driver for 'allwinner,sun6i-a31-clock-reset' nodes.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/reset/Kconfig | 9 ++++ drivers/reset/Makefile | 1 + drivers/reset/reset-sunxi.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 drivers/reset/reset-sunxi.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c42b0bc..8db25fc 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -43,4 +43,13 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block.
+config RESET_SUNXI + bool "Reset controller driver for Allwiner SoCs" + depends on DM_RESET && ARCH_SUNXI + default y + help + Support for reset controllers on Allwinner SoCs. + Say Y if you want to control reset signals provided by CCU (e.g. sun50i) + or PRCM (e.g. sun6i, sun9i) blocks. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 5c4305c..0086da9 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,10 +1,11 @@ # Copyright (c) 2016, NVIDIA CORPORATION. # # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DM_RESET) += reset-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c new file mode 100644 index 0000000..b667ca1 --- /dev/null +++ b/drivers/reset/reset-sunxi.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <reset-uclass.h> +#include <dm/device.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_reset_priv { + void __iomem *base; + size_t size; +}; + +static int sunxi_reset_request(struct reset_ctl *reset_ctl) +{ + debug("%s (%s): id %ld\n", + reset_ctl->dev->name, __func__, reset_ctl->id); + return 0; +} + +static int sunxi_reset_free(struct reset_ctl *reset_ctl) +{ + debug("%s (%s): id %ld\n", + reset_ctl->dev->name, __func__, reset_ctl->id); + return 0; +} + +static int sunxi_reset_update(struct reset_ctl *reset_ctl, bool assert) +{ + struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); + unsigned long id = reset_ctl->id; + unsigned long offset = id / 32; /* TODO: symbolic name */ + unsigned int bit = id % 32; + + debug("%s (%s): id %ld base %p offset %lx bit %d assert %d size %ld\n", + reset_ctl->dev->name, __func__, id, priv->base, offset, + bit, assert, priv->size); + + if (offset >= priv->size) + return -EINVAL; + + if (assert) + clrbits_le32(priv->base + offset, BIT(bit)); + else + setbits_le32(priv->base + offset, BIT(bit)); + + return 0; +} + +static int sunxi_reset_assert(struct reset_ctl *reset_ctl) +{ + return sunxi_reset_update(reset_ctl, true); +} + +static int sunxi_reset_deassert(struct reset_ctl *reset_ctl) +{ + return sunxi_reset_update(reset_ctl, false); +} + +static const struct reset_ops sunxi_reset_ops = { + .request = sunxi_reset_request, + .free = sunxi_reset_free, + .rst_assert = sunxi_reset_assert, + .rst_deassert = sunxi_reset_deassert, +}; + +static int sunxi_reset_probe(struct udevice *dev) +{ + struct sunxi_reset_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, + "reg", 0, &size, false); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: failed to find base address ('reg')\n", dev->name); + return -ENODEV; + } + priv->base = (void *)addr; + priv->size = size; + + if (!priv->base) + return -ENOMEM; + + return 0; +} + +static const struct udevice_id sunxi_reset_match[] = { + { .compatible = "allwinner,sun6i-a31-clock-reset" }, + { } +}; + +U_BOOT_DRIVER(sunxi_reset) = { + .name = "sunxi-reset", + .id = UCLASS_RESET, + .of_match = sunxi_reset_match, + .ops = &sunxi_reset_ops, + .priv_auto_alloc_size = sizeof(struct sunxi_reset_priv), + .probe = sunxi_reset_probe, +};

On Fri, Feb 17, 2017 at 06:52:42PM +0100, Philipp Tomsich wrote:
In order to have the device model describe the module reset bits on sunxi (well, at least for anything newer than sun6i), we need a (rather simple) driver for 'allwinner,sun6i-a31-clock-reset' nodes.
This one (and the next one) isn't the binding that we've settled for in the kernel. This DT was only one of the intermediate versions that got sent.
Maxime

When CONFIG_CLK is defined, we now provide support for the basic clock configuration of peripherals on sunxi: * clk-sunxi-mod.c implements support for module clocks, which performs parent selection (determined via the device-tree) and determines/configures a pre-divider and divider when setting a clock-rate * clk-sunxi-pll.c implements read-only (i.e. getting the rate is implemented, but setting the rate is not) access to PLLs. At this time, the necessary platform data (number of bits and position for the factors P, M, N and K) for the peripheral PLLs ('allwinner,sun6i-a31-pll6-clk') are included * clk-sunxi-gate.c: implements an clk-gate to gate individual modules (i.e. 'allwinner,sunxi-multi-bus-gates-clk')
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/clk/Makefile | 1 + drivers/clk/sunxi/Makefile | 7 ++ drivers/clk/sunxi/clk-sunxi-gate.c | 92 ++++++++++++++ drivers/clk/sunxi/clk-sunxi-mod.c | 241 +++++++++++++++++++++++++++++++++++++ drivers/clk/sunxi/clk-sunxi-pll.c | 123 +++++++++++++++++++ 5 files changed, 464 insertions(+) create mode 100644 drivers/clk/sunxi/Makefile create mode 100644 drivers/clk/sunxi/clk-sunxi-gate.c create mode 100644 drivers/clk/sunxi/clk-sunxi-mod.c create mode 100644 drivers/clk/sunxi/clk-sunxi-pll.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 884c21c..7ae8029 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -7,6 +7,7 @@
obj-$(CONFIG_CLK) += clk-uclass.o clk_fixed_rate.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile new file mode 100644 index 0000000..e37768cdd --- /dev/null +++ b/drivers/clk/sunxi/Makefile @@ -0,0 +1,7 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clk-sunxi-pll.o +obj-y += clk-sunxi-mod.o +obj-y += clk-sunxi-gate.o \ No newline at end of file diff --git a/drivers/clk/sunxi/clk-sunxi-gate.c b/drivers/clk/sunxi/clk-sunxi-gate.c new file mode 100644 index 0000000..956ba8e --- /dev/null +++ b/drivers/clk/sunxi/clk-sunxi-gate.c @@ -0,0 +1,92 @@ +/* + * (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + * + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <div64.h> +#include <wait_bit.h> +#include <dm/lists.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_clk_priv { + void *base; + size_t size; +}; + +static int sunxi_gate_update(struct clk *clk, bool enable) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + unsigned long id = clk->id; + uint32_t offset = id / 32; + uint32_t bit = id % 32; + + debug("%s (%s): id %ld base %p offset %x bit %d enable %d\n", + clk->dev->name, __func__, id, priv->base, offset, + bit, enable); + + if (enable) + setbits_le32(priv->base + offset, BIT(bit)); + else + clrbits_le32(priv->base + offset, BIT(bit)); + + return -EINVAL; +} + +static int sunxi_gate_enable(struct clk *clk) +{ + return sunxi_gate_update(clk, true); +} + +static int sunxi_gate_disable(struct clk *clk) +{ + return sunxi_gate_update(clk, false); +} + +static struct clk_ops sunxi_clk_gate_ops = { + .enable = sunxi_gate_enable, + .disable = sunxi_gate_disable, +}; + +static int sunxi_clk_gate_probe(struct udevice *dev) +{ + struct sunxi_clk_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + debug("%s: %s\n", dev->name, __func__); + + addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, + "reg", 0, &size, false); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: could not get addr\n", dev->name); + return -EINVAL; + } + + priv->base = (void *)addr; + priv->size = size; + + return 0; +} + +static const struct udevice_id sunxi_clk_gate_ids[] = { + { .compatible = "allwinner,sunxi-multi-bus-gates-clk" }, + {} +}; + +U_BOOT_DRIVER(sunxi_clk_gate) = { + .name = "sunxi_clk_gate", + .id = UCLASS_CLK, + .of_match = sunxi_clk_gate_ids, + .ops = &sunxi_clk_gate_ops, + .probe = sunxi_clk_gate_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_clk_priv), +}; + + diff --git a/drivers/clk/sunxi/clk-sunxi-mod.c b/drivers/clk/sunxi/clk-sunxi-mod.c new file mode 100644 index 0000000..4e70cc9 --- /dev/null +++ b/drivers/clk/sunxi/clk-sunxi-mod.c @@ -0,0 +1,241 @@ +/* + * (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * With sun4i_a10_get_mod0_factors(...) adapted from + * linux/drivers/clk/sunxi/clk-mod0.c + * which is + * Copyright 2013 Emilio López + * + * SPDX-License-Identifier: GPL-2.0+ + * + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <div64.h> +#include <wait_bit.h> +#include <dm/lists.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_clk_priv { + void *reg; + int num_parents; + struct clk parent[4]; +}; + +#define SRCSHIFT (24) +#define SRCMASK (0x3 << SRCSHIFT) +#define SRC(n) (n << SRCSHIFT) +#define PREDIVMASK (0x3 << 16) +#define PREDIV(n) (n << 16) +#define DIVMASK (0xf << 0) +#define DIV(n) (n) + +static ulong sunxi_mod_get_rate(struct clk *clk) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + u32 active_parent; + ulong rate = -EINVAL; + u32 regval = readl(priv->reg); + + /* if not enabled, return 0 */ + if (regval & BIT(31)) + return 0; + + active_parent = (readl(priv->reg) >> 24) & 0x3; + if (active_parent < priv->num_parents) + rate = clk_get_rate(&priv->parent[active_parent]); + + return rate; +} + +/** + * sun4i_a10_get_mod0_factors() + * - calculates m, n factors for MOD0-style clocks + * + * MOD0 rate is calculated as follows: + * rate = (parent_rate >> p) / (m + 1); + */ + +struct factors_request { + unsigned long rate; + unsigned long parent_rate; + u8 parent_index; + u8 n; + u8 k; + u8 m; + u8 p; +}; + +static void sun4i_a10_get_mod0_factors(struct factors_request *req) +{ + u8 div, calcm, calcp; + + /* These clocks can only divide, so we will never be able to + * achieve frequencies higher than the parent frequency */ + if (req->rate >= req->parent_rate) { + req->rate = req->parent_rate; + req->m = 0; + req->p = 0; + } + + div = DIV_ROUND_UP(req->parent_rate, req->rate); + + if (div < 16) + calcp = 0; + else if (div / 2 < 16) + calcp = 1; + else if (div / 4 < 16) + calcp = 2; + else + calcp = 3; + + calcm = DIV_ROUND_UP(div, 1 << calcp); + /* clamp calcm to 16, as that is the largest possible divider */ + if (calcm > 16) + calcm = 16; + + req->rate = (req->parent_rate >> calcp) / calcm; + req->m = calcm - 1; + req->p = calcp; +} + +static ulong sunxi_mod_set_rate(struct clk *clk, ulong rate) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + ulong best_rate = 0; + int i; + + debug("%s (%s): id %ld rate %ld base %p\n", + clk->dev->name, __func__, clk->id, rate, priv->reg); + + /* check if the current rate is already the target rate */ + if (sunxi_mod_get_rate(clk) == rate) + return rate; + + /* find the parent (iterate through) which allows us to have: + * fastest rate <= rate + */ + for (i = 0; i < priv->num_parents; ++i) { + ulong parent_rate = clk_get_rate(&priv->parent[i]); + struct factors_request req = { + .rate = rate, + .parent_rate = parent_rate, + .parent_index = i + }; + + debug("%s (%s): parent %d rate %ld\n", + clk->dev->name, __func__, i, parent_rate); + + if (parent_rate == -ENOSYS) { + debug("%s: parent %d does not support get_rate\n", + clk->dev->name, i); + continue; + } + + if (parent_rate == 0) { + debug("%s: parent %d seems disabled (rate == 0)\n", + clk->dev->name, i); + continue; + } + + /* We recalculate the dividers, even if the parent's + * rate is less than the requested rate + */ + sun4i_a10_get_mod0_factors(&req); + + if (req.rate > rate) { + debug("%s: rate %ld for parent %i exceeds rate\n", + clk->dev->name, req.rate, i); + continue; + } + + if (req.rate > best_rate) { + debug("%s: new best => parent %d P %d M %d rate %ld\n", + clk->dev->name, i, req.p, req.m, req.rate); + + clrsetbits_le32(priv->reg, + SRCMASK | PREDIVMASK | DIVMASK, + SRC(i) | PREDIV(req.p) | DIV(req.m)); + best_rate = req.rate; + + /* don't continue, if this is the requested rate */ + if (best_rate == rate) + break; + } + } + + return best_rate; +} + +static int sunxi_mod_enable(struct clk *clk) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + + setbits_le32(priv->reg, BIT(31)); + return 0; +} + +static int sunxi_mod_disable(struct clk *clk) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + + clrbits_le32(priv->reg, BIT(31)); + return 0; +} + +static struct clk_ops sunxi_clk_mod_ops = { + .set_rate = sunxi_mod_set_rate, + .get_rate = sunxi_mod_get_rate, + .enable = sunxi_mod_enable, + .disable = sunxi_mod_disable, +}; + +static int sunxi_clk_mod_probe(struct udevice *dev) +{ + struct sunxi_clk_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + int i; + + debug("%s: %s\n", dev->name, __func__); + + addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, + "reg", 0, &size, false); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: could not get addr\n", dev->name); + return -EINVAL; + } + + priv->reg = (void *)addr; + + for (i = 0; i < 4; ++i) { + int ret = clk_get_by_index(dev, i, &priv->parent[i]); + if (ret != 0) + break; + }; + priv->num_parents = i; + + debug("%s: reg %p num-parents %d\n", + dev->name, priv->reg, priv->num_parents); + return 0; +} + +static const struct udevice_id sunxi_clk_mod_ids[] = { + { .compatible = "allwinner,sun4i-a10-mod0-clk" }, + {} +}; + +U_BOOT_DRIVER(sunxi_clk_mod) = { + .name = "sunxi_clk_mod", + .id = UCLASS_CLK, + .of_match = sunxi_clk_mod_ids, + .ops = &sunxi_clk_mod_ops, + .probe = sunxi_clk_mod_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_clk_priv), +}; + + diff --git a/drivers/clk/sunxi/clk-sunxi-pll.c b/drivers/clk/sunxi/clk-sunxi-pll.c new file mode 100644 index 0000000..7c82ccf --- /dev/null +++ b/drivers/clk/sunxi/clk-sunxi-pll.c @@ -0,0 +1,123 @@ +/* + * (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + * + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <div64.h> +#include <wait_bit.h> +#include <dm/lists.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_clk_pll_data { + u8 nshift; + u8 nwidth; + u8 kshift; + u8 kwidth; + u8 mshift; + u8 mwidth; + u8 pshift; + u8 pwidth; + u8 n_start; +}; + +struct sunxi_clk_priv { + void *reg; +}; + +static inline uint32_t bitmask(uint8_t width, uint8_t shift) +{ + return ((1U << width) - 1) << shift; +} + +static inline uint32_t factor_extract(uint32_t regval, + uint8_t width, + uint8_t shift) +{ + return ((regval & bitmask(width, shift)) >> shift) + 1; +} + +static ulong sunxi_pll_get_rate(struct clk *clk) +{ + struct sunxi_clk_priv *priv = dev_get_priv(clk->dev); + struct sunxi_clk_pll_data *data = + (struct sunxi_clk_pll_data *)dev_get_driver_data(clk->dev); + uint32_t regval = readl(priv->reg); + int n = factor_extract(regval, data->nwidth, data->nshift); + int k = factor_extract(regval, data->kwidth, data->kshift); + int m = factor_extract(regval, data->mwidth, data->mshift); + ulong rate = (24000000 * n * k) / m; + + debug("%s (%s): id %ld base %p\n", + clk->dev->name, __func__, clk->id, priv->reg); + + /* Check if the PLL is enabled... */ + if (!(regval & BIT(31))) + return 0; + + debug("%s: n %d k %d m %d\n", clk->dev->name, n, k, m); + debug("%s: rate %ld\n", clk->dev->name, rate); + + if (clk->id == 1) + return 2 * rate; + + return rate; +} + +static struct clk_ops sunxi_clk_pll_ops = { + /* For now, we'll let the arch/board-specific code setup the + PLLs through the legacy implementation (some of this will + happen in SPL, which may not have device model capability) + and we only read the PLL rates. */ + .get_rate = sunxi_pll_get_rate, +}; + +static int sunxi_clk_pll_probe(struct udevice *dev) +{ + struct sunxi_clk_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, + "reg", 0, &size, false); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->reg = (void *)addr; + if (!priv->reg) + return -EINVAL; + + debug("%s: reg %p\n", dev->name, priv->reg); + + return 0; +} + +static struct sunxi_clk_pll_data pll6_data = { + .nwidth = 5, + .nshift = 8, + .kwidth = 2, + .kshift = 4, + .mwidth = 2, + .mshift = 0, +}; + +static const struct udevice_id sunxi_clk_pll_ids[] = { + { .compatible = "allwinner,sun6i-a31-pll6-clk", + .data = (uintptr_t)&pll6_data }, + {} +}; + +U_BOOT_DRIVER(sunxi_clk_pll) = { + .name = "sunxi_clk_pll", + .id = UCLASS_CLK, + .of_match = sunxi_clk_pll_ids, + .ops = &sunxi_clk_pll_ops, + .probe = sunxi_clk_pll_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_clk_priv), +};

Moving to a DT-based clock framework on sunxi requires the subnodes of /clocks to be bound on boot-up. As /clocks does not contain a compatible-string, the U-Boot DT parsing code ignores it (and any subnodes). To overcome this limitation, the sunxi board-init code retrieves the /clocks node and explicitly starts a DM scan of the subnodes.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- board/sunxi/board.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 89edf2e..838e89f 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -1,39 +1,40 @@ /* * (C) Copyright 2012-2013 Henrik Nordstrom henrik@henriknordstrom.net * (C) Copyright 2013 Luke Kenneth Casson Leighton lkcl@lkcl.net * * (C) Copyright 2007-2011 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> * Tom Cubie tangliang@allwinnertech.com * * Some board init for the Allwinner A10-evb board. * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <mmc.h> #include <axp_pmic.h> #include <asm/arch/clock.h> #include <asm/arch/cpu.h> #include <asm/arch/display.h> #include <asm/arch/dram.h> #include <asm/arch/gpio.h> #include <asm/arch/mmc.h> #include <asm/arch/spl.h> #include <asm/arch/usb_phy.h> #ifndef CONFIG_ARM64 #include <asm/armv7.h> #endif #include <asm/gpio.h> #include <asm/io.h> #include <crc.h> +#include <dm/root.h> #include <environment.h> #include <libfdt.h> #include <fdtdec.h> #include <led.h> #include <nand.h> #include <net.h> #include <sy8106a.h> #include <command.h>
@@ -109,76 +110,87 @@ static int setup_led(void) int board_init(void) { __maybe_unused int id_pfr1, ret; + int __maybe_unused offset;
gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
+#if defined(CONFIG_CLK) + /* Sunxi device trees have their clock definitions in a tree + * below /clocks, which is a node without a compatible-string. + * We need to manually locate it and scan its subnodes. + */ + offset = fdt_path_offset(gd->fdt_blob, "/clocks"); + if (offset > 0) + dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, offset, false); +#endif + #ifndef CONFIG_ARM64 asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1)); debug("id_pfr1: 0x%08x\n", id_pfr1); /* Generic Timer Extension available? */ if ((id_pfr1 >> CPUID_ARM_GENTIMER_SHIFT) & 0xf) { uint32_t freq;
debug("Setting CNTFRQ\n");
/* * CNTFRQ is a secure register, so we will crash if we try to * write this from the non-secure world (read is OK, though). * In case some bootcode has already set the correct value, * we avoid the risk of writing to it. */ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r"(freq)); if (freq != CONFIG_TIMER_CLK_FREQ) { debug("arch timer frequency is %d Hz, should be %d, fixing ...\n", freq, CONFIG_TIMER_CLK_FREQ); #ifdef CONFIG_NON_SECURE printf("arch timer frequency is wrong, but cannot adjust it\n"); #else asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r"(CONFIG_TIMER_CLK_FREQ)); #endif } } #endif /* !CONFIG_ARM64 */
sunxi_gpio_set_cfgpin(SUNXI_GPG(10), SUN6I_GPG_USB3); sunxi_gpio_set_cfgpin(SUNXI_GPG(11), SUN6I_GPG_USB3);
gpio_request(SUNXI_GPC(3), "STM32 Boot0"); sunxi_gpio_set_cfgpin(SUNXI_GPC(3), SUNXI_GPIO_OUTPUT); gpio_request(SUNXI_GPC(26), "STM32 Reset"); sunxi_gpio_set_cfgpin(SUNXI_GPC(26), SUNXI_GPIO_OUTPUT); #if !defined(CONFIG_DM_GPIO) gpio_request(SUNXI_GPA(7), "PHY Reset"); sunxi_gpio_set_cfgpin(SUNXI_GPA(7), SUNXI_GPIO_OUTPUT); gpio_direction_output(SUNXI_GPA(7), 0); #endif
gpio_direction_output(SUNXI_GPC(3), 0); gpio_direction_output(SUNXI_GPC(26), 0); mdelay(10); gpio_direction_output(SUNXI_GPC(26), 1); #if !defined(CONFIG_DM_GPIO) gpio_direction_output(SUNXI_GPA(7), 1); #endif
setup_led();
ret = axp_gpio_init(); if (ret) return ret;
#ifdef CONFIG_SATAPWR gpio_request(CONFIG_SATAPWR, "satapwr"); gpio_direction_output(CONFIG_SATAPWR, 1); #endif #ifdef CONFIG_MACPWR gpio_request(CONFIG_MACPWR, "macpwr"); gpio_direction_output(CONFIG_MACPWR, 1); #endif
/* Uses dm gpio code so do this here and not in i2c_init_board() */ return soft_i2c_board_init();
}
@@ -1018,24 +1030,23 @@ U_BOOT_CMD( int board_fit_config_name_match(const char *name) { #ifdef CONFIG_SPL_LOAD_FIT const char *cmp_str;
#ifdef CONFIG_DEFAULT_DEVICE_TREE cmp_str = CONFIG_DEFAULT_DEVICE_TREE; #else return 0; #endif
/* Differentiate the two Pine64 board DTs by their DRAM size. */ if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) { if ((gd->ram_size > 512 * 1024 * 1024)) return !strstr(name, "plus"); else return !!strstr(name, "plus"); } else { return strcmp(name, cmp_str); } #endif }
-

parse_phy_pins() is parsing the pinctrl-entry of the emac-node, which is in conflict with the new DM pinctrl driver for sun50i. So when building for sun50i and if the pinctrl driver is active, let the parse_phy_pins()-function do nothing.
Use the DM reset and DM clk frameworks for getting the emac module out of reset and enabling the clock gates.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/net/sun8i_emac.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 664d585..9d783e1 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -1,101 +1,107 @@ /* * (C) Copyright 2016 * Author: Amit Singh Tomar, amittomer25@gmail.com * * SPDX-License-Identifier: GPL-2.0+ * * Ethernet driver for H3/A64/A83T based SoC's * * It is derived from the work done by * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS! * */
#include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/gpio.h> +#if defined(CONFIG_DM_GPIO) +#include <asm-generic/gpio.h> +#endif +#if defined(CONFIG_CLK) +#include <clk.h> +#endif #include <common.h> #include <dm.h> #include <fdt_support.h> #include <linux/err.h> #include <malloc.h> #include <miiphy.h> #include <net.h> -#ifdef CONFIG_DM_GPIO -#include <asm-generic/gpio.h> +#if defined(CONFIG_DM_RESET) +#include <reset.h> #endif
#define MDIO_CMD_MII_BUSY BIT(0) #define MDIO_CMD_MII_WRITE BIT(1)
#define MDIO_CMD_MII_PHY_REG_ADDR_MASK 0x000001f0 #define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT 4 #define MDIO_CMD_MII_PHY_ADDR_MASK 0x0001f000 #define MDIO_CMD_MII_PHY_ADDR_SHIFT 12
#define MDIO_CMD_MDC_DIV_RATIO_M_SHIFT 20 #define MDIO_CMD_MDC_DIV_16 (0 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT) #define MDIO_CMD_MDC_DIV_32 (1 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT) #define MDIO_CMD_MDC_DIV_64 (2 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT) #define MDIO_CMD_MDC_DIV_128 (3 << MDIO_CMD_MDC_DIV_RATIO_M_SHIFT)
#define CONFIG_TX_DESCR_NUM 32 #define CONFIG_RX_DESCR_NUM 32 #define CONFIG_ETH_BUFSIZE 2048 /* Note must be dma aligned */
/* * The datasheet says that each descriptor can transfers up to 4096 bytes * But later, the register documentation reduces that value to 2048, * using 2048 cause strange behaviours and even BSP driver use 2047 */ #define CONFIG_ETH_RXSIZE 2044 /* Note must fit in ETH_BUFSIZE */
#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM) #define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
#define H3_EPHY_DEFAULT_VALUE 0x58000 #define H3_EPHY_DEFAULT_MASK GENMASK(31, 15) #define H3_EPHY_ADDR_SHIFT 20 #define REG_PHY_ADDR_MASK GENMASK(4, 0) #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
#define SC_RMII_EN BIT(13) #define SC_EPIT BIT(2) /* 1: RGMII, 0: MII */ #define SC_ETCS_MASK GENMASK(1, 0) #define SC_ETCS_EXT_GMII 0x1 #define SC_ETCS_INT_GMII 0x2
#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
#define AHB_GATE_OFFSET_EPHY 0
#if defined(CONFIG_MACH_SUN8I_H3) #define SUN8I_GPD8_GMAC 2 #else #define SUN8I_GPD8_GMAC 4 #endif
/* H3/A64 EMAC Register's offset */ #define EMAC_CTL0 0x00 #define EMAC_CTL1 0x04 #define EMAC_INT_STA 0x08 #define EMAC_INT_EN 0x0c #define EMAC_TX_CTL0 0x10 #define EMAC_TX_CTL1 0x14 #define EMAC_TX_FLOW_CTL 0x1c #define EMAC_TX_DMA_DESC 0x20 #define EMAC_RX_CTL0 0x24 #define EMAC_RX_CTL1 0x28 #define EMAC_RX_DMA_DESC 0x34 #define EMAC_MII_CMD 0x48 #define EMAC_MII_DATA 0x4c #define EMAC_ADDR0_HIGH 0x50 #define EMAC_ADDR0_LOW 0x54 #define EMAC_TX_DMA_STA 0xb0 #define EMAC_TX_CUR_DESC 0xb4 #define EMAC_TX_CUR_BUF 0xb8 #define EMAC_RX_DMA_STA 0xc0 #define EMAC_RX_CUR_DESC 0xc4
@@ -117,29 +123,35 @@ struct emac_dma_desc { struct emac_eth_dev { struct emac_dma_desc rx_chain[CONFIG_TX_DESCR_NUM]; struct emac_dma_desc tx_chain[CONFIG_RX_DESCR_NUM]; char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN); char txbuffer[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
u32 interface; u32 phyaddr; u32 link; u32 speed; u32 duplex; u32 phy_configured; u32 tx_currdescnum; u32 rx_currdescnum; u32 addr; u32 tx_slot; bool use_internal_phy;
enum emac_variant variant; void *mac_reg; phys_addr_t sysctl_reg; struct phy_device *phydev; struct mii_dev *bus; #ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio; #endif +#ifdef CONFIG_DM_RESET + struct reset_ctl reset; +#endif +#ifdef CONFIG_CLK + struct clk ahb_clk_gate; +#endif };
@@ -459,45 +471,47 @@ static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr)
static int parse_phy_pins(struct udevice *dev) { +#if !(defined(CONFIG_MACH_SUN50I) && defined(CONFIG_SUNXI_PINCTRL)) 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; } +#endif
return 0; }
@@ -609,20 +623,28 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev) static void sun8i_emac_board_setup(struct emac_eth_dev *priv) { struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
if (priv->use_internal_phy) { /* Set clock gating for ephy */ setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY));
/* Deassert EPHY */ setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY)); }
/* Set clock gating for emac */ +#if defined(CONFIG_CLK) + clk_enable(&priv->ahb_clk_gate); +#else setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC)); +#endif
/* De-assert EMAC */ +#if defined(CONFIG_DM_RESET) + reset_deassert(&priv->reset); +#else setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC)); +#endif }
#if defined(CONFIG_DM_GPIO) @@ -772,75 +794,90 @@ static const struct eth_ops sun8i_emac_eth_ops = { static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) { struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev); struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; struct emac_eth_dev *priv = dev_get_priv(dev); const char *phy_mode; int node = dev_of_offset(dev); int offset = 0; #ifdef CONFIG_DM_GPIO int reset_flags = GPIOD_IS_OUT; int ret = 0; #endif
pdata->iobase = dev_get_addr_name(dev, "emac"); priv->sysctl_reg = dev_get_addr_name(dev, "syscon");
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);
phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
if (phy_mode) pdata->phy_interface = phy_get_interface_by_name(phy_mode); printf("phy interface%d\n", pdata->phy_interface);
if (pdata->phy_interface == -1) { debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); return -EINVAL; }
priv->variant = dev_get_driver_data(dev);
if (!priv->variant) { printf("%s: Missing variant '%s'\n", __func__, (char *)priv->variant); return -EINVAL; }
if (priv->variant == H3_EMAC) { if (fdt_getprop(gd->fdt_blob, node, "allwinner,use-internal-phy", NULL)) priv->use_internal_phy = true; }
priv->interface = pdata->phy_interface;
if (!priv->use_internal_phy) parse_phy_pins(dev);
-#ifdef CONFIG_DM_GPIO +#if defined(CONFIG_DM_GPIO) if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "allwinner,reset-active-low")) reset_flags |= GPIOD_ACTIVE_LOW;
ret = gpio_request_by_name(dev, "allwinner,reset-gpio", 0, &priv->reset_gpio, reset_flags);
if (ret == 0) { ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, - "allwinner,reset-delays-us", sun8i_pdata->reset_delays, 3); + "allwinner,reset-delays-us", + sun8i_pdata->reset_delays, 3); } else if (ret == -ENOENT) { ret = 0; } #endif
+#if defined(CONFIG_DM_RESET) + if (reset_get_by_name(dev, "ahb", &priv->reset)) { + error("%s: failed to get 'ahb' reset\n", dev->name); + return -EINVAL; + } +#endif + +#if defined(CONFIG_CLK) + if (clk_get_by_name(dev, "ahb", &priv->ahb_clk_gate)) { + error("%s: failed to get 'ahb' clock\n", dev->name); + return -EINVAL; + } +#endif + return 0; }

We now support the device-model for configuration of the driver including the interface to the pinctrl, reset and clock frameworks.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- board/sunxi/board.c | 7 +- drivers/mmc/sunxi_mmc.c | 350 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 331 insertions(+), 26 deletions(-)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 838e89f..810fbd4 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -237,14 +237,14 @@ static void nand_clock_setup(void) void board_nand_init(void) { nand_pinmux_setup(); nand_clock_setup(); #ifndef CONFIG_SPL_BUILD sunxi_nand_init(); #endif } #endif
-#ifdef CONFIG_GENERIC_MMC +#if defined(CONFIG_GENERIC_MMC) && !(defined(CONFIG_DM_MMC) && defined(CONFIG_PINCTRL)) static void mmc_pinmux_setup(int sdc) { unsigned int pin; @@ -422,75 +422,76 @@ static void mmc_pinmux_setup(int sdc)
int board_mmc_init(bd_t *bis) { +#if !(defined(CONFIG_DM_MMC) && defined(CONFIG_PINCTRL)) __maybe_unused struct mmc *mmc0, *mmc1; __maybe_unused char buf[512]; __maybe_unused u32 val;
mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT); mmc0 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT); if (!mmc0) return -1;
#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1 mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA); mmc1 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT_EXTRA); if (!mmc1) return -1; #endif
#if !defined(CONFIG_SPL_BUILD) && CONFIG_MMC_SUNXI_SLOT_EXTRA == 2 #if CONFIG_MACH_SUN6I /* * the bootdevice is shown in VER_REG in the system controller * if U_boot is set then the ROM trys to boot from mmc0 regardless * of the BOOT_SEL pins. */
#if 0 val = readl(0x1c00024); if ((val & (1<<10))) /* check UBOOT_SEL */ { switch((val & (3<<8))>>8) /* check BOOT_SEL pins */ { case 0x0: /* SPI0 boot */ break; case 0x1: /* eMMC2 boot */ /* Check if there is a boot loader on eMMC2 * If not we want to fall back to SD card */ if (mmc_init(mmc1) == 0 && mmc1->block_dev.block_read(&mmc1->block_dev, 16, 1, buf) == 1) { buf[12] = 0; if (strcmp(&buf[4], "eGON.BT0") == 0) { /* Boot loader found, swap to make eMMC the first device */ mmc0->block_dev.devnum = 1; mmc1->block_dev.devnum = 0; } } break; case 0x2: /* SDC2 boot */ break; case 0x3: /* NAND Flash boot */ break; } } #endif
#else /* * On systems with an emmc (mmc2), figure out if we are booting from * the emmc and if we are make it "mmc dev 0" so that boot.scr, etc. * are searched there first. Note we only do this for u-boot proper, * not for the SPL, see spl_boot_device(). */ if (readb(SPL_ADDR + 0x28) == SUNXI_BOOTED_FROM_MMC2) { /* Booting from emmc / mmc2, swap */ mmc0->block_dev.devnum = 1; mmc1->block_dev.devnum = 0; } #endif #endif - +#endif return 0; } #endif
@@ -854,43 +855,45 @@ static void setup_environment(const void *fdt) */ static void setup_environment(const void *fdt) { +#if !defined(CONFIG_DM_MMC) uint8_t mac_addr[6]; char serial_string[17] = { 0 }; struct mmc *mmc0; struct sunxi_mmc_host { unsigned mmc_no; uint32_t *mclkreg; unsigned fatal_err; struct sunxi_mmc *reg; struct mmc_config cfg; };
mmc0 = find_mmc_device(1);
/* lookup the real device number to get the eMMC */ if(((struct sunxi_mmc_host*)mmc0->priv)->mmc_no != 2) mmc0 = find_mmc_device(0);
if(mmc0->has_init == 0) mmc_init(mmc0);
if (!getenv("ethaddr")) { /* Non OUI / registered MAC address */ mac_addr[0] = 0x02; mac_addr[1] = (mmc0->cid[0] >> 24) & 0xff; mac_addr[2] = (mmc0->cid[2] >> 0) & 0xff; mac_addr[3] = (mmc0->cid[3] >> 24) & 0xff; mac_addr[4] = (mmc0->cid[3] >> 16) & 0xff; mac_addr[5] = (mmc0->cid[3] >> 8) & 0xff;
eth_setenv_enetaddr("ethaddr", mac_addr); }
if (!getenv("serial#")) { snprintf(serial_string, sizeof(serial_string), "%08x%02x%06x", mmc0->cid[0]>>24,mmc0->cid[2]&0xff,mmc0->cid[3]>>8); setenv("serial#", serial_string); } +#endif } #endif
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 46abe4a..8075b9c 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -1,89 +1,165 @@ /* * (C) Copyright 2007-2011 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> * Aaron leafy.myeh@allwinnertech.com * + * (C) 2017 Theobroma Systems Design und Consulting GmbH + * * MMC driver for allwinner sunxi platform. * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> -#include <errno.h> -#include <malloc.h> -#include <mmc.h> -#include <asm/io.h> +#include <asm-generic/gpio.h> #include <asm/arch/clock.h> #include <asm/arch/cpu.h> #include <asm/arch/gpio.h> #include <asm/arch/mmc.h> -#include <asm-generic/gpio.h> +#include <asm/io.h> +#include <clk.h> +#include <dm/device.h> +#include <dt-structs.h> +#include <errno.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <mmc.h> +#include <reset.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_mmc_plat { + struct mmc mmc; +};
struct sunxi_mmc_host { unsigned mmc_no; +#if !defined(CONFIG_DM_MMC) uint32_t *mclkreg; +#endif unsigned fatal_err; struct sunxi_mmc *reg; struct mmc_config cfg; + bool cd_inverted; +#if defined(CONFIG_DM_MMC) + struct mmc *mmc; + struct gpio_desc cd_gpio; /* card-detect (optional) */ + struct gpio_desc pwr_gpio; /* power-enabled (optional) */ + struct gpio_desc wp_gpio; /* write-protect (optional) */ + bool wp_inverted; + struct reset_ctl reset; + struct clk ahb_clk_gate; + struct clk mmc_clk; +#else + int cd_pin; +#endif };
+#if defined(CONFIG_DM_MMC) && defined(CONFIG_DM_MMC_OPS) +static const struct dm_mmc_ops sunxi_mmc_ops; +#else +static const struct mmc_ops sunxi_mmc_ops; +#endif + +#if !defined(CONFIG_DM_MMC) /* support 4 mmc hosts */ struct sunxi_mmc_host mmc_host[4];
static int sunxi_mmc_getcd_gpio(int sdc_no) { switch (sdc_no) { case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); +#if !defined(CONFIG_ARCH_SUN50I) /* only 3 MMC controllers on the A64 */ case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); +#endif } return -EINVAL; }
static int mmc_resource_init(int sdc_no) { struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; int cd_pin, ret = 0;
debug("init mmc %d resource\n", sdc_no);
switch (sdc_no) { case 0: mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; mmchost->mclkreg = &ccm->sd0_clk_cfg; break; case 1: mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; mmchost->mclkreg = &ccm->sd1_clk_cfg; break; case 2: mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; mmchost->mclkreg = &ccm->sd2_clk_cfg; break; +#if !defined(CONFIG_ARCH_SUN50I) /* only 3 MMC controllers on the A64 */ case 3: mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; mmchost->mclkreg = &ccm->sd3_clk_cfg; break; +#endif default: printf("Wrong mmc number %d\n", sdc_no); return -1; } mmchost->mmc_no = sdc_no;
cd_pin = sunxi_mmc_getcd_gpio(sdc_no); if (cd_pin >= 0) { ret = gpio_request(cd_pin, "mmc_cd"); if (!ret) { sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP); ret = gpio_direction_input(cd_pin); } } + mmchost->cd_pin = cd_pin; + + return ret; +} +#endif + +#if defined(CONFIG_DM_MMC) +static int mmc_resource_init_from_udev(struct udevice *dev) +{ + struct sunxi_mmc_host *mmchost = dev_get_priv(dev); + int ret = 0; + + debug("%s: %s\n", dev->name, __func__); + + switch ((uintptr_t)mmchost->reg) { + case SUNXI_MMC0_BASE: + mmchost->mmc_no = 0; + break; + case SUNXI_MMC1_BASE: + mmchost->mmc_no = 1; + break; + case SUNXI_MMC2_BASE: + mmchost->mmc_no = 2; + break; +#if !defined(CONFIG_ARCH_SUN50I) /* only 3 MMC controllers on the A64 */ + case SUNXI_MMC3_BASE: + mmchost->mmc_no = 3; + break; +#endif + default: + debug("%s: unknown base address %p\n", __func__, mmchost->reg); + return -1; + } + + debug("%s: mmc_no %d\n", dev->name, mmchost->mmc_no);
return ret; } +#endif
+#if !defined(CONFIG_DM_MMC) static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz) { unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; @@ -154,112 +230,156 @@ static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz) return 0; }
-static int mmc_clk_io_on(int sdc_no) +static int mmc_clk_io_on(struct sunxi_mmc_host *mmchost) { - struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int sdc_no = mmchost->mmc_no;
debug("init mmc %d clock and io\n", sdc_no);
/* config ahb clock */ setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
#ifdef CONFIG_SUNXI_GEN_SUN6I /* unassert reset */ setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); #endif #if defined(CONFIG_MACH_SUN9I) /* sun9i has a mmc-common module, also set the gate and reset there */ writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, SUNXI_MMC_COMMON_BASE + 4 * sdc_no); #endif
return mmc_set_mod_clk(mmchost, 24000000); } +#endif + +#if defined(CONFIG_DM_MMC) +static int mmc_clk_io_on(struct sunxi_mmc_host *mmchost) +{ + /* Enable the AHB clock gate */ + clk_enable(&mmchost->ahb_clk_gate); + + /* Deassert the AHB module reset */ + reset_deassert(&mmchost->reset); + +#if defined(CONFIG_MACH_SUN9I) + /* TODO --- covert this to DM */ + /* sun9i has a mmc-common module, also set the gate and reset there */ + writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, + SUNXI_MMC_COMMON_BASE + 4 * sdc_no); +#endif + + clk_set_rate(&mmchost->mmc_clk, 24000000); + clk_enable(&mmchost->mmc_clk); + + return 0; +} +#endif
static int mmc_update_clk(struct mmc *mmc) { struct sunxi_mmc_host *mmchost = mmc->priv; unsigned int cmd; unsigned timeout_msecs = 2000; unsigned long start = get_timer(0);
+ debug("%s: base %p\n", __func__, mmchost->reg); + cmd = SUNXI_MMC_CMD_START | SUNXI_MMC_CMD_UPCLK_ONLY | SUNXI_MMC_CMD_WAIT_PRE_OVER; writel(cmd, &mmchost->reg->cmd); while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) { if (get_timer(start) > timeout_msecs) return -1; }
/* clock update sets various irq status bits, clear these */ writel(readl(&mmchost->reg->rint), &mmchost->reg->rint);
return 0; }
static int mmc_config_clock(struct mmc *mmc) { struct sunxi_mmc_host *mmchost = mmc->priv; unsigned rval = readl(&mmchost->reg->clkcr);
/* Disable Clock */ rval &= ~SUNXI_MMC_CLK_ENABLE; writel(rval, &mmchost->reg->clkcr); if (mmc_update_clk(mmc)) return -1;
+#if !defined(CONFIG_DM_MMC) /* Set mod_clk to new rate */ if (mmc_set_mod_clk(mmchost, mmc->clock)) return -1; +#else + if (clk_set_rate(&mmchost->mmc_clk, mmc->clock) == 0) + return -1; +#endif
/* Clear internal divider */ rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; writel(rval, &mmchost->reg->clkcr);
/* Re-enable Clock */ rval |= SUNXI_MMC_CLK_ENABLE; writel(rval, &mmchost->reg->clkcr); if (mmc_update_clk(mmc)) return -1;
return 0; }
+#if defined(CONFIG_DM_MMC_OPS) +static int sunxi_mmc_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int sunxi_mmc_set_ios(struct mmc *mmc) { +#endif struct sunxi_mmc_host *mmchost = mmc->priv;
debug("set ios: bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
/* Change clock first */ if (mmc->clock && mmc_config_clock(mmc) != 0) { mmchost->fatal_err = 1; return -EINVAL; }
/* Change bus width */ if (mmc->bus_width == 8) writel(0x2, &mmchost->reg->width); else if (mmc->bus_width == 4) writel(0x1, &mmchost->reg->width); else writel(0x0, &mmchost->reg->width);
return 0; }
static int sunxi_mmc_core_init(struct mmc *mmc) { struct sunxi_mmc_host *mmchost = mmc->priv; + uint32_t regval; + int ret = 0; + + debug("%s: base %p", __func__, mmchost->reg);
/* Reset controller */ writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); - udelay(1000);
- return 0; + /* Wait for the reset bit (auto-clearing) to deassert */ + ret = readl_poll_timeout(&mmchost->reg->gctrl, regval, + !(regval & SUNXI_MMC_GCTRL_RESET), 1000000); + + return ret; }
static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) @@ -317,113 +437,120 @@ static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs, return 0; }
+#if defined(CONFIG_DM_MMC_OPS) +static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int sunxi_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { +#endif struct sunxi_mmc_host *mmchost = mmc->priv; unsigned int cmdval = SUNXI_MMC_CMD_START; unsigned int timeout_msecs; int error = 0; unsigned int status = 0; unsigned int bytecnt = 0;
if (mmchost->fatal_err) return -1; if (cmd->resp_type & MMC_RSP_BUSY) debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); if (cmd->cmdidx == 12) return 0;
if (!cmd->cmdidx) cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; if (cmd->resp_type & MMC_RSP_PRESENT) cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; if (cmd->resp_type & MMC_RSP_136) cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; if (cmd->resp_type & MMC_RSP_CRC) cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
if (data) { if ((u32)(long)data->dest & 0x3) { error = -1; goto out; }
cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; if (data->flags & MMC_DATA_WRITE) cmdval |= SUNXI_MMC_CMD_WRITE; if (data->blocks > 1) cmdval |= SUNXI_MMC_CMD_AUTO_STOP; writel(data->blocksize, &mmchost->reg->blksz); writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt); }
- debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no, + debug("mmc %p, cmd %d(0x%08x), arg 0x%08x\n", mmchost, cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); writel(cmd->cmdarg, &mmchost->reg->arg);
if (!data) writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
/* * transfer data and check status * STATREG[2] : FIFO empty * STATREG[3] : FIFO full */ if (data) { int ret = 0;
bytecnt = data->blocksize * data->blocks; debug("trans data %d bytes\n", bytecnt); writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); ret = mmc_trans_data_by_cpu(mmc, data); if (ret) { error = readl(&mmchost->reg->rint) & \ SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; error = -ETIMEDOUT; goto out; } }
error = mmc_rint_wait(mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, "cmd"); if (error) goto out;
if (data) { timeout_msecs = 120; debug("cacl timeout %x msec\n", timeout_msecs); error = mmc_rint_wait(mmc, timeout_msecs, data->blocks > 1 ? SUNXI_MMC_RINT_AUTO_COMMAND_DONE : SUNXI_MMC_RINT_DATA_OVER, "data"); if (error) goto out; }
if (cmd->resp_type & MMC_RSP_BUSY) { unsigned long start = get_timer(0); timeout_msecs = 2000;
do { status = readl(&mmchost->reg->status); if (get_timer(start) > timeout_msecs) { debug("busy timeout\n"); error = -ETIMEDOUT; goto out; } } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); }
if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = readl(&mmchost->reg->resp3); cmd->response[1] = readl(&mmchost->reg->resp2); cmd->response[2] = readl(&mmchost->reg->resp1); cmd->response[3] = readl(&mmchost->reg->resp0); debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", cmd->response[3], cmd->response[2], cmd->response[1], cmd->response[0]); } else { cmd->response[0] = readl(&mmchost->reg->resp0); debug("mmc resp 0x%08x\n", cmd->response[0]); } @@ -439,50 +566,225 @@ out: return error; }
+static inline int cdpin_is_valid(struct sunxi_mmc_host *priv) +{ +#if !defined(CONFIG_DM_MMC) + return priv->cd_pin >= 0; +#else + return dm_gpio_is_valid(&priv->cd_gpio); +#endif +} + +static inline int cdpin_get_value(struct sunxi_mmc_host *priv) +{ +#if !defined(CONFIG_DM_MMC) + return gpio_get_value(priv->cd_pin); +#else + return dm_gpio_get_value(&priv->cd_gpio); +#endif +} + +#if defined(CONFIG_DM_MMC_OPS) +static int sunxi_mmc_getcd(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int sunxi_mmc_getcd(struct mmc *mmc) { - struct sunxi_mmc_host *mmchost = mmc->priv; - int cd_pin; +#endif + struct sunxi_mmc_host *priv = mmc->priv; + int value = 1;
- cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no); - if (cd_pin < 0) - return 1; + if (cdpin_is_valid(priv)) { + value = cdpin_get_value(priv);
- return !gpio_get_value(cd_pin); -} + if (priv->cd_inverted) + return !value; + }
-static const struct mmc_ops sunxi_mmc_ops = { - .send_cmd = sunxi_mmc_send_cmd, - .set_ios = sunxi_mmc_set_ios, - .init = sunxi_mmc_core_init, - .getcd = sunxi_mmc_getcd, -}; + return value; +}
+#if !defined(CONFIG_DM_MMC) struct mmc *sunxi_mmc_init(int sdc_no) { struct mmc_config *cfg = &mmc_host[sdc_no].cfg;
memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); + mmc_host[sdc_no].cd_inverted = true;
cfg->name = "SUNXI SD/MMC"; cfg->ops = &sunxi_mmc_ops;
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; cfg->host_caps = MMC_MODE_4BIT; #if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) if (sdc_no == 2) cfg->host_caps = MMC_MODE_8BIT; #endif cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
cfg->f_min = 400000; cfg->f_max = 52000000;
if (mmc_resource_init(sdc_no) != 0) return NULL;
- mmc_clk_io_on(sdc_no); + mmc_clk_io_on(&mmc_host[sdc_no]);
return mmc_create(cfg, &mmc_host[sdc_no]); } +#endif + +#if defined(CONFIG_DM_MMC) && defined(CONFIG_DM_MMC_OPS) +static const struct dm_mmc_ops sunxi_mmc_ops = { + .send_cmd = sunxi_mmc_send_cmd, + .set_ios = sunxi_mmc_set_ios, + .get_cd = sunxi_mmc_getcd, +}; +#else +static const struct mmc_ops sunxi_mmc_ops = { + .send_cmd = sunxi_mmc_send_cmd, + .set_ios = sunxi_mmc_set_ios, + .init = sunxi_mmc_core_init, + .getcd = sunxi_mmc_getcd, +}; +#endif + +#if defined(CONFIG_DM_MMC) +static int sunxi_mmc_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + +static int sunxi_mmc_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); +#if defined(CONFIG_BLK) + struct sunxi_mmc_plat *plat = dev_get_platdata(dev); +#endif + struct sunxi_mmc_host *priv = dev_get_priv(dev); + struct mmc_config *cfg = &priv->cfg; + int bus_width; + u32 f_minmax[2]; + + priv->reg = (void *)dev_get_addr(dev); + cfg->name = "SUNXI SD/MMC"; +#if !(defined(CONFIG_DM_MMC) && defined(CONFIG_DM_MMC_OPS)) + cfg->ops = &sunxi_mmc_ops; +#endif + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; + + bus_width = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "bus-width", 4); + if (bus_width == 8) + cfg->host_caps |= MMC_MODE_8BIT; + else if (bus_width == 4) + cfg->host_caps |= MMC_MODE_4BIT; + + debug("%s: reg %p bus_width %d\n", dev->name, priv->reg, bus_width); + + if (!fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "clock-freq-min-max", f_minmax, 2)) { + cfg->f_min = f_minmax[0]; + cfg->f_max = f_minmax[1]; + } else { + /* use the defaults */ + cfg->f_min = 400000; + cfg->f_max = 52000000; + } + + /* Some legacy functionality in our tree still depends on the + * mmchost->mmc_no... until we can get rid of this, initialise + * it based on the base address of the device. + */ + if (mmc_resource_init_from_udev(dev) != 0) + return -EINVAL; + + /* All GPIOs are optional */ + gpio_request_by_name(dev, "cd-gpios", 0, + &priv->cd_gpio, GPIOD_IS_IN); + priv->cd_inverted = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "cd-inverted"); + gpio_request_by_name(dev, "wp-gpios", 0, + &priv->wp_gpio, GPIOD_IS_IN); + priv->wp_inverted = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "wp-inverted"); + gpio_request_by_name(dev, "power-gpios", 0, + &priv->pwr_gpio, GPIOD_IS_OUT); + if (dm_gpio_is_valid(&priv->pwr_gpio)) + dm_gpio_set_value(&priv->pwr_gpio, 1); + + if (reset_get_by_name(dev, "ahb", &priv->reset)) { + error("%s: failed to get 'ahb' reset\n", dev->name); + return -EINVAL; + } + + if (clk_get_by_name(dev, "ahb", &priv->ahb_clk_gate) || + clk_get_by_name(dev, "mmc", &priv->mmc_clk)) { + error("%s: failed to get all required clocks ('ahb', 'mmc')\n", + dev->name); + return -EINVAL; + } + + mmc_clk_io_on(priv); + +#if defined(CONFIG_BLK) + priv->mmc = &plat->mmc; +#else + priv->mmc = mmc_create(cfg, priv); + if (priv->mmc == NULL) + return -1; +#endif + priv->mmc->priv = priv; + priv->mmc->dev = dev; + priv->mmc->cfg = cfg; + priv->mmc->has_init = 0; + upriv->mmc = priv->mmc; + +#if defined(CONFIG_DM_MMC) && defined(CONFIG_DM_MMC_OPS) + sunxi_mmc_core_init(priv->mmc); +#endif + return 0; +} + +#if defined(CONFIG_BLK) +static int sunxi_mmc_bind(struct udevice *dev) +{ + struct sunxi_mmc_plat *plat = dev_get_platdata(dev); + struct sunxi_mmc_host *priv = dev_get_priv(dev); + + debug("%s: %s\n", dev->name, __func__); + + /* TODO: To move cfg into plat, we need to change the legacy + code, which references through the arrays... */ + + return mmc_bind(dev, &plat->mmc, &priv->cfg); +} +#endif + +static const struct udevice_id sunxi_mmc_ids[] = { + { .compatible = "allwinner,sun50i-a64-mmc" }, + { } +}; + +U_BOOT_DRIVER(sunxi_mmc_drv) = { + .name = "sunxi_mmc", + .id = UCLASS_MMC, + .of_match = sunxi_mmc_ids, + .ofdata_to_platdata = sunxi_mmc_ofdata_to_platdata, + .probe = sunxi_mmc_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_mmc_host), + .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat), +#if defined(CONFIG_DM_MMC_OPS) + .ops = &sunxi_mmc_ops, +#endif +#if defined(CONFIG_BLK) + .bind = sunxi_mmc_bind, +#endif +}; + +#endif

--- arch/arm/dts/sun50i-a64.dtsi | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index d592bf2..b65d033 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -1,762 +1,772 @@ /* * Copyright (C) 2016 ARM Ltd. * based on the Allwinner H3 dtsi: * Copyright (C) 2015 Jens Kuske jenskuske@gmail.com * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual * licensing only applies to this file, and not this project as a * whole. * * a) This file 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 file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Or, alternatively, * * b) Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h>
/ { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>;
cpus { #address-cells = <1>; #size-cells = <0>;
cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0>; enable-method = "psci"; };
cpu@1 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <1>; enable-method = "psci"; };
cpu@2 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <2>; enable-method = "psci"; };
cpu@3 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <3>; enable-method = "psci"; }; };
psci { compatible = "arm,psci-0.2"; method = "smc"; };
memory: memory@40000000 { device_type = "memory"; reg = <0x40000000 0>; };
gic: interrupt-controller@1c81000 { compatible = "arm,gic-400"; interrupt-controller; #interrupt-cells = <3>; #address-cells = <0>;
reg = <0x01c81000 0x1000>, <0x01c82000 0x2000>, <0x01c84000 0x2000>, <0x01c86000 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
clocks { #address-cells = <1>; #size-cells = <1>; ranges;
osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "osc24M"; };
osc32k: osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; clock-output-names = "osc32k"; };
pll1: pll1_clk@1c20000 { #clock-cells = <0>; compatible = "allwinner,sun8i-a23-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; clock-output-names = "pll1"; };
pll6: pll6_clk@1c20028 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c20028 0x4>; clocks = <&osc24M>; clock-output-names = "pll6", "pll6x2"; };
pll6d2: pll6d2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; clock-div = <2>; clock-mult = <1>; clocks = <&pll6 0>; clock-output-names = "pll6d2"; };
pll7: pll7_clk@1c2002c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c2002c 0x4>; clocks = <&osc24M>; clock-output-names = "pll7", "pll7x2"; };
cpu: cpu_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; reg = <0x01c20050 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; clock-output-names = "cpu"; critical-clocks = <0>; };
axi: axi_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; clock-output-names = "axi"; };
ahb1: ahb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-ahb1-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; clock-output-names = "ahb1"; };
ahb2: ahb2_clk@1c2005c { #clock-cells = <0>; compatible = "allwinner,sun8i-h3-ahb2-clk"; reg = <0x01c2005c 0x4>; clocks = <&ahb1>, <&pll6d2>; clock-output-names = "ahb2"; };
apb1: apb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; clock-output-names = "apb1"; };
apb2: apb2_clk@1c20058 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6 1>, <&pll6 1>; clock-output-names = "apb2"; };
bus_gates: bus_gates_clk@1c20060 { #clock-cells = <1>; compatible = "allwinner,sun50i-a64-bus-gates-clk", "allwinner,sunxi-multi-bus-gates-clk"; reg = <0x01c20060 0x14>; ahb1_parent { clocks = <&ahb1>; clock-indices = <1>, <5>, <6>, <8>, <9>, <10>, <13>, <14>, <18>, <19>, <20>, <21>, <23>, <24>, <25>, <28>, <32>, <35>, <36>, <37>, <40>, <43>, <44>, <52>, <53>, <54>, <135>; clock-output-names = "bus_mipidsi", "bus_ce", "bus_dma", "bus_mmc0", "bus_mmc1", "bus_mmc2", "bus_nand", "bus_sdram", "bus_ts", "bus_hstimer", "bus_spi0", "bus_spi1", "bus_otg", "bus_otg_ehci0", "bus_ehci0", "bus_otg_ohci0", "bus_ve", "bus_lcd0", "bus_lcd1", "bus_deint", "bus_csi", "bus_hdmi", "bus_de", "bus_gpu", "bus_msgbox", "bus_spinlock", "bus_dbg"; }; ahb2_parent { clocks = <&ahb2>; clock-indices = <17>, <29>; clock-output-names = "bus_gmac", "bus_ohci0"; }; apb1_parent { clocks = <&apb1>; clock-indices = <64>, <65>, <69>, <72>, <76>, <77>, <78>; clock-output-names = "bus_codec", "bus_spdif", "bus_pio", "bus_ths", "bus_i2s0", "bus_i2s1", "bus_i2s2"; }; abp2_parent { clocks = <&apb2>; clock-indices = <96>, <97>, <98>, <101>, <112>, <113>, <114>, <115>, <116>; clock-output-names = "bus_i2c0", "bus_i2c1", "bus_i2c2", "bus_scr", "bus_uart0", "bus_uart1", "bus_uart2", "bus_uart3", "bus_uart4"; }; };
mmc0_clk: mmc0_clk@1c20088 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc0"; };
mmc1_clk: mmc1_clk@1c2008c { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc1"; };
mmc2_clk: mmc2_clk@1c20090 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc2"; }; };
soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges;
mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; clocks = <&bus_gates 8>, <&mmc0_clk>, <&mmc0_clk>, <&mmc0_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 8>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc1: mmc@1c10000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; clocks = <&bus_gates 9>, <&mmc1_clk>, <&mmc1_clk>, <&mmc1_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 9>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc2: mmc@1c11000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; clocks = <&bus_gates 10>, <&mmc2_clk>, <&mmc2_clk>, <&mmc2_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 10>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 69>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
/* The A64 does not have bank A and leaves a hole in the address space where it normally would be */
gpiob: gpiob@24 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'B'>; reg = < 0x24 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; };
gpioc: gpioc@48 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x48 0x24 >; allwinner,gpiobank-name = <'C'>; };
gpiod: gpiod@6c { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x6c 0x24 >; allwinner,gpiobank-name = <'D'>; };
gpioe: gpioe@90 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x90 0x24 >; allwinner,gpiobank-name = <'E'>; };
gpiof: gpiof@b4 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xb4 0x24 >; allwinner,gpiobank-name = <'F'>; };
gpiog: gpiog@d8 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xd8 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'G'>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; };
gpioh: gpioh@fc { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xfc 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'H'>; interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; };
uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart0_pins_b: uart0_pins_b { allwinner,pins = "PF2", "PF3"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_2pins: uart1_2pins { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_4pins: uart1_4pins { allwinner,pins = "PG6", "PG7", "PG8", "PG9"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_2pins: uart2_2pins { allwinner,pins = "PB0", "PB1"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_4pins: uart2_4pins { allwinner,pins = "PB0", "PB1", "PB2", "PB3"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_pins_a: uart3_pins_a { allwinner,pins = "PD0", "PD1"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_2pins_b: uart3_2pins_b { allwinner,pins = "PH4", "PH5"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_4pins_b: uart3_4pins_b { allwinner,pins = "PH4", "PH5", "PH6", "PH7"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_2pins: uart4_2pins { allwinner,pins = "PD2", "PD3"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_4pins: uart4_4pins { allwinner,pins = "PD2", "PD3", "PD4", "PD5"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
mmc0_pins: mmc0_pins { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; - allwinner,drive = <SUN4I_PINCTRL_30_MA>; - allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + drive-strength = < 30 >; + bias-pull-up; };
mmc0_default_cd_pin: mmc0_cd_pin { allwinner,pins = "PF6"; allwinner,function = "gpio_in"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_PULL_UP>; };
mmc1_pins: mmc1_pins { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; - allwinner,drive = <SUN4I_PINCTRL_30_MA>; - allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + drive-strength = < 30 >; + bias-pull-up; };
mmc2_pins: mmc2_pins { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; - allwinner,drive = <SUN4I_PINCTRL_30_MA>; - allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + drive-strength = < 30 >; + bias-pull-up; + }; + + mmc2_8bit_pins: mmc2_8bit { + allwinner,pins = "PC5", "PC6", "PC8", + "PC9", "PC10", "PC11", + "PC12", "PC13", "PC14", + "PC15", "PC16"; + allwinner,function = "mmc2"; + drive-strength = < 30 >; + bias-pull-up; };
i2c0_pins: i2c0_pins { allwinner,pins = "PH0", "PH1"; allwinner,function = "i2c0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c1_pins: i2c1_pins { allwinner,pins = "PH2", "PH3"; allwinner,function = "i2c1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c2_pins: i2c2_pins { allwinner,pins = "PE14", "PE15"; allwinner,function = "i2c2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
rmii_pins: rmii_pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; allwinner,function = "emac"; allwinner,drive = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
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 = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; };
r_pio: pinctrl@01f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
gpiol: gpiol@0 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'L'>; reg = < 0x0 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; }; };
ahb_rst: reset@1c202c0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202c0 0xc>; };
apb1_rst: reset@1c202d0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d0 0x4>; };
apb2_rst: reset@1c202d8 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d8 0x4>; };
uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 112>; resets = <&apb2_rst 16>; status = "disabled"; };
uart1: serial@1c28400 { compatible = "snps,dw-apb-uart"; reg = <0x01c28400 0x400>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 113>; resets = <&apb2_rst 17>; status = "disabled"; };
uart2: serial@1c28800 { compatible = "snps,dw-apb-uart"; reg = <0x01c28800 0x400>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 114>; resets = <&apb2_rst 18>; status = "disabled"; };
uart3: serial@1c28c00 { compatible = "snps,dw-apb-uart"; reg = <0x01c28c00 0x400>; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 115>; resets = <&apb2_rst 19>; status = "disabled"; };
uart4: serial@1c29000 { compatible = "snps,dw-apb-uart"; reg = <0x01c29000 0x400>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 116>; resets = <&apb2_rst 20>; status = "disabled"; };
rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; };
i2c0: i2c@1c2ac00 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 96>; resets = <&apb2_rst 0>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c1: i2c@1c2b000 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b000 0x400>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 97>; resets = <&apb2_rst 1>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c2: i2c@1c2b400 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b400 0x400>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 98>; resets = <&apb2_rst 2>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
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 = <&ahb_rst 17>; reset-names = "ahb"; clocks = <&bus_gates 17>; clock-names = "ahb"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
usbphy: phy@1c1b810 { compatible = "allwinner,sun50i-a64-usb-phy", "allwinner,sun8i-a33-usb-phy"; reg = <0x01c1b810 0x14>, <0x01c1b800 0x4>; reg-names = "phy_ctrl", "pmu1"; status = "disabled"; #phy-cells = <1>; };
ehci1: usb@01c1b000 { compatible = "allwinner,sun50i-a64-ehci", "generic-ehci"; reg = <0x01c1b000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled"; };
ohci1: usb@01c1b400 { compatible = "allwinner,sun50i-a64-ohci", "generic-ohci"; reg = <0x01c1b400 0x100>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "enabled"; }; }; };

Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- arch/arm/dts/sun50i-a64.dtsi | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index b65d033..b540bd9 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -1,772 +1,818 @@ /* * Copyright (C) 2016 ARM Ltd. * based on the Allwinner H3 dtsi: * Copyright (C) 2015 Jens Kuske jenskuske@gmail.com * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual * licensing only applies to this file, and not this project as a * whole. * * a) This file 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 file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Or, alternatively, * * b) Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/pinctrl/sun4i-a10.h>
/ { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>;
cpus { #address-cells = <1>; #size-cells = <0>;
cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0>; enable-method = "psci"; };
cpu@1 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <1>; enable-method = "psci"; };
cpu@2 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <2>; enable-method = "psci"; };
cpu@3 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <3>; enable-method = "psci"; }; };
psci { compatible = "arm,psci-0.2"; method = "smc"; };
memory: memory@40000000 { device_type = "memory"; reg = <0x40000000 0>; };
gic: interrupt-controller@1c81000 { compatible = "arm,gic-400"; interrupt-controller; #interrupt-cells = <3>; #address-cells = <0>;
reg = <0x01c81000 0x1000>, <0x01c82000 0x2000>, <0x01c84000 0x2000>, <0x01c86000 0x2000>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; };
clocks { #address-cells = <1>; #size-cells = <1>; ranges;
osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "osc24M"; };
osc32k: osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; clock-output-names = "osc32k"; };
pll1: pll1_clk@1c20000 { #clock-cells = <0>; compatible = "allwinner,sun8i-a23-pll1-clk"; reg = <0x01c20000 0x4>; clocks = <&osc24M>; clock-output-names = "pll1"; };
pll6: pll6_clk@1c20028 { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c20028 0x4>; clocks = <&osc24M>; clock-output-names = "pll6", "pll6x2"; };
pll6d2: pll6d2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; clock-div = <2>; clock-mult = <1>; clocks = <&pll6 0>; clock-output-names = "pll6d2"; };
pll7: pll7_clk@1c2002c { #clock-cells = <1>; compatible = "allwinner,sun6i-a31-pll6-clk"; reg = <0x01c2002c 0x4>; clocks = <&osc24M>; clock-output-names = "pll7", "pll7x2"; };
cpu: cpu_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-cpu-clk"; reg = <0x01c20050 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>; clock-output-names = "cpu"; critical-clocks = <0>; };
axi: axi_clk@1c20050 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-axi-clk"; reg = <0x01c20050 0x4>; clocks = <&cpu>; clock-output-names = "axi"; };
ahb1: ahb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun6i-a31-ahb1-clk"; reg = <0x01c20054 0x4>; clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>; clock-output-names = "ahb1"; };
ahb2: ahb2_clk@1c2005c { #clock-cells = <0>; compatible = "allwinner,sun8i-h3-ahb2-clk"; reg = <0x01c2005c 0x4>; clocks = <&ahb1>, <&pll6d2>; clock-output-names = "ahb2"; };
apb1: apb1_clk@1c20054 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb0-clk"; reg = <0x01c20054 0x4>; clocks = <&ahb1>; clock-output-names = "apb1"; };
apb2: apb2_clk@1c20058 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-apb1-clk"; reg = <0x01c20058 0x4>; clocks = <&osc32k>, <&osc24M>, <&pll6 1>, <&pll6 1>; clock-output-names = "apb2"; };
bus_gates: bus_gates_clk@1c20060 { #clock-cells = <1>; compatible = "allwinner,sun50i-a64-bus-gates-clk", "allwinner,sunxi-multi-bus-gates-clk"; reg = <0x01c20060 0x14>; ahb1_parent { clocks = <&ahb1>; clock-indices = <1>, <5>, <6>, <8>, <9>, <10>, <13>, <14>, <18>, <19>, <20>, <21>, <23>, <24>, <25>, <28>, <32>, <35>, <36>, <37>, <40>, <43>, <44>, <52>, <53>, <54>, <135>; clock-output-names = "bus_mipidsi", "bus_ce", "bus_dma", "bus_mmc0", "bus_mmc1", "bus_mmc2", "bus_nand", "bus_sdram", "bus_ts", "bus_hstimer", "bus_spi0", "bus_spi1", "bus_otg", "bus_otg_ehci0", "bus_ehci0", "bus_otg_ohci0", "bus_ve", "bus_lcd0", "bus_lcd1", "bus_deint", "bus_csi", "bus_hdmi", "bus_de", "bus_gpu", "bus_msgbox", "bus_spinlock", "bus_dbg"; }; ahb2_parent { clocks = <&ahb2>; clock-indices = <17>, <29>; clock-output-names = "bus_gmac", "bus_ohci0"; }; apb1_parent { clocks = <&apb1>; clock-indices = <64>, <65>, <69>, <72>, <76>, <77>, <78>; clock-output-names = "bus_codec", "bus_spdif", "bus_pio", "bus_ths", "bus_i2s0", "bus_i2s1", "bus_i2s2"; }; abp2_parent { clocks = <&apb2>; clock-indices = <96>, <97>, <98>, <101>, <112>, <113>, <114>, <115>, <116>; clock-output-names = "bus_i2c0", "bus_i2c1", "bus_i2c2", "bus_scr", "bus_uart0", "bus_uart1", "bus_uart2", "bus_uart3", "bus_uart4"; }; };
mmc0_clk: mmc0_clk@1c20088 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc0"; };
mmc1_clk: mmc1_clk@1c2008c { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc1"; };
mmc2_clk: mmc2_clk@1c20090 { #clock-cells = <0>; compatible = "allwinner,sun4i-a10-mod0-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll7 1>; clock-output-names = "mmc2"; }; + + spi0_clk: spi0_clk@01c200a0 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-a10-mod0-clk"; + reg = <0x01c200a0 0x4>; + clocks = <&osc24M>, <&pll6 0>, <&pll7 0>; + clock-output-names = "spi0"; + }; + + spi1_clk: spi1_clk@01c200a4 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-a10-mod0-clk"; + reg = <0x01c200a4 0x4>; + clocks = <&osc24M>, <&pll6 0>, <&pll7 0>; + clock-output-names = "spi1"; + }; };
soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges;
mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; clocks = <&bus_gates 8>, <&mmc0_clk>, <&mmc0_clk>, <&mmc0_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 8>; reset-names = "ahb"; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc1: mmc@1c10000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c10000 0x1000>; clocks = <&bus_gates 9>, <&mmc1_clk>, <&mmc1_clk>, <&mmc1_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 9>; reset-names = "ahb"; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
mmc2: mmc@1c11000 { compatible = "allwinner,sun50i-a64-mmc", "allwinner,sun5i-a13-mmc"; reg = <0x01c11000 0x1000>; clocks = <&bus_gates 10>, <&mmc2_clk>, <&mmc2_clk>, <&mmc2_clk>; clock-names = "ahb", "mmc", "output", "sample"; resets = <&ahb_rst 10>; reset-names = "ahb"; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
pio: pinctrl@1c20800 { compatible = "allwinner,sun50i-a64-pinctrl"; reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 69>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
/* The A64 does not have bank A and leaves a hole in the address space where it normally would be */
gpiob: gpiob@24 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'B'>; reg = < 0x24 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; };
gpioc: gpioc@48 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x48 0x24 >; allwinner,gpiobank-name = <'C'>; };
gpiod: gpiod@6c { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x6c 0x24 >; allwinner,gpiobank-name = <'D'>; };
gpioe: gpioe@90 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0x90 0x24 >; allwinner,gpiobank-name = <'E'>; };
gpiof: gpiof@b4 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xb4 0x24 >; allwinner,gpiobank-name = <'F'>; };
gpiog: gpiog@d8 { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xd8 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'G'>; interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; };
gpioh: gpioh@fc { compatible = "allwinner,sunxi-gpiobank"; reg = < 0xfc 0x24 >, < 0x220 0x1c >; allwinner,gpiobank-name = <'H'>; interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; };
uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart0_pins_b: uart0_pins_b { allwinner,pins = "PF2", "PF3"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_2pins: uart1_2pins { allwinner,pins = "PG6", "PG7"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart1_4pins: uart1_4pins { allwinner,pins = "PG6", "PG7", "PG8", "PG9"; allwinner,function = "uart1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_2pins: uart2_2pins { allwinner,pins = "PB0", "PB1"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart2_4pins: uart2_4pins { allwinner,pins = "PB0", "PB1", "PB2", "PB3"; allwinner,function = "uart2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_pins_a: uart3_pins_a { allwinner,pins = "PD0", "PD1"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_2pins_b: uart3_2pins_b { allwinner,pins = "PH4", "PH5"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart3_4pins_b: uart3_4pins_b { allwinner,pins = "PH4", "PH5", "PH6", "PH7"; allwinner,function = "uart3"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_2pins: uart4_2pins { allwinner,pins = "PD2", "PD3"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
uart4_4pins: uart4_4pins { allwinner,pins = "PD2", "PD3", "PD4", "PD5"; allwinner,function = "uart4"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
mmc0_pins: mmc0_pins { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; drive-strength = < 30 >; bias-pull-up; };
mmc0_default_cd_pin: mmc0_cd_pin { allwinner,pins = "PF6"; allwinner,function = "gpio_in"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_PULL_UP>; };
mmc1_pins: mmc1_pins { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; drive-strength = < 30 >; bias-pull-up; };
mmc2_pins: mmc2_pins { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; drive-strength = < 30 >; bias-pull-up; };
mmc2_8bit_pins: mmc2_8bit { allwinner,pins = "PC5", "PC6", "PC8", "PC9", "PC10", "PC11", "PC12", "PC13", "PC14", "PC15", "PC16"; allwinner,function = "mmc2"; drive-strength = < 30 >; bias-pull-up; };
i2c0_pins: i2c0_pins { allwinner,pins = "PH0", "PH1"; allwinner,function = "i2c0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c1_pins: i2c1_pins { allwinner,pins = "PH2", "PH3"; allwinner,function = "i2c1"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
i2c2_pins: i2c2_pins { allwinner,pins = "PE14", "PE15"; allwinner,function = "i2c2"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
rmii_pins: rmii_pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; allwinner,function = "emac"; allwinner,drive = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; };
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 = <SUN4I_PINCTRL_40_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; + + spi0_pins: spi0_pins { + allwinner,pins = "PC0", "PC1", "PC2", "PC3"; + allwinner,function = "spi0"; + }; + + spi1_pins: spi1_pins { + allwinner,pins = "PD0", "PD1", "PD2", "PD3"; + allwinner,function = "spi1"; + }; };
r_pio: pinctrl@01f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller; #gpio-cells = <3>;
interrupt-controller; #interrupt-cells = <2>;
#address-cells = <1>; #size-cells = <1>;
gpiol: gpiol@0 { compatible = "allwinner,sunxi-gpiobank"; allwinner,gpiobank-name = <'L'>; reg = < 0x0 0x24 >, < 0x200 0x1c >; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; }; };
ahb_rst: reset@1c202c0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202c0 0xc>; };
apb1_rst: reset@1c202d0 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d0 0x4>; };
apb2_rst: reset@1c202d8 { #reset-cells = <1>; compatible = "allwinner,sun6i-a31-clock-reset"; reg = <0x01c202d8 0x4>; };
uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 112>; resets = <&apb2_rst 16>; status = "disabled"; };
uart1: serial@1c28400 { compatible = "snps,dw-apb-uart"; reg = <0x01c28400 0x400>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 113>; resets = <&apb2_rst 17>; status = "disabled"; };
uart2: serial@1c28800 { compatible = "snps,dw-apb-uart"; reg = <0x01c28800 0x400>; interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 114>; resets = <&apb2_rst 18>; status = "disabled"; };
uart3: serial@1c28c00 { compatible = "snps,dw-apb-uart"; reg = <0x01c28c00 0x400>; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 115>; resets = <&apb2_rst 19>; status = "disabled"; };
uart4: serial@1c29000 { compatible = "snps,dw-apb-uart"; reg = <0x01c29000 0x400>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clocks = <&bus_gates 116>; resets = <&apb2_rst 20>; status = "disabled"; };
rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; };
i2c0: i2c@1c2ac00 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 96>; resets = <&apb2_rst 0>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c1: i2c@1c2b000 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b000 0x400>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 97>; resets = <&apb2_rst 1>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
i2c2: i2c@1c2b400 { compatible = "allwinner,sun6i-a31-i2c"; reg = <0x01c2b400 0x400>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; clocks = <&bus_gates 98>; resets = <&apb2_rst 2>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
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 = <&ahb_rst 17>; reset-names = "ahb"; clocks = <&bus_gates 17>; clock-names = "ahb"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; };
usbphy: phy@1c1b810 { compatible = "allwinner,sun50i-a64-usb-phy", "allwinner,sun8i-a33-usb-phy"; reg = <0x01c1b810 0x14>, <0x01c1b800 0x4>; reg-names = "phy_ctrl", "pmu1"; status = "disabled"; #phy-cells = <1>; };
ehci1: usb@01c1b000 { compatible = "allwinner,sun50i-a64-ehci", "generic-ehci"; reg = <0x01c1b000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "disabled"; };
ohci1: usb@01c1b400 { compatible = "allwinner,sun50i-a64-ohci", "generic-ohci"; reg = <0x01c1b400 0x100>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy 1>; phy-names = "usb"; status = "enabled"; }; + + spi0: spi@01c68000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c68000 0x1000>; + clocks = <&bus_gates 20>, <&spi0_clk>; + clock-names = "ahb", "spi"; + resets = <&ahb_rst 20>; + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + spi1: spi@01c69000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c69000 0x1000>; + clocks = <&bus_gates 21>, <&spi1_clk>; + clock-names = "ahb", "spi"; + resets = <&ahb_rst 21>; + interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; }; };
participants (4)
-
Chen-Yu Tsai
-
Dr. Philipp Tomsich
-
Maxime Ripard
-
Philipp Tomsich