* [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation
@ 2017-02-22 20:47 Philipp Tomsich
2017-02-22 20:47 ` [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi Philipp Tomsich
` (5 more replies)
0 siblings, 6 replies; 19+ messages in thread
From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw)
To: u-boot
Here's v2, which incorporates the feedback from Maxime and ChenYu
into a more complete and less intrusive version.
The most elegant solution to our problem with pinctrl & gpio, which
will also work equally well for ccu and reset, is to have the device
model bind multiple drivers to a single node: for this reason, one
patch of the series touches the device-model core.
To provide a bit more context, I've also include the change showing
how this is enabled in our defconfig (i.e. a diff against our defconfig,
even though the defconfig has not been submitted yet).
Changes in v2:
* two variants to reuse the sunxi_gpio layer:
- create a matching soc_data for sunxi_gpio and rebind
- have the device-model do this for us
* got rid of the gpio-banks and gpiobridge drivers
Philipp Tomsich (6):
sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi
dm: core: Allow multiple drivers to bind for a single node
sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding
defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS
sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio
sun50i: dts: update DTS to avoid warnings
arch/arm/dts/sun50i-a64.dtsi | 62 ++-
arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 +
configs/lynx_defconfig | 1 +
.../pinctrl/allwinner,pinctrl.txt | 65 +++
drivers/core/Kconfig | 14 +
drivers/core/lists.c | 12 +-
drivers/gpio/sunxi_gpio.c | 15 +-
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 | 321 ++++++++++++
drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++
14 files changed, 1479 insertions(+), 32 deletions(-)
create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h
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
--
1.9.1
^ permalink raw reply [flat|nested] 19+ messages in thread* [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-02-22 23:18 ` Maxime Ripard 2017-02-22 20:47 ` [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node Philipp Tomsich ` (4 subsequent siblings) 5 siblings, 1 reply; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot 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 * dynamically creates the driver_data for a sunxi_gpio (see sunxi_gpio.c) driver and binds it to the same device-tree node * 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) Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> --- arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + .../pinctrl/allwinner,pinctrl.txt | 65 +++ drivers/gpio/sunxi_gpio.c | 15 +- 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 | 317 +++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ 10 files changed, 1411 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h 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/arch/arm/include/asm/arch-sunxi/gpio-internal.h b/arch/arm/include/asm/arch-sunxi/gpio-internal.h new file mode 100644 index 0000000..4dcdd34 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/gpio-internal.h @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + +#ifndef _SUNXI_GPIO_INTERNAL_H +#define _SUNXI_GPIO_INTERNAL_H + +/* This data structure is shared between the sunxi_gpio driver and + * the sunxi_pinctrl driver. + */ +struct sunxi_gpio_soc_data { + int start; + int no_banks; +}; + +#endif 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..946831f --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt @@ -0,0 +1,65 @@ +* 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. + +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> + +Example: + + pio: pinctrl at 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>; + + 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..fd0c1ac 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -16,6 +16,7 @@ #include <fdtdec.h> #include <malloc.h> #include <asm/arch/gpio.h> +#include <asm/arch/gpio-internal.h> #include <asm/io.h> #include <asm/gpio.h> #include <dm/device-internal.h> @@ -275,11 +276,6 @@ static int gpio_sunxi_probe(struct udevice *dev) return 0; } -struct sunxi_gpio_soc_data { - int start; - int no_banks; -}; - /** * We have a top-level GPIO device with no actual GPIOs. It has a child * device for each Sunxi bank. @@ -353,18 +349,22 @@ static const struct udevice_id sunxi_gpio_ids[] = { 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 { } }; @@ -376,4 +376,5 @@ U_BOOT_DRIVER(gpio_sunxi) = { .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, }; + #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 @@ -16,3 +16,5 @@ 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..4640cee --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,317 @@ +/* + * (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 <asm/arch/gpio-internal.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> +#include <dt-bindings/gpio/gpio.h> +#include <linux/kernel.h> +#include "pinctrl-sunxi.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_pctrl_priv { + void *base; +#if defined(CONFIG_DM_GPIO) + struct sunxi_gpio_soc_data gpio_soc_data; + struct udevice *gpio_dev; +#endif +}; + +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 inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, + struct sunxi_gpio_soc_data *soc_data) +{ + int i; + unsigned pinnum; + unsigned low = data->pin_base / PINS_PER_BANK; + unsigned high = data->pin_base; + + for (i = 0; i < data->npins; ++i) { + pinnum = data->pins[i].pin.number; + high = max(high, pinnum); + } + + /* convert pin-numbers to bank numbers */ + high /= PINS_PER_BANK; + + soc_data->start = low; + soc_data->no_banks = high - low + 1; +} + +static int sunxi_pctrl_bind_gpio(struct udevice *dev) +{ +#if defined(CONFIG_DM_GPIO) + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); + const struct sunxi_pinctrl_desc *data = + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); + struct driver *gpio_driver; + char name[20]; + int ret; + + /* Fill the soc_data for the gpio driver from the pinctrl_desc */ + soc_data_from_desc(data, &priv->gpio_soc_data); + + gpio_driver = lists_driver_lookup_name("gpio_sunxi"); + if (!gpio_driver) + return -ENOENT; + + ret = device_bind_with_driver_data(dev, gpio_driver, "sunxi_gpio", + (ulong)&priv->gpio_soc_data, + dev->of_offset, &priv->gpio_dev); + + if (ret < 0) + return ret; + + snprintf(name, sizeof(name), "sunxi_gpio@%x", (uint32_t)priv->base); + device_set_name(priv->gpio_dev, name); +#endif + + return 0; +} + +static int sunxi_pctrl_probe(struct udevice *dev) +{ + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); + 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; + + return sunxi_pctrl_bind_gpio(dev); +} + +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, +}; + 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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi 2017-02-22 20:47 ` [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi Philipp Tomsich @ 2017-02-22 23:18 ` Maxime Ripard 2017-02-23 3:54 ` Chen-Yu Tsai 0 siblings, 1 reply; 19+ messages in thread From: Maxime Ripard @ 2017-02-22 23:18 UTC (permalink / raw) To: u-boot On Wed, Feb 22, 2017 at 09:47:27PM +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 > * dynamically creates the driver_data for a sunxi_gpio (see sunxi_gpio.c) > driver and binds it to the same device-tree node > * 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) > > Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> > --- > arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + > .../pinctrl/allwinner,pinctrl.txt | 65 +++ > drivers/gpio/sunxi_gpio.c | 15 +- > 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 | 317 +++++++++++ > drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ > 10 files changed, 1411 insertions(+), 7 deletions(-) > create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h > 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/arch/arm/include/asm/arch-sunxi/gpio-internal.h b/arch/arm/include/asm/arch-sunxi/gpio-internal.h > new file mode 100644 > index 0000000..4dcdd34 > --- /dev/null > +++ b/arch/arm/include/asm/arch-sunxi/gpio-internal.h > @@ -0,0 +1,19 @@ > +/* > + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > + > +#ifndef _SUNXI_GPIO_INTERNAL_H > +#define _SUNXI_GPIO_INTERNAL_H > + > +/* This data structure is shared between the sunxi_gpio driver and > + * the sunxi_pinctrl driver. > + */ > +struct sunxi_gpio_soc_data { > + int start; > + int no_banks; > +}; > + > +#endif > 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..946831f > --- /dev/null > +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt > @@ -0,0 +1,65 @@ > +* 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. > + > +Properties for the pinctrl node: > + - compatible: should be "allwinner,sun50i-pinctrl" There's a typo here, the compatible is sun50i-a64-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 (and ideally, this would take three clocks: the bus gate + the two oscillators). > + > +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") allwinner,pins and allwinner,function are also deprecated in favour of pins and function. > + - drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA > + - bias-pull-up > + - bias-pull-down > + - bias-disable (default) The default is not bias-disable, but to keep the current configuration > + > +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> > + > +Example: > + > + pio: pinctrl at 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>; > + > + 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..fd0c1ac 100644 > --- a/drivers/gpio/sunxi_gpio.c > +++ b/drivers/gpio/sunxi_gpio.c > @@ -16,6 +16,7 @@ > #include <fdtdec.h> > #include <malloc.h> > #include <asm/arch/gpio.h> > +#include <asm/arch/gpio-internal.h> > #include <asm/io.h> > #include <asm/gpio.h> > #include <dm/device-internal.h> > @@ -275,11 +276,6 @@ static int gpio_sunxi_probe(struct udevice *dev) > return 0; > } > > -struct sunxi_gpio_soc_data { > - int start; > - int no_banks; > -}; > - > /** > * We have a top-level GPIO device with no actual GPIOs. It has a child > * device for each Sunxi bank. > @@ -353,18 +349,22 @@ static const struct udevice_id sunxi_gpio_ids[] = { > 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 > { } > }; > > @@ -376,4 +376,5 @@ U_BOOT_DRIVER(gpio_sunxi) = { > .bind = gpio_sunxi_bind, > .probe = gpio_sunxi_probe, > }; > + > #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 > @@ -16,3 +16,5 @@ 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..4640cee > --- /dev/null > +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c > @@ -0,0 +1,317 @@ > +/* > + * (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 <asm/arch/gpio-internal.h> > +#include <dm/device-internal.h> > +#include <dm/lists.h> > +#include <dm/pinctrl.h> > +#include <dt-bindings/pinctrl/sun4i-a10.h> > +#include <dt-bindings/gpio/gpio.h> > +#include <linux/kernel.h> > +#include "pinctrl-sunxi.h" > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct sunxi_pctrl_priv { > + void *base; > +#if defined(CONFIG_DM_GPIO) > + struct sunxi_gpio_soc_data gpio_soc_data; > + struct udevice *gpio_dev; > +#endif > +}; > + > +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 inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, > + struct sunxi_gpio_soc_data *soc_data) > +{ > + int i; > + unsigned pinnum; > + unsigned low = data->pin_base / PINS_PER_BANK; > + unsigned high = data->pin_base; > + > + for (i = 0; i < data->npins; ++i) { > + pinnum = data->pins[i].pin.number; > + high = max(high, pinnum); > + } > + > + /* convert pin-numbers to bank numbers */ > + high /= PINS_PER_BANK; > + > + soc_data->start = low; > + soc_data->no_banks = high - low + 1; > +} > + > +static int sunxi_pctrl_bind_gpio(struct udevice *dev) > +{ > +#if defined(CONFIG_DM_GPIO) > + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); > + const struct sunxi_pinctrl_desc *data = > + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); > + struct driver *gpio_driver; > + char name[20]; > + int ret; > + > + /* Fill the soc_data for the gpio driver from the pinctrl_desc */ > + soc_data_from_desc(data, &priv->gpio_soc_data); > + > + gpio_driver = lists_driver_lookup_name("gpio_sunxi"); > + if (!gpio_driver) > + return -ENOENT; > + > + ret = device_bind_with_driver_data(dev, gpio_driver, "sunxi_gpio", > + (ulong)&priv->gpio_soc_data, > + dev->of_offset, &priv->gpio_dev); > + > + if (ret < 0) > + return ret; > + > + snprintf(name, sizeof(name), "sunxi_gpio@%x", (uint32_t)priv->base); > + device_set_name(priv->gpio_dev, name); > +#endif > + > + return 0; > +} > + > +static int sunxi_pctrl_probe(struct udevice *dev) > +{ > + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); > + 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; > + > + return sunxi_pctrl_bind_gpio(dev); > +} > + > +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, > +}; > + > 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 > -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170222/1b5a1029/attachment.sig> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi 2017-02-22 23:18 ` Maxime Ripard @ 2017-02-23 3:54 ` Chen-Yu Tsai 2017-02-23 18:10 ` Maxime Ripard 0 siblings, 1 reply; 19+ messages in thread From: Chen-Yu Tsai @ 2017-02-23 3:54 UTC (permalink / raw) To: u-boot On Thu, Feb 23, 2017 at 7:18 AM, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > On Wed, Feb 22, 2017 at 09:47:27PM +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 >> * dynamically creates the driver_data for a sunxi_gpio (see sunxi_gpio.c) >> driver and binds it to the same device-tree node >> * 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) >> >> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> >> --- >> arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + >> .../pinctrl/allwinner,pinctrl.txt | 65 +++ >> drivers/gpio/sunxi_gpio.c | 15 +- >> 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 | 317 +++++++++++ >> drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ >> 10 files changed, 1411 insertions(+), 7 deletions(-) >> create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h >> 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/arch/arm/include/asm/arch-sunxi/gpio-internal.h b/arch/arm/include/asm/arch-sunxi/gpio-internal.h >> new file mode 100644 >> index 0000000..4dcdd34 >> --- /dev/null >> +++ b/arch/arm/include/asm/arch-sunxi/gpio-internal.h >> @@ -0,0 +1,19 @@ >> +/* >> + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> + >> +#ifndef _SUNXI_GPIO_INTERNAL_H >> +#define _SUNXI_GPIO_INTERNAL_H >> + >> +/* This data structure is shared between the sunxi_gpio driver and >> + * the sunxi_pinctrl driver. >> + */ >> +struct sunxi_gpio_soc_data { >> + int start; >> + int no_banks; >> +}; >> + >> +#endif >> 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..946831f >> --- /dev/null >> +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt >> @@ -0,0 +1,65 @@ >> +* 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. >> + >> +Properties for the pinctrl node: >> + - compatible: should be "allwinner,sun50i-pinctrl" > > There's a typo here, the compatible is sun50i-a64-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 > > (and ideally, this would take three clocks: the bus gate + the two > oscillators). > >> + >> +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") > > allwinner,pins and allwinner,function are also deprecated in favour of > pins and function. > >> + - drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA >> + - bias-pull-up >> + - bias-pull-down >> + - bias-disable (default) > > The default is not bias-disable, but to keep the current configuration Shouldn't we just copy the binding docs from the Linux kernel? Afterall they are supposed to be the same. ChenYu >> + >> +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> >> + >> +Example: >> + >> + pio: pinctrl at 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>; >> + >> + 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..fd0c1ac 100644 >> --- a/drivers/gpio/sunxi_gpio.c >> +++ b/drivers/gpio/sunxi_gpio.c >> @@ -16,6 +16,7 @@ >> #include <fdtdec.h> >> #include <malloc.h> >> #include <asm/arch/gpio.h> >> +#include <asm/arch/gpio-internal.h> >> #include <asm/io.h> >> #include <asm/gpio.h> >> #include <dm/device-internal.h> >> @@ -275,11 +276,6 @@ static int gpio_sunxi_probe(struct udevice *dev) >> return 0; >> } >> >> -struct sunxi_gpio_soc_data { >> - int start; >> - int no_banks; >> -}; >> - >> /** >> * We have a top-level GPIO device with no actual GPIOs. It has a child >> * device for each Sunxi bank. >> @@ -353,18 +349,22 @@ static const struct udevice_id sunxi_gpio_ids[] = { >> 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 >> { } >> }; >> >> @@ -376,4 +376,5 @@ U_BOOT_DRIVER(gpio_sunxi) = { >> .bind = gpio_sunxi_bind, >> .probe = gpio_sunxi_probe, >> }; >> + >> #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 >> @@ -16,3 +16,5 @@ 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..4640cee >> --- /dev/null >> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c >> @@ -0,0 +1,317 @@ >> +/* >> + * (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 <asm/arch/gpio-internal.h> >> +#include <dm/device-internal.h> >> +#include <dm/lists.h> >> +#include <dm/pinctrl.h> >> +#include <dt-bindings/pinctrl/sun4i-a10.h> >> +#include <dt-bindings/gpio/gpio.h> >> +#include <linux/kernel.h> >> +#include "pinctrl-sunxi.h" >> + >> +DECLARE_GLOBAL_DATA_PTR; >> + >> +struct sunxi_pctrl_priv { >> + void *base; >> +#if defined(CONFIG_DM_GPIO) >> + struct sunxi_gpio_soc_data gpio_soc_data; >> + struct udevice *gpio_dev; >> +#endif >> +}; >> + >> +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 inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, >> + struct sunxi_gpio_soc_data *soc_data) >> +{ >> + int i; >> + unsigned pinnum; >> + unsigned low = data->pin_base / PINS_PER_BANK; >> + unsigned high = data->pin_base; >> + >> + for (i = 0; i < data->npins; ++i) { >> + pinnum = data->pins[i].pin.number; >> + high = max(high, pinnum); >> + } >> + >> + /* convert pin-numbers to bank numbers */ >> + high /= PINS_PER_BANK; >> + >> + soc_data->start = low; >> + soc_data->no_banks = high - low + 1; >> +} >> + >> +static int sunxi_pctrl_bind_gpio(struct udevice *dev) >> +{ >> +#if defined(CONFIG_DM_GPIO) >> + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); >> + const struct sunxi_pinctrl_desc *data = >> + (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); >> + struct driver *gpio_driver; >> + char name[20]; >> + int ret; >> + >> + /* Fill the soc_data for the gpio driver from the pinctrl_desc */ >> + soc_data_from_desc(data, &priv->gpio_soc_data); >> + >> + gpio_driver = lists_driver_lookup_name("gpio_sunxi"); >> + if (!gpio_driver) >> + return -ENOENT; >> + >> + ret = device_bind_with_driver_data(dev, gpio_driver, "sunxi_gpio", >> + (ulong)&priv->gpio_soc_data, >> + dev->of_offset, &priv->gpio_dev); >> + >> + if (ret < 0) >> + return ret; >> + >> + snprintf(name, sizeof(name), "sunxi_gpio@%x", (uint32_t)priv->base); >> + device_set_name(priv->gpio_dev, name); >> +#endif >> + >> + return 0; >> +} >> + >> +static int sunxi_pctrl_probe(struct udevice *dev) >> +{ >> + struct sunxi_pctrl_priv *priv = dev_get_priv(dev); >> + 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; >> + >> + return sunxi_pctrl_bind_gpio(dev); >> +} >> + >> +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, >> +}; >> + >> 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 >> > > -- > Maxime Ripard, Free Electrons > Embedded Linux and Kernel engineering > http://free-electrons.com ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi 2017-02-23 3:54 ` Chen-Yu Tsai @ 2017-02-23 18:10 ` Maxime Ripard 0 siblings, 0 replies; 19+ messages in thread From: Maxime Ripard @ 2017-02-23 18:10 UTC (permalink / raw) To: u-boot On Thu, Feb 23, 2017 at 11:54:15AM +0800, Chen-Yu Tsai wrote: > On Thu, Feb 23, 2017 at 7:18 AM, Maxime Ripard > <maxime.ripard@free-electrons.com> wrote: > > On Wed, Feb 22, 2017 at 09:47:27PM +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 > >> * dynamically creates the driver_data for a sunxi_gpio (see sunxi_gpio.c) > >> driver and binds it to the same device-tree node > >> * 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) > >> > >> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> > >> --- > >> arch/arm/include/asm/arch-sunxi/gpio-internal.h | 19 + > >> .../pinctrl/allwinner,pinctrl.txt | 65 +++ > >> drivers/gpio/sunxi_gpio.c | 15 +- > >> 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 | 317 +++++++++++ > >> drivers/pinctrl/sunxi/pinctrl-sunxi.h | 311 +++++++++++ > >> 10 files changed, 1411 insertions(+), 7 deletions(-) > >> create mode 100644 arch/arm/include/asm/arch-sunxi/gpio-internal.h > >> 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/arch/arm/include/asm/arch-sunxi/gpio-internal.h b/arch/arm/include/asm/arch-sunxi/gpio-internal.h > >> new file mode 100644 > >> index 0000000..4dcdd34 > >> --- /dev/null > >> +++ b/arch/arm/include/asm/arch-sunxi/gpio-internal.h > >> @@ -0,0 +1,19 @@ > >> +/* > >> + * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH > >> + * > >> + * SPDX-License-Identifier: GPL-2.0+ > >> + */ > >> + > >> + > >> +#ifndef _SUNXI_GPIO_INTERNAL_H > >> +#define _SUNXI_GPIO_INTERNAL_H > >> + > >> +/* This data structure is shared between the sunxi_gpio driver and > >> + * the sunxi_pinctrl driver. > >> + */ > >> +struct sunxi_gpio_soc_data { > >> + int start; > >> + int no_banks; > >> +}; > >> + > >> +#endif > >> 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..946831f > >> --- /dev/null > >> +++ b/doc/device-tree-bindings/pinctrl/allwinner,pinctrl.txt > >> @@ -0,0 +1,65 @@ > >> +* 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. > >> + > >> +Properties for the pinctrl node: > >> + - compatible: should be "allwinner,sun50i-pinctrl" > > > > There's a typo here, the compatible is sun50i-a64-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 > > > > (and ideally, this would take three clocks: the bus gate + the two > > oscillators). > > > >> + > >> +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") > > > > allwinner,pins and allwinner,function are also deprecated in favour of > > pins and function. > > > >> + - drive-strength: a drive-stength setting of 10, 20, 30 or 40 mA > >> + - bias-pull-up > >> + - bias-pull-down > >> + - bias-disable (default) > > > > The default is not bias-disable, but to keep the current configuration > > Shouldn't we just copy the binding docs from the Linux kernel? > Afterall they are supposed to be the same. Yep, that would probably be the easiest. Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170223/ccf5b85f/attachment-0001.sig> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-03-03 4:52 ` Simon Glass 2017-02-22 20:47 ` [U-Boot] [PATCH v2 3/6] sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding Philipp Tomsich ` (3 subsequent siblings) 5 siblings, 1 reply; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot Currently, driver binding stops once it encounters the first compatible driver that doesn't refuse to bind. However, there are cases where a single node will need to be handled by multiple driver classes. For those cases we provide a configurable option to continue to bind after the first driver has been found. The first use cases for this are from the DM conversion of the sunxi (Allwinner) architecture: * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to bind against a single node * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to bind against a single node Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> --- drivers/core/Kconfig | 14 ++++++++++++++ drivers/core/lists.c | 12 +++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 8749561..913101c 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -31,6 +31,20 @@ config DM_WARN This will cause dm_warn() to be compiled out - it will do nothing when called. +config DM_ALLOW_MULTIPLE_DRIVERS + bool "Allow multiple drivers to bind for one node" + depends on DM + default n + help + The driver model in U-Boot originally did not allow multiple + drivers to bind for a single device node. + + If enabled, multiple drivers can now bind for a single node + by using the same compatible string for matching: lists_bind_fdt() + will assume that binding multiple drivers is desirable, if the + caller does not request the pointer to the udevice structure to + be returned (i.e. if devp is NULL). + config DM_DEVICE_REMOVE bool "Support device removal" depends on DM diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 23b6ba7..52efe69 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -166,7 +166,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_dbg(" - attempt to match compatible string '%s'\n", compat); - for (entry = driver; entry != driver + n_ents; entry++) { + entry = driver; +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) + allow_more_matches: +#endif + for (; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, compat); if (!ret) @@ -190,6 +194,12 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, found = true; if (devp) *devp = dev; +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) + else { + entry++; + goto allow_more_matches; + } +#endif } break; } -- 1.9.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-02-22 20:47 ` [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node Philipp Tomsich @ 2017-03-03 4:52 ` Simon Glass 2017-03-03 10:52 ` Dr. Philipp Tomsich 0 siblings, 1 reply; 19+ messages in thread From: Simon Glass @ 2017-03-03 4:52 UTC (permalink / raw) To: u-boot Hi Philipp, On 22 February 2017 at 13:47, Philipp Tomsich <philipp.tomsich@theobroma-systems.com> wrote: > Currently, driver binding stops once it encounters the first > compatible driver that doesn't refuse to bind. However, there are > cases where a single node will need to be handled by multiple driver > classes. For those cases we provide a configurable option to continue > to bind after the first driver has been found. > > The first use cases for this are from the DM conversion of the sunxi > (Allwinner) architecture: > * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to > bind against a single node > * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to > bind against a single node Does linux work this way? Another approach would be to have a separate MISC driver with two children, one pinctrl, one clk. > > Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> > --- > drivers/core/Kconfig | 14 ++++++++++++++ > drivers/core/lists.c | 12 +++++++++++- > 2 files changed, 25 insertions(+), 1 deletion(-) > > diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig > index 8749561..913101c 100644 > --- a/drivers/core/Kconfig > +++ b/drivers/core/Kconfig > @@ -31,6 +31,20 @@ config DM_WARN > This will cause dm_warn() to be compiled out - it will do nothing > when called. > > +config DM_ALLOW_MULTIPLE_DRIVERS > + bool "Allow multiple drivers to bind for one node" > + depends on DM > + default n You should be able to drop this line. > + help > + The driver model in U-Boot originally did not allow multiple > + drivers to bind for a single device node. > + > + If enabled, multiple drivers can now bind for a single node > + by using the same compatible string for matching: lists_bind_fdt() > + will assume that binding multiple drivers is desirable, if the > + caller does not request the pointer to the udevice structure to > + be returned (i.e. if devp is NULL). Please update the function documentation in the header file. > + > config DM_DEVICE_REMOVE > bool "Support device removal" > depends on DM > diff --git a/drivers/core/lists.c b/drivers/core/lists.c > index 23b6ba7..52efe69 100644 > --- a/drivers/core/lists.c > +++ b/drivers/core/lists.c > @@ -166,7 +166,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, > dm_dbg(" - attempt to match compatible string '%s'\n", > compat); > > - for (entry = driver; entry != driver + n_ents; entry++) { > + entry = driver; > +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) > + allow_more_matches: > +#endif > + for (; entry != driver + n_ents; entry++) { > ret = driver_check_compatible(entry->of_match, &id, > compat); > if (!ret) > @@ -190,6 +194,12 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, > found = true; > if (devp) > *devp = dev; > +#if defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) Can you make this a variable, e.g. with allow_multiple = IS_ENABLED(DM_ALLOW_MULTIPLE_DRIVERS)? I'd prefer not to add #ifdefs in this file. > + else { > + entry++; > + goto allow_more_matches; Is it possible to loop without using goto? > + } > +#endif > } > break; > } > -- > 1.9.1 > Regards, Simon ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-03-03 4:52 ` Simon Glass @ 2017-03-03 10:52 ` Dr. Philipp Tomsich 2017-03-12 20:21 ` Simon Glass 0 siblings, 1 reply; 19+ messages in thread From: Dr. Philipp Tomsich @ 2017-03-03 10:52 UTC (permalink / raw) To: u-boot Hi Simon, > On 03 Mar 2017, at 05:52, Simon Glass <sjg@chromium.org> wrote: > > Hi Philipp, > > On 22 February 2017 at 13:47, Philipp Tomsich > <philipp.tomsich at theobroma-systems.com <mailto:philipp.tomsich@theobroma-systems.com>> wrote: >> Currently, driver binding stops once it encounters the first >> compatible driver that doesn't refuse to bind. However, there are >> cases where a single node will need to be handled by multiple driver >> classes. For those cases we provide a configurable option to continue >> to bind after the first driver has been found. >> >> The first use cases for this are from the DM conversion of the sunxi >> (Allwinner) architecture: >> * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to >> bind against a single node >> * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to >> bind against a single node > > Does linux work this way? Another approach would be to have a separate > MISC driver with two children, one pinctrl, one clk. The linux CLK driver creates and registers a reset-controller; the PINCTRL driver does the same with the gpio-controller. Similar code to do this is easily possible in U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series. However, binding multiple times makes for much simpler code and allows to keep driver data in separate drivers. Regards, Philipp. ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-03-03 10:52 ` Dr. Philipp Tomsich @ 2017-03-12 20:21 ` Simon Glass 2017-03-13 8:40 ` Heiko Stübner 2017-03-20 7:08 ` Maxime Ripard 0 siblings, 2 replies; 19+ messages in thread From: Simon Glass @ 2017-03-12 20:21 UTC (permalink / raw) To: u-boot Hi, On 3 March 2017 at 03:52, Dr. Philipp Tomsich <philipp.tomsich@theobroma-systems.com> wrote: > Hi Simon, > > On 03 Mar 2017, at 05:52, Simon Glass <sjg@chromium.org> wrote: > > Hi Philipp, > > On 22 February 2017 at 13:47, Philipp Tomsich > <philipp.tomsich@theobroma-systems.com> wrote: > > Currently, driver binding stops once it encounters the first > compatible driver that doesn't refuse to bind. However, there are > cases where a single node will need to be handled by multiple driver > classes. For those cases we provide a configurable option to continue > to bind after the first driver has been found. > > The first use cases for this are from the DM conversion of the sunxi > (Allwinner) architecture: > * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to > bind against a single node > * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to > bind against a single node > > > Does linux work this way? Another approach would be to have a separate > MISC driver with two children, one pinctrl, one clk. > > > The linux CLK driver creates and registers a reset-controller; the PINCTRL > driver > does the same with the gpio-controller. Similar code to do this is easily > possible in > U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series. > > However, binding multiple times makes for much simpler code and allows to > keep > driver data in separate drivers. My question was more whether Linux registers multiple drivers with one device node. It's just not something I expected. I'm not really convinced on this. It will break the current one-to-one relationship, and functions like device_get_child_by_of_offset(). I think it would be better to have a MISC driver with two children. Regards, Simon ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-03-12 20:21 ` Simon Glass @ 2017-03-13 8:40 ` Heiko Stübner 2017-03-20 7:08 ` Maxime Ripard 1 sibling, 0 replies; 19+ messages in thread From: Heiko Stübner @ 2017-03-13 8:40 UTC (permalink / raw) To: u-boot Hi Simon, Am Sonntag, 12. März 2017, 14:21:35 CET schrieb Simon Glass: > On 3 March 2017 at 03:52, Dr. Philipp Tomsich > <philipp.tomsich@theobroma-systems.com> wrote: > > On 03 Mar 2017, at 05:52, Simon Glass <sjg@chromium.org> wrote: > > On 22 February 2017 at 13:47, Philipp Tomsich > > <philipp.tomsich@theobroma-systems.com> wrote: > > > > Currently, driver binding stops once it encounters the first > > compatible driver that doesn't refuse to bind. However, there are > > cases where a single node will need to be handled by multiple driver > > classes. For those cases we provide a configurable option to continue > > to bind after the first driver has been found. > > > > The first use cases for this are from the DM conversion of the sunxi > > (Allwinner) architecture: > > * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to > > > > bind against a single node > > > > * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to > > > > bind against a single node > > > > Does linux work this way? Another approach would be to have a separate > > MISC driver with two children, one pinctrl, one clk. > > > > > > The linux CLK driver creates and registers a reset-controller; the PINCTRL > > driver > > does the same with the gpio-controller. Similar code to do this is easily > > possible in > > U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series. > > > > However, binding multiple times makes for much simpler code and allows to > > keep > > driver data in separate drivers. > > My question was more whether Linux registers multiple drivers with one > device node. It's just not something I expected. > > I'm not really convinced on this. It will break the current one-to-one > relationship, and functions like device_get_child_by_of_offset(). I > think it would be better to have a MISC driver with two children. In the regular device model the Linux kernel also generally has a one-to-one model. There are special cases, like clock and timer init using special handling, or things like "syscon" which acts like more of a flag and can live next to a regular device. Therefore things like the Rockchip clock controller create the reset controller included in the CRU block. A behaviour the uboot clk driver mimics. Also doesn't allowing multiple drivers to sit on top of a node create contention on who gets access to registers? At least in the kernel multiple mappings of registers are generally not favoured. Heiko ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-03-12 20:21 ` Simon Glass 2017-03-13 8:40 ` Heiko Stübner @ 2017-03-20 7:08 ` Maxime Ripard 2017-03-22 13:05 ` Simon Glass 1 sibling, 1 reply; 19+ messages in thread From: Maxime Ripard @ 2017-03-20 7:08 UTC (permalink / raw) To: u-boot On Sun, Mar 12, 2017 at 02:21:35PM -0600, Simon Glass wrote: > Hi, > > On 3 March 2017 at 03:52, Dr. Philipp Tomsich > <philipp.tomsich@theobroma-systems.com> wrote: > > Hi Simon, > > > > On 03 Mar 2017, at 05:52, Simon Glass <sjg@chromium.org> wrote: > > > > Hi Philipp, > > > > On 22 February 2017 at 13:47, Philipp Tomsich > > <philipp.tomsich@theobroma-systems.com> wrote: > > > > Currently, driver binding stops once it encounters the first > > compatible driver that doesn't refuse to bind. However, there are > > cases where a single node will need to be handled by multiple driver > > classes. For those cases we provide a configurable option to continue > > to bind after the first driver has been found. > > > > The first use cases for this are from the DM conversion of the sunxi > > (Allwinner) architecture: > > * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to > > bind against a single node > > * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to > > bind against a single node > > > > > > Does linux work this way? Another approach would be to have a separate > > MISC driver with two children, one pinctrl, one clk. > > > > > > The linux CLK driver creates and registers a reset-controller; the PINCTRL > > driver > > does the same with the gpio-controller. Similar code to do this is easily > > possible in > > U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series. > > > > However, binding multiple times makes for much simpler code and allows to > > keep > > driver data in separate drivers. > > My question was more whether Linux registers multiple drivers with one > device node. It's just not something I expected. It does, but it's not really what we're doing in the linux driver. It has one driver, with one device, but registering into multiple frameworks. Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170320/13f2e446/attachment.sig> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node 2017-03-20 7:08 ` Maxime Ripard @ 2017-03-22 13:05 ` Simon Glass 0 siblings, 0 replies; 19+ messages in thread From: Simon Glass @ 2017-03-22 13:05 UTC (permalink / raw) To: u-boot Hi, On 20 March 2017 at 01:08, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > On Sun, Mar 12, 2017 at 02:21:35PM -0600, Simon Glass wrote: >> Hi, >> >> On 3 March 2017 at 03:52, Dr. Philipp Tomsich >> <philipp.tomsich@theobroma-systems.com> wrote: >> > Hi Simon, >> > >> > On 03 Mar 2017, at 05:52, Simon Glass <sjg@chromium.org> wrote: >> > >> > Hi Philipp, >> > >> > On 22 February 2017 at 13:47, Philipp Tomsich >> > <philipp.tomsich@theobroma-systems.com> wrote: >> > >> > Currently, driver binding stops once it encounters the first >> > compatible driver that doesn't refuse to bind. However, there are >> > cases where a single node will need to be handled by multiple driver >> > classes. For those cases we provide a configurable option to continue >> > to bind after the first driver has been found. >> > >> > The first use cases for this are from the DM conversion of the sunxi >> > (Allwinner) architecture: >> > * pinctrl (UCLASS_PINCTRL) and gpio (UCLASS_GPIO) drivers need to >> > bind against a single node >> > * clock (UCLASS_CLK) and reset (UCLASS_RESET) drivers also need to >> > bind against a single node >> > >> > >> > Does linux work this way? Another approach would be to have a separate >> > MISC driver with two children, one pinctrl, one clk. >> > >> > >> > The linux CLK driver creates and registers a reset-controller; the PINCTRL >> > driver >> > does the same with the gpio-controller. Similar code to do this is easily >> > possible in >> > U-Boot … see sunxi_pctrl_bind_gpio(…) in [PATCH v2 1/6] of this series. >> > >> > However, binding multiple times makes for much simpler code and allows to >> > keep >> > driver data in separate drivers. >> >> My question was more whether Linux registers multiple drivers with one >> device node. It's just not something I expected. > > It does, but it's not really what we're doing in the linux driver. It > has one driver, with one device, but registering into multiple > frameworks. I believe that the U-Boot equivalent of this is to have a parent device with several children each in its own uclass. Regards, Simon ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 3/6] sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS Philipp Tomsich ` (2 subsequent siblings) 5 siblings, 0 replies; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot Our gpio and pinctrl driver need to be bound against the same node. While this can be done by hand (i.e. explicitly looking up the driver, creating the driver-data and binding the device), it is much easier done when the new option for the binding of multiple drivers against a single node is configured. Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> --- drivers/gpio/sunxi_gpio.c | 4 ++-- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index fd0c1ac..cbec1b9 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -349,7 +349,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { 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) +#if !defined(CONFIG_SUNXI_PINCTRL) || defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) /* 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 @@ -362,7 +362,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3), -#if !defined(CONFIG_SUNXI_PINCTRL) +#if !defined(CONFIG_SUNXI_PINCTRL) || defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) ID("allwinner,sun50i-a64-r-pinctrl", l_1), #endif { } diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4640cee..445707e 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -14,7 +14,9 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/gpio.h> +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) #include <asm/arch/gpio-internal.h> +#endif #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/pinctrl.h> @@ -27,7 +29,7 @@ DECLARE_GLOBAL_DATA_PTR; struct sunxi_pctrl_priv { void *base; -#if defined(CONFIG_DM_GPIO) +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) struct sunxi_gpio_soc_data gpio_soc_data; struct udevice *gpio_dev; #endif @@ -217,6 +219,7 @@ static int sunxi_pctrl_set_state(struct udevice *dev, struct udevice *config) return 0; } +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) static inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, struct sunxi_gpio_soc_data *soc_data) { @@ -236,10 +239,11 @@ static inline void soc_data_from_desc(const struct sunxi_pinctrl_desc *data, soc_data->start = low; soc_data->no_banks = high - low + 1; } +#endif static int sunxi_pctrl_bind_gpio(struct udevice *dev) { -#if defined(CONFIG_DM_GPIO) +#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_DM_ALLOW_MULTIPLE_DRIVERS) struct sunxi_pctrl_priv *priv = dev_get_priv(dev); const struct sunxi_pinctrl_desc *data = (struct sunxi_pinctrl_desc *)dev_get_driver_data(dev); -- 1.9.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich ` (2 preceding siblings ...) 2017-02-22 20:47 ` [U-Boot] [PATCH v2 3/6] sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-02-22 23:19 ` Maxime Ripard 2017-02-22 20:47 ` [U-Boot] [PATCH v2 5/6] sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings Philipp Tomsich 5 siblings, 1 reply; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot Now that we have the new functionality to allow multiple drivers to bind for a single node, we want to enable it for the A64-uQ7. Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> --- configs/lynx_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/lynx_defconfig b/configs/lynx_defconfig index 7b773f1..0fba279 100644 --- a/configs/lynx_defconfig +++ b/configs/lynx_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN50I=y +CONFIG_DM_ALLOW_MULTIPLE_DRIVERS=y CONFIG_PINCTRL=y CONFIG_SUNXI_PINCTRL=y CONFIG_CLK=y -- 1.9.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS 2017-02-22 20:47 ` [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS Philipp Tomsich @ 2017-02-22 23:19 ` Maxime Ripard 0 siblings, 0 replies; 19+ messages in thread From: Maxime Ripard @ 2017-02-22 23:19 UTC (permalink / raw) To: u-boot On Wed, Feb 22, 2017 at 09:47:30PM +0100, Philipp Tomsich wrote: > Now that we have the new functionality to allow multiple drivers to > bind for a single node, we want to enable it for the A64-uQ7. > > Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> > --- > configs/lynx_defconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/configs/lynx_defconfig b/configs/lynx_defconfig > index 7b773f1..0fba279 100644 > --- a/configs/lynx_defconfig > +++ b/configs/lynx_defconfig > @@ -2,6 +2,7 @@ CONFIG_ARM=y > CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y > CONFIG_ARCH_SUNXI=y > CONFIG_MACH_SUN50I=y > +CONFIG_DM_ALLOW_MULTIPLE_DRIVERS=y I guess it would be better to just put the default value in Kconfig as MACH_SUN50I or even ARCH_SUNXI to enable it for all the boards Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170222/120eafaa/attachment.sig> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 5/6] sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich ` (3 preceding siblings ...) 2017-02-22 20:47 ` [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings Philipp Tomsich 5 siblings, 0 replies; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot To sync up with use of a pinctrl-driver, this updates the DTS. Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> --- arch/arm/dts/sun50i-a64.dtsi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index 24406d0..54b68e0 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -376,9 +376,9 @@ gpio-controller; #gpio-cells = <3>; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <3>; - uart0_pins_a: uart0 at 0 { + uart0_pins_a: uart0_pins_a { allwinner,pins = "PB8", "PB9"; allwinner,function = "uart0"; allwinner,drive = <SUN4I_PINCTRL_10_MA>; @@ -532,10 +532,9 @@ reg = <0x01f02c00 0x400>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + #gpio-cells = <3>; interrupt-controller; #interrupt-cells = <3>; - #size-cells = <0>; - #gpio-cells = <3>; }; ahb_rst: reset at 1c202c0 { -- 1.9.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich ` (4 preceding siblings ...) 2017-02-22 20:47 ` [U-Boot] [PATCH v2 5/6] sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio Philipp Tomsich @ 2017-02-22 20:47 ` Philipp Tomsich 2017-02-22 23:20 ` Maxime Ripard 5 siblings, 1 reply; 19+ messages in thread From: Philipp Tomsich @ 2017-02-22 20:47 UTC (permalink / raw) To: u-boot 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 | 57 ++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi index 54b68e0..4911d6a 100644 --- a/arch/arm/dts/sun50i-a64.dtsi +++ b/arch/arm/dts/sun50i-a64.dtsi @@ -88,7 +88,7 @@ method = "smc"; }; - memory { + memory: memory at 40000000 { device_type = "memory"; reg = <0x40000000 0>; }; @@ -378,84 +378,84 @@ interrupt-controller; #interrupt-cells = <3>; - uart0_pins_a: uart0_pins_a { + 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 0 { + mmc0_pins: mmc0-pins { allwinner,pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; allwinner,function = "mmc0"; @@ -463,14 +463,14 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; - mmc0_default_cd_pin: mmc0_cd_pin at 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 at 0 { + mmc1_pins: mmc1-pins { allwinner,pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; allwinner,function = "mmc1"; @@ -478,36 +478,51 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; - mmc2_pins: mmc2 at 0 { + mmc2_pins: mmc2-pins { allwinner,pins = "PC1", "PC5", "PC6", "PC8", "PC9", "PC10"; allwinner,function = "mmc2"; +<<<<<<< HEAD allwinner,drive = <SUN4I_PINCTRL_30_MA>; allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; +======= + drive-strength = < 30 >; + bias-pull-up; }; - i2c0_pins: i2c0_pins { + 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; +>>>>>>> 20221b3... [f] dts warnings + }; + + 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 { + 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 { + 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 { + rmii_pins: rmii-pins { allwinner,pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; @@ -516,7 +531,7 @@ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; }; - rgmii_pins: rgmii_pins { + rgmii_pins: rgmii-pins { allwinner,pins = "PD8", "PD9", "PD10", "PD11", "PD12", "PD13", "PD15", "PD16", "PD17", "PD18", "PD19", -- 1.9.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings 2017-02-22 20:47 ` [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings Philipp Tomsich @ 2017-02-22 23:20 ` Maxime Ripard 2017-02-22 23:24 ` Dr. Philipp Tomsich 0 siblings, 1 reply; 19+ messages in thread From: Maxime Ripard @ 2017-02-22 23:20 UTC (permalink / raw) To: u-boot On Wed, Feb 22, 2017 at 09:47:32PM +0100, Philipp Tomsich wrote: > +<<<<<<< HEAD > allwinner,drive = <SUN4I_PINCTRL_30_MA>; > allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; > +======= > + drive-strength = < 30 >; > + bias-pull-up; > }; > > - i2c0_pins: i2c0_pins { > + 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; > +>>>>>>> 20221b3... [f] dts warnings Hmmm, are you sure about those ? :) -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170222/18160e36/attachment.sig> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings 2017-02-22 23:20 ` Maxime Ripard @ 2017-02-22 23:24 ` Dr. Philipp Tomsich 0 siblings, 0 replies; 19+ messages in thread From: Dr. Philipp Tomsich @ 2017-02-22 23:24 UTC (permalink / raw) To: u-boot > On 23 Feb 2017, at 00:20, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > > On Wed, Feb 22, 2017 at 09:47:32PM +0100, Philipp Tomsich wrote: >> +<<<<<<< HEAD >> allwinner,drive = <SUN4I_PINCTRL_30_MA>; >> allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; >> +======= >> + drive-strength = < 30 >; >> + bias-pull-up; >> }; >> >> - i2c0_pins: i2c0_pins { >> + 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; >> +>>>>>>> 20221b3... [f] dts warnings > > Hmmm, are you sure about those ? :) I can?t believe this slipped through. I think I need more sleep. At least the patch-format wasn?t such a mess this time around? Cheers, Philipp. ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2017-03-22 13:05 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-02-22 20:47 [U-Boot] [PATCH v2 0/6] sunxi: DM pinctrl implementation Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 1/6] sunxi: add pinctrl (UCLASS_PINCTRL) support for sunxi Philipp Tomsich 2017-02-22 23:18 ` Maxime Ripard 2017-02-23 3:54 ` Chen-Yu Tsai 2017-02-23 18:10 ` Maxime Ripard 2017-02-22 20:47 ` [U-Boot] [PATCH v2 2/6] dm: core: Allow multiple drivers to bind for a single node Philipp Tomsich 2017-03-03 4:52 ` Simon Glass 2017-03-03 10:52 ` Dr. Philipp Tomsich 2017-03-12 20:21 ` Simon Glass 2017-03-13 8:40 ` Heiko Stübner 2017-03-20 7:08 ` Maxime Ripard 2017-03-22 13:05 ` Simon Glass 2017-02-22 20:47 ` [U-Boot] [PATCH v2 3/6] sunxi: CONFIG_DM_ALLOW_MULTIPLE_DRIVERS for gpio/pinctrl binding Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 4/6] defconfig: lynx: enable CONFIG_DM_ALLOW_MULTIPLE_DRIVERS Philipp Tomsich 2017-02-22 23:19 ` Maxime Ripard 2017-02-22 20:47 ` [U-Boot] [PATCH v2 5/6] sun50i: dts: add r_pio node and pinconfig entries into r_pio and pio Philipp Tomsich 2017-02-22 20:47 ` [U-Boot] [PATCH v2 6/6] sun50i: dts: update DTS to avoid warnings Philipp Tomsich 2017-02-22 23:20 ` Maxime Ripard 2017-02-22 23:24 ` Dr. Philipp Tomsich
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox