Browse Source

Merge branch '2020-10-08-misc-board-improvements'

- Move ASPEED ram driver, update.
- Exhance pinctrl/gpio support, update Kendryte K210 support
- Enhance qemu_arm64 support for a single binary to work with and
  without TF-A
Tom Rini 3 years ago
parent
commit
0570938e3c

+ 8 - 0
Kconfig

@@ -422,6 +422,14 @@ config SYS_SRAM_SIZE
 	default 0x10000 if TARGET_TRICORDER
 	default 0x0
 
+config EXAMPLES
+	bool "Compile API examples"
+	depends on !SANDBOX
+	default y if ARCH_QEMU
+	help
+	  U-Boot provides an API for standalone applications. Examples are
+	  provided in directory examples/.
+
 endmenu		# General setup
 
 menu "Boot images"

+ 3 - 0
MAINTAINERS

@@ -935,7 +935,9 @@ RISC-V KENDRYTE
 M:	Sean Anderson <seanga2@gmail.com>
 S:	Maintained
 F:	doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
+F:	doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
 F:	drivers/clk/kendryte/
+F:	drivers/pinctrl/kendryte/
 F:	include/kendryte/
 
 RNG
@@ -960,6 +962,7 @@ M:	Simon Glass <sjg@chromium.org>
 S:	Maintained
 F:	arch/sandbox/
 F:	doc/arch/sandbox.rst
+F:	include/dt-bindings/*/sandbox*.h
 
 SH
 M:	Marek Vasut <marek.vasut+renesas@gmail.com>

+ 10 - 5
arch/arm/Kconfig

@@ -12,7 +12,6 @@ config ARM64
 if ARM64
 config POSITION_INDEPENDENT
 	bool "Generate position-independent pre-relocation code"
-	select INIT_SP_RELATIVE
 	help
 	  U-Boot expects to be linked to a specific hard-coded address, and to
 	  be loaded to and run from that address. This option lifts that
@@ -23,6 +22,8 @@ config POSITION_INDEPENDENT
 
 config INIT_SP_RELATIVE
 	bool "Specify the early stack pointer relative to the .bss section"
+	default n if ARCH_QEMU
+	default y if POSITION_INDEPENDENT
 	help
 	  U-Boot typically uses a hard-coded value for the stack pointer
 	  before relocation. Enable this option to instead calculate the
@@ -76,7 +77,7 @@ config GIC_V3_ITS
 
 config STATIC_RELA
 	bool
-	default y if ARM64 && !POSITION_INDEPENDENT
+	default y if ARM64
 
 config DMA_ADDR_T_64BIT
 	bool
@@ -932,7 +933,6 @@ config ARCH_OWL
 
 config ARCH_QEMU
 	bool "QEMU Virtual Platform"
-	select ARCH_SUPPORT_TFABOOT
 	select DM
 	select DM_SERIAL
 	select OF_CONTROL
@@ -1801,8 +1801,13 @@ config TFABOOT
 	depends on ARCH_SUPPORT_TFABOOT
 	default n
 	help
-	  Enabling this will make a U-Boot binary that is capable of being
-	  booted via TF-A (Trusted Firmware for Cortex-A).
+	  Some platforms support the setup of secure registers (for instance
+	  for CPU errata handling) or provide secure services like PSCI.
+	  Those services could also be provided by other firmware parts
+	  like TF-A (Trusted Firmware for Cortex-A), in which case U-Boot
+	  does not need to (and cannot) execute this code.
+	  Enabling this option will make a U-Boot binary that is relying
+	  on other firmware layers to provide secure functionality.
 
 config TI_SECURE_DEVICE
 	bool "HS Device Type Support"

+ 2 - 1
arch/arm/cpu/armv8/start.S

@@ -83,7 +83,8 @@ save_boot_params_ret:
 pie_fixup:
 	adr	x0, _start		/* x0 <- Runtime value of _start */
 	ldr	x1, _TEXT_BASE		/* x1 <- Linked value of _start */
-	sub	x9, x0, x1		/* x9 <- Run-vs-link offset */
+	subs	x9, x0, x1		/* x9 <- Run-vs-link offset */
+	beq	pie_fixup_done
 	adrp    x2, __rel_dyn_start     /* x2 <- Runtime &__rel_dyn_start */
 	add     x2, x2, #:lo12:__rel_dyn_start
 	adrp    x3, __rel_dyn_end       /* x3 <- Runtime &__rel_dyn_end */

+ 1 - 1
arch/arm/mach-aspeed/ast2500/Makefile

@@ -1,3 +1,3 @@
 obj-y += lowlevel_init.o
 obj-y += board_common.o
-obj-y += clk_ast2500.o sdram_ast2500.o
+obj-y += clk_ast2500.o

+ 115 - 0
arch/riscv/dts/k210-maix-bit.dts

@@ -8,6 +8,7 @@
 #include "k210.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
 	model = "Sipeed Maix Bit 2.0";
@@ -17,6 +18,32 @@
 		stdout-path = "serial0:115200";
 	};
 
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		green {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		blue {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
 	sound {
 		compatible = "simple-audio-card";
 		simple-audio-card,format = "i2s";
@@ -39,9 +66,97 @@
 };
 
 &uarths0 {
+	pinctrl-0 = <&fpioa_uarths>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&fpioa_gpiohs>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&fpioa_gpio>;
+	pinctrl-names = "default";
 	status = "okay";
 };
 
 &i2s0 {
 	#sound-dai-cells = <1>;
+	pinctrl-0 = <&fpioa_i2s0>;
+	pinctrl-names = "default";
+};
+
+&fpioa {
+	status = "okay";
+
+	fpioa_uarths: uarths {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	fpioa_gpio: gpio {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>,
+			 <K210_FPIOA(10, K210_PCF_GPIO2)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	fpioa_gpiohs: gpiohs {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(30, K210_PCF_GPIOHS14)>,
+			 <K210_FPIOA(31, K210_PCF_GPIOHS15)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	fpioa_i2s0: i2s0 {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	fpioa_dvp: dvp {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	fpioa_spi0: spi0 {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	fpioa_spi1: spi1 {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>;
+	};
+};
+
+&dvp0 {
+	pinctrl-0 = <&fpioa_dvp>;
+	pinctrl-names = "default";
 };

+ 12 - 0
arch/riscv/dts/k210.dtsi

@@ -5,6 +5,7 @@
 
 #include <dt-bindings/clock/k210-sysctl.h>
 #include <dt-bindings/mfd/k210-sysctl.h>
+#include <dt-bindings/pinctrl/k210-pinctrl.h>
 #include <dt-bindings/reset/k210-sysctl.h>
 
 / {
@@ -368,7 +369,18 @@
 				reg = <0x502B0000 0x100>;
 				clocks = <&sysclk K210_CLK_FPIOA>;
 				resets = <&sysrst K210_RST_FPIOA>;
+				kendryte,sysctl = <&sysctl>;
+				kendryte,power-offset = <K210_SYSCTL_POWER_SEL>;
+				pinctrl-0 = <&fpioa_jtag>;
+				pinctrl-names = "default";
 				status = "disabled";
+
+				fpioa_jtag: jtag {
+					pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+						 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+						 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+						 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+				};
 			};
 
 			sha256: sha256@502C0000 {

+ 39 - 8
arch/sandbox/dts/test.dts

@@ -2,6 +2,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/sandbox-gpio.h>
+#include <dt-bindings/pinctrl/sandbox-pinmux.h>
 
 / {
 	model = "sandbox";
@@ -558,7 +559,7 @@
 
 		default_off {
 			gpios = <&gpio_a 6 0>;
-			label = "sandbox:default_off";
+			/* label intentionally omitted */
 			default-state = "off";
 		};
 	};
@@ -1094,30 +1095,60 @@
 	pinctrl {
 		compatible = "sandbox,pinctrl";
 
-		pinctrl-names = "default";
-		pinctrl-0 = <&gpios>;
+		pinctrl-names = "default", "alternate";
+		pinctrl-0 = <&pinctrl_gpios>, <&pinctrl_i2s>;
+		pinctrl-1 = <&pinctrl_spi>, <&pinctrl_i2c>;
 
-		gpios: gpios {
+		pinctrl_gpios: gpios {
 			gpio0 {
-				pins = "GPIO0";
+				pins = "P5";
+				function = "GPIO";
 				bias-pull-up;
 				input-disable;
 			};
 			gpio1 {
-				pins = "GPIO1";
+				pins = "P6";
+				function = "GPIO";
 				output-high;
 				drive-open-drain;
 			};
 			gpio2 {
-				pins = "GPIO2";
+				pinmux = <SANDBOX_PINMUX(7, SANDBOX_PINMUX_GPIO)>;
 				bias-pull-down;
 				input-enable;
 			};
 			gpio3 {
-				pins = "GPIO3";
+				pinmux = <SANDBOX_PINMUX(8, SANDBOX_PINMUX_GPIO)>;
 				bias-disable;
 			};
 		};
+
+		pinctrl_i2c: i2c {
+			groups {
+				groups = "I2C_UART";
+				function = "I2C";
+			};
+
+			pins {
+				pins = "P0", "P1";
+				drive-open-drain;
+			};
+		};
+
+		pinctrl_i2s: i2s {
+			groups = "SPI_I2S";
+			function = "I2S";
+		};
+
+		pinctrl_spi: spi {
+			groups = "SPI_I2S";
+			function = "SPI";
+
+			cs {
+				pinmux = <SANDBOX_PINMUX(5, SANDBOX_PINMUX_CS)>,
+					 <SANDBOX_PINMUX(6, SANDBOX_PINMUX_CS)>;
+			};
+		};
 	};
 
 	hwspinlock@0 {

+ 9 - 0
board/sipeed/maix/Kconfig

@@ -44,4 +44,13 @@ config BOARD_SPECIFIC_OPTIONS
 	imply RESET_SYSCON
 	imply SYSRESET
 	imply SYSRESET_SYSCON
+	imply PINCTRL
+	imply PINCONF
+	imply PINCTRL_K210
+	imply DM_GPIO
+	imply DWAPB_GPIO
+	imply SIFIVE_GPIO
+	imply CMD_GPIO
+	imply LED
+	imply LED_GPIO
 endif

+ 1 - 0
configs/qemu_arm64_defconfig

@@ -1,6 +1,7 @@
 CONFIG_ARM=y
 CONFIG_ARCH_QEMU=y
 CONFIG_NR_DRAM_BANKS=1
+CONFIG_POSITION_INDEPENDENT=y
 CONFIG_ENV_SIZE=0x40000
 CONFIG_ENV_SECT_SIZE=0x40000
 CONFIG_AHCI=y

+ 1 - 0
doc/api/index.rst

@@ -9,6 +9,7 @@ U-Boot API documentation
    dfu
    efi
    linker_lists
+   pinctrl
    rng
    serial
    unicode

+ 7 - 0
doc/api/pinctrl.rst

@@ -0,0 +1,7 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Pinctrl and Pinmux
+==================
+
+.. kernel-doc:: include/dm/pinctrl.h
+   :internal:

+ 62 - 2
doc/board/sipeed/maix.rst

@@ -199,7 +199,7 @@ To run legacy images, use the ``bootm`` command:
     Load Address: 80000000
     Entry Point:  80000000
 
-    $ picocom -b 115200 /dev/ttyUSB0i
+    $ picocom -b 115200 /dev/ttyUSB0
     => loady
     ## Ready for binary (ymodem) download to 0x80000000 at 115200 bps...
     C
@@ -230,6 +230,66 @@ To run legacy images, use the ``bootm`` command:
     argv[0] = "<NULL>"
     Hit any key to exit ...
 
+Pin Assignment
+--------------
+
+The K210 contains a Fully Programmable I/O Array (FPIOA), which can remap any of
+its 256 input functions to any any of 48 output pins. The following table has
+the default pin assignments for the BitM.
+
+===== ========== =======
+Pin   Function   Comment
+===== ========== =======
+IO_0  JTAG_TCLK
+IO_1  JTAG_TDI
+IO_2  JTAG_TMS
+IO_3  JTAG_TDO
+IO_4  UARTHS_RX
+IO_5  UARTHS_TX
+IO_6             Not set
+IO_7             Not set
+IO_8  GPIO_0
+IO_9  GPIO_1
+IO_10 GPIO_2
+IO_11 GPIO_3
+IO_12 GPIO_4     Green LED
+IO_13 GPIO_5     Red LED
+IO_14 GPIO_6     Blue LED
+IO_15 GPIO_7
+IO_16 GPIOHS_0   ISP
+IO_17 GPIOHS_1
+IO_18 I2S0_SCLK  MIC CLK
+IO_19 I2S0_WS    MIC WS
+IO_20 I2S0_IN_D0 MIC SD
+IO_21 GPIOHS_5
+IO_22 GPIOHS_6
+IO_23 GPIOHS_7
+IO_24 GPIOHS_8
+IO_25 GPIOHS_9
+IO_26 SPI1_D1    MMC MISO
+IO_27 SPI1_SCLK  MMC CLK
+IO_28 SPI1_D0    MMC MOSI
+IO_29 GPIOHS_13  MMC CS
+IO_30 GPIOHS_14
+IO_31 GPIOHS_15
+IO_32 GPIOHS_16
+IO_33 GPIOHS_17
+IO_34 GPIOHS_18
+IO_35 GPIOHS_19
+IO_36 GPIOHS_20  Panel CS
+IO_37 GPIOHS_21  Panel RST
+IO_38 GPIOHS_22  Panel DC
+IO_39 SPI0_SCK   Panel WR
+IO_40 SCCP_SDA
+IO_41 SCCP_SCLK
+IO_42 DVP_RST
+IO_43 DVP_VSYNC
+IO_44 DVP_PWDN
+IO_45 DVP_HSYNC
+IO_46 DVP_XCLK
+IO_47 DVP_PCLK
+===== ========== =======
+
 Over- and Under-clocking
 ------------------------
 
@@ -408,7 +468,7 @@ Address    Size      Description
 0x8801C000 0x1000    riscv priv spec 1.9 config
 0x8801D000 0x2000    flattened device tree (contains only addresses and
                      interrupts)
-0x8801f000 0x1000    credits
+0x8801F000 0x1000    credits
 ========== ========= ===========
 
 Links

+ 102 - 0
doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt

@@ -0,0 +1,102 @@
+Kendryte K210 FPIOA
+
+This binding describes the Fully-Programmable Input/Output Array (FPIOA) found
+in Kendryte K210 SoCs. Any of the 256 functions can be mapped to any of the 48
+pins.
+
+Required properties:
+- compatible: should be "kendryte,k210-fpioa"
+- reg: address and length of the FPIOA registers
+- kendryte,sysctl: phandle to the "sysctl" register map node
+- kendryte,power-offset: offset in the register map of the power bank control
+  register (in bytes)
+
+Configuration nodes
+
+Pin configuration nodes are documented in pinctrl-bindings.txt
+
+Required properties for pin-configuration nodes or sub-nodes are:
+- groups: list of power groups to which the configuration applies. Valid groups
+  are:
+	A0, A1, A2, B0, B1, B2, C0, C1
+  (either this or "pinmux" must be specified)
+- pinmux: integer array representing pin multiplexing configuration. In addition
+  to the 256 standard functions, each pin can also output the direction
+  indicator (DO) of any function. This signal is high whenever the function
+  would normally drive the output. Helper macros to ease assembling the "pinmux"
+  arguments from the pin and function are provided by the FPIOA header file at:
+  <dt-bindings/pinctrl/k210-pinctrl.h>
+  Integer values in the "pinmux" argument list are assembled as:
+  ((PIN << 16) | (DO << 8) | (FUNC))
+  Valid values for PIN are numbers 0 through 47.
+  Valid values for DO are 0 or 1.
+  Valid values for FUNC are numbers 0 through 255. For a complete list of
+  acceptable functions, consult the FPIOA header file.
+  (either this or "groups" must be specified)
+
+Optional properties for "pinmux" nodes are:
+	bias-disable, bias-pull-down, bias-pull-up, drive-strength,
+	drive-strength-ua, input-enable, input-disable, input-schmitt-enable,
+	input-schmitt-disable, output-low, output-high, output-enable,
+	output-disable, slew-rate, output-polarity-invert, input-polarity-invert
+
+Optional properties for "groups" nodes are:
+	power-source
+
+Notes on specific properties include:
+- bias-pull-up, -down, and -pin-default: The pull strength cannot be configured.
+- drive-strength: There are 8 drive strength settings between 11 and 50 mA.
+- input- and output-polarity-invert: Invert the polarity of either the input or
+  the output, respectively.
+- power-source: Controls the output voltage of a bank of pins. Either
+  K210_PC_POWER_1V8 or K210_PC_POWER_3V3 may be specified.
+- slew-rate: Specifying this property reduces the slew rate.
+
+Example:
+fpioa: pinmux@502B0000 {
+	compatible = "kendryte,k210-fpioa";
+	reg = <0x502B0000 0x100>;
+	kendryte,sysctl = <&sysctl>;
+	kendryte,power-offset = <K210_SYSCTL_POWER_SEL>;
+
+	/* JTAG running at 3.3V and driven at 11 mA */
+	fpioa_jtag: jtag {
+		voltage {
+			group = "A0";
+			power-source = <K210_PC_POWER_3V3>;
+		};
+
+		jtag {
+			pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCK)>,
+				 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+				 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+				 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+			drive-strength = <11>;
+		}
+	};
+
+	/* I2C configured for use with a TCA9800 level shifter */
+	fpioa_i2c: i2c {
+		i2c {
+			pinmux = <K210_FPIOA(6, K210_PCF_I2C0_SCLK)>,
+				 <K210_FPIOA(7, K210_PCF_I2C0_SDA)>;
+		};
+
+		direction {
+			pinmux = <K210_FPIOA_DO(8, K210_PCF_I2C0_SDA)>;
+			output-polarity-invert;
+		};
+	};
+
+	/* UART with an active-high TX status LED */
+	fpioa_uart1: uart1 {
+		uart {
+			pinmux = <K210_FPIOA(9, K210_PCF_UART1_TX)>,
+				 <K210_FPIOA(10, K210_PCF_UART1_RX)>;
+		};
+
+		status {
+			pinmux = <K210_FPIOA_DO(11, K210_PCF_UART1_TX)>;
+		};
+	};
+};

+ 59 - 6
doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt

@@ -119,7 +119,8 @@ For example:
 
 The contents of each of those pin configuration child nodes is defined
 entirely by the binding for the individual pin controller device. There
-exists no common standard for this content.
+exists no common standard for this content. The pinctrl framework only
+provides generic helper bindings that the pin controller driver can use.
 
 The pin configuration nodes need not be direct children of the pin controller
 device; they may be grandchildren, for example. Whether this is legal, and
@@ -156,6 +157,29 @@ state_2_node_a {
 	pins = "mfio29", "mfio30";
 };
 
+For hardware where pin multiplexing configurations have to be specified for
+each single pin the number of required sub-nodes containing "pin" and
+"function" properties can quickly escalate and become hard to write and
+maintain.
+
+For cases like this, the pin controller driver may use the pinmux helper
+property, where the pin identifier is provided with mux configuration settings
+in a pinmux group. A pinmux group consists of the pin identifier and mux
+settings represented as a single integer or an array of integers.
+
+The pinmux property accepts an array of pinmux groups, each of them describing
+a single pin multiplexing configuration.
+
+pincontroller {
+	state_0_node_a {
+		pinmux = <PINMUX_GROUP>, <PINMUX_GROUP>, ...;
+	};
+};
+
+Each individual pin controller driver bindings documentation shall specify
+how pin IDs and pin multiplexing configuration are defined and assembled
+together in a pinmux group.
+
 == Generic pin configuration node content ==
 
 Many data items that are represented in a pin configuration node are common
@@ -168,12 +192,15 @@ structure of the DT nodes that contain these properties.
 Supported generic properties are:
 
 pins			- the list of pins that properties in the node
-			  apply to (either this or "group" has to be
+			  apply to (either this, "group" or "pinmux" has to be
 			  specified)
 group			- the group to apply the properties to, if the driver
 			  supports configuration of whole groups rather than
-			  individual pins (either this or "pins" has to be
-			  specified)
+			  individual pins (either this, "pins" or "pinmux" has
+			  to be specified)
+pinmux			- the list of numeric pin ids and their mux settings
+			  that properties in the node apply to (either this,
+			  "pins" or "groups" have to be specified)
 bias-disable		- disable any pin bias
 bias-high-impedance	- high impedance mode ("third-state", "floating")
 bias-bus-hold		- latch weakly
@@ -184,17 +211,30 @@ drive-push-pull		- drive actively high and low
 drive-open-drain	- drive with open drain
 drive-open-source	- drive with open source
 drive-strength		- sink or source at most X mA
-input-enable		- enable input on pin (no effect on output)
-input-disable		- disable input on pin (no effect on output)
+drive-strength-microamp	- sink or source at most X uA
+input-enable		- enable input on pin (no effect on output, such as
+			  enabling an input buffer)
+input-disable		- disable input on pin (no effect on output, such as
+			  disabling an input buffer)
 input-schmitt-enable	- enable schmitt-trigger mode
 input-schmitt-disable	- disable schmitt-trigger mode
 input-debounce		- debounce mode with debound time X
 power-source		- select between different power supplies
 low-power-enable	- enable low power mode
 low-power-disable	- disable low power mode
+output-disable		- disable output on a pin (such as disable an output
+			  buffer)
+output-enable		- enable output on a pin without actively driving it
+			  (such as enabling an output buffer)
 output-low		- set the pin to output mode with low level
 output-high		- set the pin to output mode with high level
+sleep-hardware-state	- indicate this is sleep related state which will be programmed
+			  into the registers for the sleep state.
 slew-rate		- set the slew rate
+skew-delay		- this affects the expected clock skew on input pins
+			  and the delay before latching a value to an output
+			  pin. Typically indicates how many double-inverters are
+			  used to delay the signal.
 
 For example:
 
@@ -216,6 +256,12 @@ state_2_node_a {
 		bias-pull-up;
 	};
 };
+state_3_node_a {
+	mux {
+		pinmux = <GPIOx_PINm_MUXn>, <GPIOx_PINj_MUXk)>;
+		input-enable;
+	};
+};
 
 Some of the generic properties take arguments. For those that do, the
 arguments are described below.
@@ -224,11 +270,18 @@ arguments are described below.
   binding for the hardware defines:
   - Whether the entries are integers or strings, and their meaning.
 
+- pinmux takes a list of pin IDs and mux settings as required argument. The
+  specific bindings for the hardware defines:
+  - How pin IDs and mux settings are defined and assembled together in a single
+    integer or an array of integers.
+
 - bias-pull-up, -down and -pin-default take as optional argument on hardware
   supporting it the pull strength in Ohm. bias-disable will disable the pull.
 
 - drive-strength takes as argument the target strength in mA.
 
+- drive-strength-microamp takes as argument the target strength in uA.
+
 - input-debounce takes the debounce time in usec as argument
   or 0 to disable debouncing
 

+ 23 - 10
drivers/gpio/dwapb_gpio.c

@@ -40,7 +40,7 @@ struct gpio_dwapb_platdata {
 	const char	*name;
 	int		bank;
 	int		pins;
-	fdt_addr_t	base;
+	void __iomem	*base;
 };
 
 static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin)
@@ -66,13 +66,6 @@ static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin,
 	return 0;
 }
 
-static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin)
-{
-	struct gpio_dwapb_platdata *plat = dev_get_platdata(dev);
-	return !!(readl(plat->base + GPIO_EXT_PORT(plat->bank)) & (1 << pin));
-}
-
-
 static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val)
 {
 	struct gpio_dwapb_platdata *plat = dev_get_platdata(dev);
@@ -98,6 +91,18 @@ static int dwapb_gpio_get_function(struct udevice *dev, unsigned offset)
 		return GPIOF_INPUT;
 }
 
+static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin)
+{
+	struct gpio_dwapb_platdata *plat = dev_get_platdata(dev);
+	u32 value;
+
+	if (dwapb_gpio_get_function(dev, pin) == GPIOF_OUTPUT)
+		value = readl(plat->base + GPIO_SWPORT_DR(plat->bank));
+	else
+		value = readl(plat->base + GPIO_EXT_PORT(plat->bank));
+	return !!(value & BIT(pin));
+}
+
 static const struct dm_gpio_ops gpio_dwapb_ops = {
 	.direction_input	= dwapb_gpio_direction_input,
 	.direction_output	= dwapb_gpio_direction_output,
@@ -176,7 +181,7 @@ static int gpio_dwapb_bind(struct udevice *dev)
 		if (!plat)
 			return -ENOMEM;
 
-		plat->base = base;
+		plat->base = (void *)base;
 		plat->bank = bank;
 		plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0);
 
@@ -186,7 +191,15 @@ static int gpio_dwapb_bind(struct udevice *dev)
 			 * Fall back to node name. This means accessing pins
 			 * via bank name won't work.
 			 */
-			plat->name = ofnode_get_name(node);
+			char name[32];
+
+			snprintf(name, sizeof(name), "%s_",
+				 ofnode_get_name(node));
+			plat->name = strdup(name);
+			if (!plat->name) {
+				kfree(plat);
+				return -ENOMEM;
+			}
 		}
 
 		ret = device_bind_ofnode(dev, dev->driver, plat->name,

+ 2 - 5
drivers/led/led_gpio.c

@@ -99,11 +99,8 @@ static int led_gpio_bind(struct udevice *parent)
 		const char *label;
 
 		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
+		if (!label)
+			label = ofnode_get_name(node);
 		ret = device_bind_driver_to_node(parent, "gpio_led",
 						 ofnode_get_name(node),
 						 node, &dev);

+ 7 - 0
drivers/pinctrl/Kconfig

@@ -291,6 +291,13 @@ config ASPEED_AST2500_PINCTRL
 	  uses Generic Pinctrl framework and is compatible with the Linux
 	  driver, i.e. it uses the same device tree configuration.
 
+config PINCTRL_K210
+	bool "Kendryte K210 Fully-Programmable Input/Output Array driver"
+	depends on DM && PINCTRL_GENERIC
+	help
+	  Support pin multiplexing on the K210. The "FPIOA" can remap any
+	  supported function to any multifunctional IO pin. It can also perform
+	  basic GPIO functions, such as reading the current value of a pin.
 endif
 
 source "drivers/pinctrl/broadcom/Kconfig"

+ 1 - 0
drivers/pinctrl/Makefile

@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
 obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl_pic32.o
 obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
+obj-$(CONFIG_PINCTRL_K210)	+= pinctrl-kendryte.o
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
 obj-$(CONFIG_PINCTRL_MTK)	+= mediatek/
 obj-$(CONFIG_PINCTRL_MSCC)	+= mscc/

+ 97 - 30
drivers/pinctrl/pinctrl-generic.c

@@ -227,6 +227,13 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group,
 }
 #endif
 
+enum pinmux_subnode_type {
+	PST_NONE = 0,
+	PST_PIN,
+	PST_GROUP,
+	PST_PINMUX,
+};
+
 /**
  * pinctrl_generic_set_state_one() - set state for a certain pin/group
  * Apply all pin multiplexing and pin configurations specified by @config
@@ -234,13 +241,15 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group,
  *
  * @dev: pin controller device
  * @config: pseudo device pointing to config node
- * @is_group: target of operation (true: pin group, false: pin)
- * @selector: pin selector or group selector, depending on @is_group
+ * @subnode_type: target of operation (pin, group, or pin specified by a pinmux
+ * group)
+ * @selector: pin selector or group selector, depending on @subnode_type
  * @return: 0 on success, or negative error code on failure
  */
 static int pinctrl_generic_set_state_one(struct udevice *dev,
 					 struct udevice *config,
-					 bool is_group, unsigned selector)
+					 enum pinmux_subnode_type subnode_type,
+					 unsigned selector)
 {
 	const char *propname;
 	const void *value;
@@ -248,17 +257,22 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 	int len, func_selector, param, ret;
 	u32 arg, default_val;
 
+	assert(subnode_type != PST_NONE);
+
 	dev_for_each_property(property, config) {
 		value = dev_read_prop_by_prop(&property, &propname, &len);
 		if (!value)
 			return -EINVAL;
 
-		if (!strcmp(propname, "function")) {
+		/* pinmux subnodes already have their muxing set */
+		if (subnode_type != PST_PINMUX &&
+		    !strcmp(propname, "function")) {
 			func_selector = pinmux_func_name_to_selector(dev,
 								     value);
 			if (func_selector < 0)
 				return func_selector;
-			ret = pinmux_enable_setting(dev, is_group,
+			ret = pinmux_enable_setting(dev,
+						    subnode_type == PST_GROUP,
 						    selector,
 						    func_selector);
 		} else {
@@ -272,7 +286,8 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 			else
 				arg = default_val;
 
-			ret = pinconf_enable_setting(dev, is_group,
+			ret = pinconf_enable_setting(dev,
+						     subnode_type == PST_GROUP,
 						     selector, param, arg);
 		}
 
@@ -283,6 +298,41 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 	return 0;
 }
 
+/**
+ * pinctrl_generic_get_subnode_type() - determine whether there is a valid
+ * pins, groups, or pinmux property in the config node
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @count: number of specifiers contained within the property
+ * @return: the type of the subnode, or PST_NONE
+ */
+static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev,
+								 struct udevice *config,
+								 int *count)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	*count = dev_read_string_count(config, "pins");
+	if (*count >= 0)
+		return PST_PIN;
+
+	*count = dev_read_string_count(config, "groups");
+	if (*count >= 0)
+		return PST_GROUP;
+
+	if (ops->pinmux_property_set) {
+		*count = dev_read_size(config, "pinmux");
+		if (*count >= 0 && !(*count % sizeof(u32))) {
+			*count /= sizeof(u32);
+			return PST_PINMUX;
+		}
+	}
+
+	*count = 0;
+	return PST_NONE;
+}
+
 /**
  * pinctrl_generic_set_state_subnode() - apply all settings in config node
  *
@@ -293,38 +343,55 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 static int pinctrl_generic_set_state_subnode(struct udevice *dev,
 					     struct udevice *config)
 {
-	const char *subnode_target_type = "pins";
-	bool is_group = false;
+	enum pinmux_subnode_type subnode_type;
 	const char *name;
-	int strings_count, selector, i, ret;
-
-	strings_count = dev_read_string_count(config, subnode_target_type);
-	if (strings_count < 0) {
-		subnode_target_type = "groups";
-		is_group = true;
-		strings_count = dev_read_string_count(config,
-						      subnode_target_type);
-		if (strings_count < 0) {
+	int count, selector, i, ret, scratch;
+	const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */
+
+	subnode_type = pinctrl_generic_get_subnode_type(dev, config, &count);
+
+	debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name,
+	      count);
+
+	if (subnode_type == PST_PINMUX) {
+		pinmux_groups = dev_read_prop(config, "pinmux", &scratch);
+		if (!pinmux_groups)
+			return -EINVAL;
+	}
+
+	for (i = 0; i < count; i++) {
+		switch (subnode_type) {
+		case PST_PIN:
+			ret = dev_read_string_index(config, "pins", i, &name);
+			if (ret)
+				return ret;
+			selector = pinctrl_pin_name_to_selector(dev, name);
+			break;
+		case PST_GROUP:
+			ret = dev_read_string_index(config, "groups", i, &name);
+			if (ret)
+				return ret;
+			selector = pinctrl_group_name_to_selector(dev, name);
+			break;
+		case PST_PINMUX: {
+			const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+			u32 pinmux_group = fdt32_to_cpu(pinmux_groups[i]);
+
+			/* Checked for in pinctrl_generic_get_subnode_type */
+			selector = ops->pinmux_property_set(dev, pinmux_group);
+			break;
+		}
+		case PST_NONE:
+		default:
 			/* skip this node; may contain config child nodes */
 			return 0;
 		}
-	}
-
-	for (i = 0; i < strings_count; i++) {
-		ret = dev_read_string_index(config, subnode_target_type, i,
-					    &name);
-		if (ret)
-			return ret;
 
-		if (is_group)
-			selector = pinctrl_group_name_to_selector(dev, name);
-		else
-			selector = pinctrl_pin_name_to_selector(dev, name);
 		if (selector < 0)
 			return selector;
 
-		ret = pinctrl_generic_set_state_one(dev, config,
-						    is_group, selector);
+		ret = pinctrl_generic_set_state_one(dev, config, subnode_type,
+						    selector);
 		if (ret)
 			return ret;
 	}

+ 737 - 0
drivers/pinctrl/pinctrl-kendryte.c

@@ -0,0 +1,737 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/k210-pinctrl.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+
+/*
+ * The K210 only implements 8 drive levels, even though there is register space
+ * for 16
+ */
+#define K210_PC_DRIVE_MASK GENMASK(11, 8)
+#define K210_PC_DRIVE_SHIFT 8
+#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_MAX 7
+
+#define K210_PC_MODE_MASK GENMASK(23, 12)
+/*
+ * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) where FUNCTION_OE is a
+ * physical signal from the function
+ */
+#define K210_PC_OE       BIT(12) /* Output Enable */
+#define K210_PC_OE_INV   BIT(13) /* INVert function-controlled Output Enable */
+#define K210_PC_DO_OE    BIT(14) /* set Data Out to the Output Enable signal */
+#define K210_PC_DO_INV   BIT(15) /* INVert final Data Output */
+#define K210_PC_PU       BIT(16) /* Pull Up */
+#define K210_PC_PD       BIT(17) /* Pull Down */
+/* Strong pull up not implemented on K210 */
+#define K210_PC_SL       BIT(19) /* reduce SLew rate to prevent overshoot */
+/* Same semantics as OE above */
+#define K210_PC_IE       BIT(20) /* Input Enable */
+#define K210_PC_IE_INV   BIT(21) /* INVert function-controlled Input Enable */
+#define K210_PC_DI_INV   BIT(22) /* INVert Data Input */
+#define K210_PC_ST       BIT(23) /* Schmitt Trigger */
+#define K210_PC_DI       BIT(31) /* raw Data Input */
+#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD)
+
+#define K210_PC_MODE_IN   (K210_PC_IE | K210_PC_ST)
+#define K210_PC_MODE_OUT  (K210_PC_DRIVE_7 | K210_PC_OE)
+#define K210_PC_MODE_I2C  (K210_PC_MODE_IN | K210_PC_IE_INV | K210_PC_SL | \
+			   K210_PC_OE | K210_PC_OE_INV | K210_PC_PU)
+#define K210_PC_MODE_SPI  (K210_PC_MODE_IN | K210_PC_IE_INV | \
+			   K210_PC_MODE_OUT | K210_PC_OE_INV)
+#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT)
+
+#define K210_PG_FUNC GENMASK(7, 0)
+#define K210_PG_DO BIT(8)
+#define K210_PG_PIN GENMASK(22, 16)
+
+#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1)
+#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2)
+
+struct k210_fpioa {
+	u32 pins[48];
+	u32 tie_en[8];
+	u32 tie_val[8];
+};
+
+struct k210_pc_priv {
+	struct clk clk;
+	struct k210_fpioa __iomem *fpioa; /* FPIOA register */
+	struct regmap *sysctl; /* Sysctl regmap */
+	u32 power_offset; /* Power bank register offset */
+};
+
+#ifdef CONFIG_CMD_PINMUX
+static const char k210_pc_pin_names[][6] = {
+#define PIN(i) \
+	[i] = "IO_" #i
+	PIN(0),
+	PIN(1),
+	PIN(2),
+	PIN(3),
+	PIN(4),
+	PIN(5),
+	PIN(6),
+	PIN(7),
+	PIN(8),
+	PIN(9),
+	PIN(10),
+	PIN(11),
+	PIN(12),
+	PIN(13),
+	PIN(14),
+	PIN(15),
+	PIN(16),
+	PIN(17),
+	PIN(18),
+	PIN(19),
+	PIN(20),
+	PIN(21),
+	PIN(22),
+	PIN(23),
+	PIN(24),
+	PIN(25),
+	PIN(26),
+	PIN(27),
+	PIN(28),
+	PIN(29),
+	PIN(30),
+	PIN(31),
+	PIN(32),
+	PIN(33),
+	PIN(34),
+	PIN(35),
+	PIN(36),
+	PIN(37),
+	PIN(38),
+	PIN(39),
+	PIN(40),
+	PIN(41),
+	PIN(42),
+	PIN(43),
+	PIN(44),
+	PIN(45),
+	PIN(46),
+	PIN(47),
+#undef PIN
+};
+
+static int k210_pc_get_pins_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(k210_pc_pin_names);
+};
+
+static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector)
+{
+	return k210_pc_pin_names[selector];
+}
+#endif /* CONFIG_CMD_PINMUX */
+
+/* These are just power domains */
+static const char k210_pc_group_names[][3] = {
+	[0] = "A0",
+	[1] = "A1",
+	[2] = "A2",
+	[3] = "B0",
+	[4] = "B1",
+	[5] = "B2",
+	[6] = "C0",
+	[7] = "C1",
+};
+
+static int k210_pc_get_groups_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(k210_pc_group_names);
+}
+
+static const char *k210_pc_get_group_name(struct udevice *dev,
+					  unsigned selector)
+{
+	return k210_pc_group_names[selector];
+}
+
+enum k210_pc_mode_id {
+	K210_PC_DEFAULT_DISABLED,
+	K210_PC_DEFAULT_IN,
+	K210_PC_DEFAULT_IN_TIE,
+	K210_PC_DEFAULT_OUT,
+	K210_PC_DEFAULT_I2C,
+	K210_PC_DEFAULT_SPI,
+	K210_PC_DEFAULT_GPIO,
+	K210_PC_DEFAULT_INT13,
+};
+
+static const u32 k210_pc_mode_id_to_mode[] = {
+#define DEFAULT(mode) \
+	[K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
+	[K210_PC_DEFAULT_DISABLED] = 0,
+	DEFAULT(IN),
+	[K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
+	DEFAULT(OUT),
+	DEFAULT(I2C),
+	DEFAULT(SPI),
+	DEFAULT(GPIO),
+	[K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
+#undef DEFAULT
+};
+
+/* This saves around 2K vs having a pointer+mode */
+struct k210_pcf_info {
+#ifdef CONFIG_CMD_PINMUX
+	char name[15];
+#endif
+	u8 mode_id;
+};
+
+static const struct k210_pcf_info k210_pcf_infos[] = {
+#ifdef CONFIG_CMD_PINMUX
+#define FUNC(id, mode) \
+	[K210_PCF_##id] = { \
+		.name = #id, \
+		.mode_id = K210_PC_DEFAULT_##mode \
+	}
+#else
+#define FUNC(id, mode) \
+	[K210_PCF_##id] = { \
+		.mode_id = K210_PC_DEFAULT_##mode \
+	}
+#endif
+	FUNC(JTAG_TCLK,      IN),
+	FUNC(JTAG_TDI,       IN),
+	FUNC(JTAG_TMS,       IN),
+	FUNC(JTAG_TDO,       OUT),
+	FUNC(SPI0_D0,        SPI),
+	FUNC(SPI0_D1,        SPI),
+	FUNC(SPI0_D2,        SPI),
+	FUNC(SPI0_D3,        SPI),
+	FUNC(SPI0_D4,        SPI),
+	FUNC(SPI0_D5,        SPI),
+	FUNC(SPI0_D6,        SPI),
+	FUNC(SPI0_D7,        SPI),
+	FUNC(SPI0_SS0,       OUT),
+	FUNC(SPI0_SS1,       OUT),
+	FUNC(SPI0_SS2,       OUT),
+	FUNC(SPI0_SS3,       OUT),
+	FUNC(SPI0_ARB,       IN_TIE),
+	FUNC(SPI0_SCLK,      OUT),
+	FUNC(UARTHS_RX,      IN),
+	FUNC(UARTHS_TX,      OUT),
+	FUNC(RESV6,          IN),
+	FUNC(RESV7,          IN),
+	FUNC(CLK_SPI1,       OUT),
+	FUNC(CLK_I2C1,       OUT),
+	FUNC(GPIOHS0,        GPIO),
+	FUNC(GPIOHS1,        GPIO),
+	FUNC(GPIOHS2,        GPIO),
+	FUNC(GPIOHS3,        GPIO),
+	FUNC(GPIOHS4,        GPIO),
+	FUNC(GPIOHS5,        GPIO),
+	FUNC(GPIOHS6,        GPIO),
+	FUNC(GPIOHS7,        GPIO),
+	FUNC(GPIOHS8,        GPIO),
+	FUNC(GPIOHS9,        GPIO),
+	FUNC(GPIOHS10,       GPIO),
+	FUNC(GPIOHS11,       GPIO),
+	FUNC(GPIOHS12,       GPIO),
+	FUNC(GPIOHS13,       GPIO),
+	FUNC(GPIOHS14,       GPIO),
+	FUNC(GPIOHS15,       GPIO),
+	FUNC(GPIOHS16,       GPIO),
+	FUNC(GPIOHS17,       GPIO),
+	FUNC(GPIOHS18,       GPIO),
+	FUNC(GPIOHS19,       GPIO),
+	FUNC(GPIOHS20,       GPIO),
+	FUNC(GPIOHS21,       GPIO),
+	FUNC(GPIOHS22,       GPIO),
+	FUNC(GPIOHS23,       GPIO),
+	FUNC(GPIOHS24,       GPIO),
+	FUNC(GPIOHS25,       GPIO),
+	FUNC(GPIOHS26,       GPIO),
+	FUNC(GPIOHS27,       GPIO),
+	FUNC(GPIOHS28,       GPIO),
+	FUNC(GPIOHS29,       GPIO),
+	FUNC(GPIOHS30,       GPIO),
+	FUNC(GPIOHS31,       GPIO),
+	FUNC(GPIO0,          GPIO),
+	FUNC(GPIO1,          GPIO),
+	FUNC(GPIO2,          GPIO),
+	FUNC(GPIO3,          GPIO),
+	FUNC(GPIO4,          GPIO),
+	FUNC(GPIO5,          GPIO),
+	FUNC(GPIO6,          GPIO),
+	FUNC(GPIO7,          GPIO),
+	FUNC(UART1_RX,       IN),
+	FUNC(UART1_TX,       OUT),
+	FUNC(UART2_RX,       IN),
+	FUNC(UART2_TX,       OUT),
+	FUNC(UART3_RX,       IN),
+	FUNC(UART3_TX,       OUT),
+	FUNC(SPI1_D0,        SPI),
+	FUNC(SPI1_D1,        SPI),
+	FUNC(SPI1_D2,        SPI),
+	FUNC(SPI1_D3,        SPI),
+	FUNC(SPI1_D4,        SPI),
+	FUNC(SPI1_D5,        SPI),
+	FUNC(SPI1_D6,        SPI),
+	FUNC(SPI1_D7,        SPI),
+	FUNC(SPI1_SS0,       OUT),
+	FUNC(SPI1_SS1,       OUT),
+	FUNC(SPI1_SS2,       OUT),
+	FUNC(SPI1_SS3,       OUT),
+	FUNC(SPI1_ARB,       IN_TIE),
+	FUNC(SPI1_SCLK,      OUT),
+	FUNC(SPI2_D0,        SPI),
+	FUNC(SPI2_SS,        IN),
+	FUNC(SPI2_SCLK,      IN),
+	FUNC(I2S0_MCLK,      OUT),
+	FUNC(I2S0_SCLK,      OUT),
+	FUNC(I2S0_WS,        OUT),
+	FUNC(I2S0_IN_D0,     IN),
+	FUNC(I2S0_IN_D1,     IN),
+	FUNC(I2S0_IN_D2,     IN),
+	FUNC(I2S0_IN_D3,     IN),
+	FUNC(I2S0_OUT_D0,    OUT),
+	FUNC(I2S0_OUT_D1,    OUT),
+	FUNC(I2S0_OUT_D2,    OUT),
+	FUNC(I2S0_OUT_D3,    OUT),
+	FUNC(I2S1_MCLK,      OUT),
+	FUNC(I2S1_SCLK,      OUT),
+	FUNC(I2S1_WS,        OUT),
+	FUNC(I2S1_IN_D0,     IN),
+	FUNC(I2S1_IN_D1,     IN),
+	FUNC(I2S1_IN_D2,     IN),
+	FUNC(I2S1_IN_D3,     IN),
+	FUNC(I2S1_OUT_D0,    OUT),
+	FUNC(I2S1_OUT_D1,    OUT),
+	FUNC(I2S1_OUT_D2,    OUT),
+	FUNC(I2S1_OUT_D3,    OUT),
+	FUNC(I2S2_MCLK,      OUT),
+	FUNC(I2S2_SCLK,      OUT),
+	FUNC(I2S2_WS,        OUT),
+	FUNC(I2S2_IN_D0,     IN),
+	FUNC(I2S2_IN_D1,     IN),
+	FUNC(I2S2_IN_D2,     IN),
+	FUNC(I2S2_IN_D3,     IN),
+	FUNC(I2S2_OUT_D0,    OUT),
+	FUNC(I2S2_OUT_D1,    OUT),
+	FUNC(I2S2_OUT_D2,    OUT),
+	FUNC(I2S2_OUT_D3,    OUT),
+	FUNC(RESV0,          DISABLED),
+	FUNC(RESV1,          DISABLED),
+	FUNC(RESV2,          DISABLED),
+	FUNC(RESV3,          DISABLED),
+	FUNC(RESV4,          DISABLED),
+	FUNC(RESV5,          DISABLED),
+	FUNC(I2C0_SCLK,      I2C),
+	FUNC(I2C0_SDA,       I2C),
+	FUNC(I2C1_SCLK,      I2C),
+	FUNC(I2C1_SDA,       I2C),
+	FUNC(I2C2_SCLK,      I2C),
+	FUNC(I2C2_SDA,       I2C),
+	FUNC(DVP_XCLK,       OUT),
+	FUNC(DVP_RST,        OUT),
+	FUNC(DVP_PWDN,       OUT),
+	FUNC(DVP_VSYNC,      IN),
+	FUNC(DVP_HSYNC,      IN),
+	FUNC(DVP_PCLK,       IN),
+	FUNC(DVP_D0,         IN),
+	FUNC(DVP_D1,         IN),
+	FUNC(DVP_D2,         IN),
+	FUNC(DVP_D3,         IN),
+	FUNC(DVP_D4,         IN),
+	FUNC(DVP_D5,         IN),
+	FUNC(DVP_D6,         IN),
+	FUNC(DVP_D7,         IN),
+	FUNC(SCCB_SCLK,      I2C),
+	FUNC(SCCB_SDA,       I2C),
+	FUNC(UART1_CTS,      IN),
+	FUNC(UART1_DSR,      IN),
+	FUNC(UART1_DCD,      IN),
+	FUNC(UART1_RI,       IN),
+	FUNC(UART1_SIR_IN,   IN),
+	FUNC(UART1_DTR,      OUT),
+	FUNC(UART1_RTS,      OUT),
+	FUNC(UART1_OUT2,     OUT),
+	FUNC(UART1_OUT1,     OUT),
+	FUNC(UART1_SIR_OUT,  OUT),
+	FUNC(UART1_BAUD,     OUT),
+	FUNC(UART1_RE,       OUT),
+	FUNC(UART1_DE,       OUT),
+	FUNC(UART1_RS485_EN, OUT),
+	FUNC(UART2_CTS,      IN),
+	FUNC(UART2_DSR,      IN),
+	FUNC(UART2_DCD,      IN),
+	FUNC(UART2_RI,       IN),
+	FUNC(UART2_SIR_IN,   IN),
+	FUNC(UART2_DTR,      OUT),
+	FUNC(UART2_RTS,      OUT),
+	FUNC(UART2_OUT2,     OUT),
+	FUNC(UART2_OUT1,     OUT),
+	FUNC(UART2_SIR_OUT,  OUT),
+	FUNC(UART2_BAUD,     OUT),
+	FUNC(UART2_RE,       OUT),
+	FUNC(UART2_DE,       OUT),
+	FUNC(UART2_RS485_EN, OUT),
+	FUNC(UART3_CTS,      IN),
+	FUNC(UART3_DSR,      IN),
+	FUNC(UART3_DCD,      IN),
+	FUNC(UART3_RI,       IN),
+	FUNC(UART3_SIR_IN,   IN),
+	FUNC(UART3_DTR,      OUT),
+	FUNC(UART3_RTS,      OUT),
+	FUNC(UART3_OUT2,     OUT),
+	FUNC(UART3_OUT1,     OUT),
+	FUNC(UART3_SIR_OUT,  OUT),
+	FUNC(UART3_BAUD,     OUT),
+	FUNC(UART3_RE,       OUT),
+	FUNC(UART3_DE,       OUT),
+	FUNC(UART3_RS485_EN, OUT),
+	FUNC(TIMER0_TOGGLE1, OUT),
+	FUNC(TIMER0_TOGGLE2, OUT),
+	FUNC(TIMER0_TOGGLE3, OUT),
+	FUNC(TIMER0_TOGGLE4, OUT),
+	FUNC(TIMER1_TOGGLE1, OUT),
+	FUNC(TIMER1_TOGGLE2, OUT),
+	FUNC(TIMER1_TOGGLE3, OUT),
+	FUNC(TIMER1_TOGGLE4, OUT),
+	FUNC(TIMER2_TOGGLE1, OUT),
+	FUNC(TIMER2_TOGGLE2, OUT),
+	FUNC(TIMER2_TOGGLE3, OUT),
+	FUNC(TIMER2_TOGGLE4, OUT),
+	FUNC(CLK_SPI2,       OUT),
+	FUNC(CLK_I2C2,       OUT),
+	FUNC(INTERNAL0,      OUT),
+	FUNC(INTERNAL1,      OUT),
+	FUNC(INTERNAL2,      OUT),
+	FUNC(INTERNAL3,      OUT),
+	FUNC(INTERNAL4,      OUT),
+	FUNC(INTERNAL5,      OUT),
+	FUNC(INTERNAL6,      OUT),
+	FUNC(INTERNAL7,      OUT),
+	FUNC(INTERNAL8,      OUT),
+	FUNC(INTERNAL9,      IN),
+	FUNC(INTERNAL10,     IN),
+	FUNC(INTERNAL11,     IN),
+	FUNC(INTERNAL12,     IN),
+	FUNC(INTERNAL13,     INT13),
+	FUNC(INTERNAL14,     I2C),
+	FUNC(INTERNAL15,     IN),
+	FUNC(INTERNAL16,     IN),
+	FUNC(INTERNAL17,     IN),
+	FUNC(CONSTANT,       DISABLED),
+	FUNC(INTERNAL18,     IN),
+	FUNC(DEBUG0,         OUT),
+	FUNC(DEBUG1,         OUT),
+	FUNC(DEBUG2,         OUT),
+	FUNC(DEBUG3,         OUT),
+	FUNC(DEBUG4,         OUT),
+	FUNC(DEBUG5,         OUT),
+	FUNC(DEBUG6,         OUT),
+	FUNC(DEBUG7,         OUT),
+	FUNC(DEBUG8,         OUT),
+	FUNC(DEBUG9,         OUT),
+	FUNC(DEBUG10,        OUT),
+	FUNC(DEBUG11,        OUT),
+	FUNC(DEBUG12,        OUT),
+	FUNC(DEBUG13,        OUT),
+	FUNC(DEBUG14,        OUT),
+	FUNC(DEBUG15,        OUT),
+	FUNC(DEBUG16,        OUT),
+	FUNC(DEBUG17,        OUT),
+	FUNC(DEBUG18,        OUT),
+	FUNC(DEBUG19,        OUT),
+	FUNC(DEBUG20,        OUT),
+	FUNC(DEBUG21,        OUT),
+	FUNC(DEBUG22,        OUT),
+	FUNC(DEBUG23,        OUT),
+	FUNC(DEBUG24,        OUT),
+	FUNC(DEBUG25,        OUT),
+	FUNC(DEBUG26,        OUT),
+	FUNC(DEBUG27,        OUT),
+	FUNC(DEBUG28,        OUT),
+	FUNC(DEBUG29,        OUT),
+	FUNC(DEBUG30,        OUT),
+	FUNC(DEBUG31,        OUT),
+#undef FUNC
+};
+
+static int k210_pc_pinmux_set(struct udevice *dev, u32 pinmux_group)
+{
+	unsigned pin = FIELD_GET(K210_PG_PIN, pinmux_group);
+	bool do_oe = FIELD_GET(K210_PG_DO, pinmux_group);
+	unsigned func = FIELD_GET(K210_PG_FUNC, pinmux_group);
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	const struct k210_pcf_info *info = &k210_pcf_infos[func];
+	u32 mode = k210_pc_mode_id_to_mode[info->mode_id];
+	u32 val = func | mode | (do_oe ? K210_PC_DO_OE : 0);
+
+	debug("%s(%.8x): IO_%.2u = %3u | %.8x\n", __func__, pinmux_group, pin,
+	      func, mode);
+
+	writel(val, &priv->fpioa->pins[pin]);
+	return pin;
+}
+
+/* Max drive strength in uA */
+static const int k210_pc_drive_strength[] = {
+	[0] = 11200,
+	[1] = 16800,
+	[2] = 22300,
+	[3] = 27800,
+	[4] = 33300,
+	[5] = 38700,
+	[6] = 44100,
+	[7] = 49500,
+};
+
+static int k210_pc_get_drive(unsigned max_strength_ua)
+{
+	int i;
+
+	for (i = K210_PC_DRIVE_MAX; i; i--)
+		if (k210_pc_drive_strength[i] < max_strength_ua)
+			return i;
+
+	return -EINVAL;
+}
+
+static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector,
+			       unsigned param, unsigned argument)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	u32 val = readl(&priv->fpioa->pins[pin_selector]);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		val &= ~K210_PC_BIAS_MASK;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (argument)
+			val |= K210_PC_PD;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (argument)
+			val |= K210_PC_PD;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		argument *= 1000;
+	case PIN_CONFIG_DRIVE_STRENGTH_UA: {
+		int drive = k210_pc_get_drive(argument);
+
+		if (IS_ERR_VALUE(drive))
+			return drive;
+		val &= ~K210_PC_DRIVE_MASK;
+		val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
+		break;
+	}
+	case PIN_CONFIG_INPUT_ENABLE:
+		if (argument)
+			val |= K210_PC_IE;
+		else
+			val &= ~K210_PC_IE;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT:
+		argument = 1;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		if (argument)
+			val |= K210_PC_ST;
+		else
+			val &= ~K210_PC_ST;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		k210_pc_pinmux_set(dev,
+				   K210_FPIOA(pin_selector, K210_PCF_CONSTANT));
+		val = readl(&priv->fpioa->pins[pin_selector]);
+		val |= K210_PC_MODE_OUT;
+
+		if (!argument)
+			val |= K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		if (argument)
+			val |= K210_PC_OE;
+		else
+			val &= ~K210_PC_OE;
+		break;
+	case PIN_CONFIG_SLEW_RATE:
+		if (argument)
+			val |= K210_PC_SL;
+		else
+			val &= ~K210_PC_SL;
+		break;
+	case PIN_CONFIG_OUTPUT_INVERT:
+		if (argument)
+			val |= K210_PC_DO_INV;
+		else
+			val &= ~K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_INPUT_INVERT:
+		if (argument)
+			val |= K210_PC_DI_INV;
+		else
+			val &= ~K210_PC_DI_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(val, &priv->fpioa->pins[pin_selector]);
+	return 0;
+}
+
+static int k210_pc_pinconf_group_set(struct udevice *dev,
+				     unsigned group_selector, unsigned param,
+				     unsigned argument)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+
+	if (param == PIN_CONFIG_POWER_SOURCE) {
+		u32 bit = BIT(group_selector);
+
+		regmap_update_bits(priv->sysctl, priv->power_offset, bit,
+				   argument ? bit : 0);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_CMD_PINMUX
+static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector,
+				  char *buf, int size)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	u32 val = readl(&priv->fpioa->pins[selector]);
+	const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK];
+
+	strncpy(buf, info->name, min((size_t)size, sizeof(info->name)));
+	return 0;
+}
+#endif
+
+static const struct pinconf_param k210_pc_pinconf_params[] = {
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX },
+	{ "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX },
+	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+	{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+	{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+	{ "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 },
+	{ "output-low", PIN_CONFIG_OUTPUT, 0 },
+	{ "output-high", PIN_CONFIG_OUTPUT, 1 },
+	{ "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+	{ "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
+	{ "slew-rate", PIN_CONFIG_SLEW_RATE, 1 },
+	{ "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1},
+	{ "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1},
+};
+
+static const struct pinctrl_ops k210_pc_pinctrl_ops = {
+#ifdef CONFIG_CMD_PINMUX
+	.get_pins_count = k210_pc_get_pins_count,
+	.get_pin_name = k210_pc_get_pin_name,
+#endif
+	.get_groups_count = k210_pc_get_groups_count,
+	.get_group_name = k210_pc_get_group_name,
+	.pinmux_property_set = k210_pc_pinmux_set,
+	.pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params),
+	.pinconf_params = k210_pc_pinconf_params,
+	.pinconf_set = k210_pc_pinconf_set,
+	.pinconf_group_set = k210_pc_pinconf_group_set,
+	.set_state = pinctrl_generic_set_state,
+#ifdef CONFIG_CMD_PINMUX
+	.get_pin_muxing = k210_pc_get_pin_muxing,
+#endif
+};
+
+static int k210_pc_probe(struct udevice *dev)
+{
+	int ret, i, j;
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+
+	priv->fpioa = dev_read_addr_ptr(dev);
+	if (!priv->fpioa)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &priv->clk);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&priv->clk);
+	if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
+		goto err;
+
+	priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl");
+	if (IS_ERR(priv->sysctl)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset);
+	if (ret)
+		goto err;
+
+	debug("%s: fpioa = %p sysctl = %p power offset = %x\n", __func__,
+	      priv->fpioa, (void *)priv->sysctl->ranges[0].start,
+	      priv->power_offset);
+
+	/* Init input ties */
+	for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) {
+		u32 val = 0;
+
+		for (j = 0; j < 32; j++)
+			if (k210_pcf_infos[i * 32 + j].mode_id ==
+			    K210_PC_DEFAULT_IN_TIE)
+				val |= BIT(j);
+		writel(val, &priv->fpioa->tie_en[i]);
+		writel(val, &priv->fpioa->tie_val[i]);
+	}
+
+	return 0;
+
+err:
+	clk_free(&priv->clk);
+	return ret;
+}
+
+static const struct udevice_id k210_pc_ids[] = {
+	{ .compatible = "kendryte,k210-fpioa" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_k210) = {
+	.name = "pinctrl_k210",
+	.id = UCLASS_PINCTRL,
+	.of_match = k210_pc_ids,
+	.probe = k210_pc_probe,
+	.priv_auto_alloc_size = sizeof(struct k210_pc_priv),
+	.ops = &k210_pc_pinctrl_ops,
+};

+ 138 - 48
drivers/pinctrl/pinctrl-sandbox.c

@@ -1,57 +1,70 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  */
 
-/* #define DEBUG */
-
 #include <common.h>
 #include <dm.h>
-#include <log.h>
 #include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/sandbox-pinmux.h>
+#include <log.h>
 #include <linux/bitops.h>
 
+/*
+ * This driver emulates a pin controller with the following rules:
+ * - The pinctrl config for each pin must be set individually
+ * - The first three pins (P0-P2) must be muxed as a group
+ * - The next two pins (P3-P4) must be muxed as a group
+ * - The last four pins (P5-P8) must be muxed individually
+ */
+
 static const char * const sandbox_pins[] = {
-	"SCL",
-	"SDA",
-	"TX",
-	"RX",
-	"W1",
-	"GPIO0",
-	"GPIO1",
-	"GPIO2",
-	"GPIO3",
+#define PIN(x) \
+	[x] = "P" #x
+	PIN(0),
+	PIN(1),
+	PIN(2),
+	PIN(3),
+	PIN(4),
+	PIN(5),
+	PIN(6),
+	PIN(7),
+	PIN(8),
+#undef PIN
 };
 
-static const char * const sandbox_pins_muxing[] = {
-	"I2C SCL",
-	"I2C SDA",
-	"Uart TX",
-	"Uart RX",
-	"1-wire gpio",
-	"gpio",
-	"gpio",
-	"gpio",
-	"gpio",
+static const char * const sandbox_pins_muxing[][2] = {
+	{ "UART TX", "I2C SCL" },
+	{ "UART RX", "I2C SDA" },
+	{ "SPI SCLK", "I2S SCK" },
+	{ "SPI MOSI", "I2S SD" },
+	{ "SPI MISO", "I2S WS" },
+	{ "GPIO0", "SPI CS0" },
+	{ "GPIO1", "SPI CS1" },
+	{ "GPIO2", "PWM0" },
+	{ "GPIO3", "PWM1" },
 };
 
+#define SANDBOX_GROUP_I2C_UART 0
+#define SANDBOX_GROUP_SPI_I2S 1
+
 static const char * const sandbox_groups[] = {
-	"i2c",
-	"serial_a",
-	"serial_b",
-	"spi",
-	"w1",
+	[SANDBOX_GROUP_I2C_UART] = "I2C_UART",
+	[SANDBOX_GROUP_SPI_I2S] = "SPI_I2S",
 };
 
 static const char * const sandbox_functions[] = {
-	"i2c",
-	"serial",
-	"spi",
-	"w1",
-	"gpio",
-	"gpio",
-	"gpio",
-	"gpio",
+#define FUNC(id) \
+	[SANDBOX_PINMUX_##id] = #id
+	FUNC(UART),
+	FUNC(I2C),
+	FUNC(SPI),
+	FUNC(I2S),
+	FUNC(GPIO),
+	FUNC(CS),
+	FUNC(PWM),
+#undef FUNC
 };
 
 static const struct pinconf_param sandbox_conf_params[] = {
@@ -68,9 +81,12 @@ static const struct pinconf_param sandbox_conf_params[] = {
 	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
 };
 
-/* bitfield used to save param and value of each pin/selector */
-static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)];
-static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)];
+/* Bitfield used to save param and value of each pin/selector */
+struct sandbox_pinctrl_priv {
+	unsigned int mux;
+	unsigned int pins_param[ARRAY_SIZE(sandbox_pins)];
+	unsigned int pins_value[ARRAY_SIZE(sandbox_pins)];
+};
 
 static int sandbox_get_pins_count(struct udevice *dev)
 {
@@ -87,16 +103,18 @@ static int sandbox_get_pin_muxing(struct udevice *dev,
 				  char *buf, int size)
 {
 	const struct pinconf_param *p;
+	struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
 	int i;
 
-	snprintf(buf, size, "%s", sandbox_pins_muxing[selector]);
+	snprintf(buf, size, "%s",
+		 sandbox_pins_muxing[selector][!!(priv->mux & BIT(selector))]);
 
-	if (sandbox_pins_param[selector]) {
+	if (priv->pins_param[selector]) {
 		for (i = 0, p = sandbox_conf_params;
 		     i < ARRAY_SIZE(sandbox_conf_params);
 		     i++, p++) {
-			if ((sandbox_pins_param[selector] & BIT(p->param)) &&
-			    (!!(sandbox_pins_value[selector] & BIT(p->param)) ==
+			if ((priv->pins_param[selector] & BIT(p->param)) &&
+			    (!!(priv->pins_value[selector] & BIT(p->param)) ==
 			     p->default_value)) {
 				strncat(buf, " ", size);
 				strncat(buf, p->property, size);
@@ -133,12 +151,32 @@ static const char *sandbox_get_function_name(struct udevice *dev,
 static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
 			      unsigned func_selector)
 {
+	int mux;
+	struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+
 	debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
 	      pin_selector, sandbox_get_pin_name(dev, pin_selector),
 	      func_selector, sandbox_get_function_name(dev, func_selector));
 
-	sandbox_pins_param[pin_selector] = 0;
-	sandbox_pins_value[pin_selector] = 0;
+	if (pin_selector < 5)
+		return -EINVAL;
+
+	switch (func_selector) {
+	case SANDBOX_PINMUX_GPIO:
+		mux = 0;
+		break;
+	case SANDBOX_PINMUX_CS:
+	case SANDBOX_PINMUX_PWM:
+		mux = BIT(pin_selector);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	priv->mux &= ~BIT(pin_selector);
+	priv->mux |= mux;
+	priv->pins_param[pin_selector] = 0;
+	priv->pins_value[pin_selector] = 0;
 
 	return 0;
 }
@@ -147,25 +185,75 @@ static int sandbox_pinmux_group_set(struct udevice *dev,
 				    unsigned group_selector,
 				    unsigned func_selector)
 {
+	bool mux;
+	int i, group_start, group_end;
+	struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+	unsigned int mask;
+
 	debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
 	      group_selector, sandbox_get_group_name(dev, group_selector),
 	      func_selector, sandbox_get_function_name(dev, func_selector));
 
+	if (group_selector == SANDBOX_GROUP_I2C_UART) {
+		group_start = 0;
+		group_end = 1;
+
+		if (func_selector == SANDBOX_PINMUX_UART)
+			mux = false;
+		else if (func_selector == SANDBOX_PINMUX_I2C)
+			mux = true;
+		else
+			return -EINVAL;
+	} else if (group_selector == SANDBOX_GROUP_SPI_I2S) {
+		group_start = 2;
+		group_end = 4;
+
+		if (func_selector == SANDBOX_PINMUX_SPI)
+			mux = false;
+		else if (func_selector == SANDBOX_PINMUX_I2S)
+			mux = true;
+		else
+			return -EINVAL;
+	} else {
+		return -EINVAL;
+	}
+
+	mask = GENMASK(group_end, group_start);
+	priv->mux &= ~mask;
+	priv->mux |= mux ? mask : 0;
+
+	for (i = group_start; i < group_end; i++) {
+		priv->pins_param[i] = 0;
+		priv->pins_value[i] = 0;
+	}
+
 	return 0;
 }
 
+static int sandbox_pinmux_property_set(struct udevice *dev, u32 pinmux_group)
+{
+	int ret;
+	unsigned pin_selector = pinmux_group & 0xFFFF;
+	unsigned func_selector = pinmux_group >> 16;
+
+	ret = sandbox_pinmux_set(dev, pin_selector, func_selector);
+	return ret ? ret : pin_selector;
+}
+
 static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
 			       unsigned param, unsigned argument)
 {
+	struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+
 	debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
 	      pin_selector, sandbox_get_pin_name(dev, pin_selector),
 	      param, argument);
 
-	sandbox_pins_param[pin_selector] |= BIT(param);
+	priv->pins_param[pin_selector] |= BIT(param);
 	if (argument)
-		sandbox_pins_value[pin_selector] |= BIT(param);
+		priv->pins_value[pin_selector] |= BIT(param);
 	else
-		sandbox_pins_value[pin_selector] &= ~BIT(param);
+		priv->pins_value[pin_selector] &= ~BIT(param);
 
 	return 0;
 }
@@ -191,6 +279,7 @@ const struct pinctrl_ops sandbox_pinctrl_ops = {
 	.get_function_name = sandbox_get_function_name,
 	.pinmux_set = sandbox_pinmux_set,
 	.pinmux_group_set = sandbox_pinmux_group_set,
+	.pinmux_property_set = sandbox_pinmux_property_set,
 	.pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
 	.pinconf_params = sandbox_conf_params,
 	.pinconf_set = sandbox_pinconf_set,
@@ -207,5 +296,6 @@ U_BOOT_DRIVER(sandbox_pinctrl) = {
 	.name = "sandbox_pinctrl",
 	.id = UCLASS_PINCTRL,
 	.of_match = sandbox_pinctrl_match,
+	.priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv),
 	.ops = &sandbox_pinctrl_ops,
 };

+ 1 - 0
drivers/ram/Kconfig

@@ -73,6 +73,7 @@ config IMXRT_SDRAM
 	  to support external memories like sdram, psram & nand.
 	  This driver is for the sdram memory interface with the SEMC.
 
+source "drivers/ram/aspeed/Kconfig"
 source "drivers/ram/rockchip/Kconfig"
 source "drivers/ram/sifive/Kconfig"
 source "drivers/ram/stm32mp1/Kconfig"

+ 1 - 0
drivers/ram/Makefile

@@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 
 obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o
 obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
+obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/
 
 obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o

+ 10 - 0
drivers/ram/aspeed/Kconfig

@@ -0,0 +1,10 @@
+if RAM || SPL_RAM
+config ASPEED_DDR4_DUALX8
+	bool "Enable Dual X8 DDR4 die"
+	depends on DM && OF_CONTROL && ARCH_ASPEED
+	default n
+	help
+		Say Y if dual X8 DDR4 die is used on the board.  The aspeed ddr sdram
+		controller needs to know if the memory chip mounted on the board is dual
+		 x8 die or not.  Or it may get the wrong size of the memory space.
+endif

+ 3 - 0
drivers/ram/aspeed/Makefile

@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+obj-$(CONFIG_ASPEED_AST2500) += sdram_ast2500.o

+ 1 - 1
arch/arm/mach-aspeed/ast2500/sdram_ast2500.c → drivers/ram/aspeed/sdram_ast2500.c

@@ -247,7 +247,7 @@ static int ast2500_sdrammc_init_ddr4(struct dram_info *info)
 	    | SDRAM_PCR_RESETN_DIS
 	    | SDRAM_PCR_RGAP_CTRL_EN | SDRAM_PCR_ODT_EN | SDRAM_PCR_ODT_EXT_EN;
 	const u32 conf = (SDRAM_CONF_CAP_1024M << SDRAM_CONF_CAP_SHIFT)
-#ifdef CONFIG_DUALX8_RAM
+#ifdef CONFIG_ASPEED_DDR4_DUALX8
 	    | SDRAM_CONF_DUALX8
 #endif
 	    | SDRAM_CONF_SCRAMBLE | SDRAM_CONF_SCRAMBLE_PAT2 | SDRAM_CONF_DDR4;

+ 1 - 1
drivers/watchdog/designware_wdt.c

@@ -130,7 +130,7 @@ static int designware_wdt_probe(struct udevice *dev)
 	if (ret)
 		return ret;
 
-	priv->clk_khz = clk_get_rate(&clk);
+	priv->clk_khz = clk_get_rate(&clk) / 1000;
 	if (!priv->clk_khz)
 		return -EINVAL;
 #else

+ 1 - 1
examples/Makefile

@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-ifndef CONFIG_SANDBOX
+ifdef CONFIG_EXAMPLES
 
 ifdef FTRACE
 subdir-ccflags-y += -finstrument-functions -DFTRACE

+ 1 - 7
include/configs/qemu-arm.h

@@ -45,13 +45,7 @@
 #define CONFIG_SYS_CBSIZE 512
 
 #define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
-#ifdef CONFIG_TFABOOT
-#define CONFIG_SYS_FLASH_BASE		0x4000000
-#define CONFIG_SYS_MAX_FLASH_BANKS	1
-#else
-#define CONFIG_SYS_FLASH_BASE		0x0
-#define CONFIG_SYS_MAX_FLASH_BANKS	2
-#endif
+#define CONFIG_SYS_MAX_FLASH_BANKS_DETECT	2
 #define CONFIG_SYS_MAX_FLASH_SECT	256 /* Sector: 256K, Bank: 64M */
 #define CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
 

+ 340 - 158
include/dm/pinctrl.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@com>
  */
 
 #ifndef __PINCTRL_H
@@ -11,11 +11,10 @@
 
 /**
  * struct pinconf_param - pin config parameters
- *
- * @property: property name in DT nodes
- * @param: ID for this config parameter
- * @default_value: default value for this config parameter used in case
- *	no value is specified in DT nodes
+ * @property:		Property name in DT nodes
+ * @param:		ID for this config parameter
+ * @default_value:	default value for this config parameter used in case
+ *			no value is specified in DT nodes
  */
 struct pinconf_param {
 	const char * const property;
@@ -27,106 +26,274 @@ struct pinconf_param {
  * struct pinctrl_ops - pin control operations, to be implemented by
  * pin controller drivers.
  *
- * The @set_state is the only mandatory operation.  You can implement your
- * pinctrl driver with its own @set_state.  In this case, the other callbacks
- * are not required.  Otherwise, generic pinctrl framework is also available;
- * use pinctrl_generic_set_state for @set_state, and implement other operations
+ * set_state() is the only mandatory operation. You can implement your pinctrl
+ * driver with its own @set_state. In this case, the other callbacks are not
+ * required. Otherwise, generic pinctrl framework is also available; use
+ * pinctrl_generic_set_state for @set_state, and implement other operations
  * depending on your necessity.
- *
- * @get_pins_count: return number of selectable named pins available
- *	in this driver.  (necessary to parse "pins" property in DTS)
- * @get_pin_name: return the pin name of the pin selector,
- *	called by the core to figure out which pin it shall do
- *	operations to.  (necessary to parse "pins" property in DTS)
- * @get_groups_count: return number of selectable named groups available
- *	in this driver.  (necessary to parse "groups" property in DTS)
- * @get_group_name: return the group name of the group selector,
- *	called by the core to figure out which pin group it shall do
- *	operations to.  (necessary to parse "groups" property in DTS)
- * @get_functions_count: return number of selectable named functions available
- *	in this driver.  (necessary for pin-muxing)
- * @get_function_name: return the function name of the muxing selector,
- *	called by the core to figure out which mux setting it shall map a
- *	certain device to.  (necessary for pin-muxing)
- * @pinmux_set: enable a certain muxing function with a certain pin.
- *	The @func_selector selects a certain function whereas @pin_selector
- *	selects a certain pin to be used. On simple controllers one of them
- *	may be ignored.  (necessary for pin-muxing against a single pin)
- * @pinmux_group_set: enable a certain muxing function with a certain pin
- *	group.  The @func_selector selects a certain function whereas
- *	@group_selector selects a certain set of pins to be used. On simple
- *	controllers one of them may be ignored.
- *	(necessary for pin-muxing against a pin group)
- * @pinconf_num_params: number of driver-specific parameters to be parsed
- *	from device trees  (necessary for pin-configuration)
- * @pinconf_params: list of driver_specific parameters to be parsed from
- *	device trees  (necessary for pin-configuration)
- * @pinconf_set: configure an individual pin with a given parameter.
- *	(necessary for pin-configuration against a single pin)
- * @pinconf_group_set: configure all pins in a group with a given parameter.
- *	(necessary for pin-configuration against a pin group)
- * @set_state: do pinctrl operations specified by @config, a pseudo device
- *	pointing a config node. (necessary for pinctrl_full)
- * @set_state_simple: do needed pinctrl operations for a peripherl @periph.
- *	(necessary for pinctrl_simple)
- * @get_pin_muxing: display the muxing of a given pin.
- * @gpio_request_enable: requests and enables GPIO on a certain pin.
- *	Implement this only if you can mux every pin individually as GPIO. The
- *	affected GPIO range is passed along with an offset(pin number) into that
- *	specific GPIO range - function selectors and pin groups are orthogonal
- *	to this, the core will however make sure the pins do not collide.
- * @gpio_disable_free: free up GPIO muxing on a certain pin, the reverse of
- *	@gpio_request_enable
  */
 struct pinctrl_ops {
+	/**
+	 * @get_pins_count: Get the number of selectable pins
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * This function is necessary to parse the "pins" property in DTS.
+	 *
+	 * @Return:
+	 *	number of selectable named pins available in this driver
+	 */
 	int (*get_pins_count)(struct udevice *dev);
+
+	/**
+	 * @get_pin_name: Get the name of a pin
+	 *
+	 * @dev: Pinctrl device of the pin
+	 *
+	 * @selector: The pin selector
+	 *
+	 * This function is called by the core to figure out which pin it will
+	 * do operations to. This function is necessary to parse the "pins"
+	 * property in DTS.
+	 *
+	 * @Return: const pointer to the name of the pin
+	 */
 	const char *(*get_pin_name)(struct udevice *dev, unsigned selector);
+
+	/**
+	 * @get_groups_count: Get the number of selectable groups
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * This function is necessary to parse the "groups" property in DTS.
+	 *
+	 * @Return:
+	 *	number of selectable named groups available in the driver
+	 */
 	int (*get_groups_count)(struct udevice *dev);
+
+	/**
+	 * @get_group_name: Get the name of a group
+	 *
+	 * @dev: Pinctrl device of the group
+	 *
+	 * @selector: The group selector
+	 *
+	 * This function is called by the core to figure out which group it
+	 * will do operations to. This function is necessary to parse the
+	 * "groups" property in DTS.
+	 *
+	 * @Return: Pointer to the name of the group
+	 */
 	const char *(*get_group_name)(struct udevice *dev, unsigned selector);
+
+	/**
+	 * @get_functions_count: Get the number of selectable functions
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * This function is necessary for pin-muxing.
+	 *
+	 * @Return:
+	 *	number of selectable named functions available in this driver
+	 */
 	int (*get_functions_count)(struct udevice *dev);
+
+	/**
+	 * @get_function_name: Get the name of a function
+	 *
+	 * @dev: Pinmux device of the function
+	 *
+	 * @selector: The function selector
+	 *
+	 * This function is called by the core to figure out which mux setting
+	 * it will map a certain device to. This function is necessary for
+	 * pin-muxing.
+	 *
+	 * @Return:
+	 *	Pointer to the function name of the muxing selector
+	 */
 	const char *(*get_function_name)(struct udevice *dev,
 					 unsigned selector);
+
+	/**
+	 * @pinmux_set: Mux a pin to a function
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @pin_selector: The pin selector
+	 *
+	 * @func_selector: The func selector
+	 *
+	 * On simple controllers one of @pin_selector or @func_selector may be
+	 * ignored. This function is necessary for pin-muxing against a single
+	 * pin.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*pinmux_set)(struct udevice *dev, unsigned pin_selector,
 			  unsigned func_selector);
+
+	/**
+	 * @pinmux_group_set: Mux a group of pins to a function
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @group_selector: The group selector
+	 *
+	 * @func_selector: The func selector
+	 *
+	 * On simple controllers one of @group_selector or @func_selector may be
+	 * ignored. This function is necessary for pin-muxing against a group of
+	 * pins.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*pinmux_group_set)(struct udevice *dev, unsigned group_selector,
 				unsigned func_selector);
+
+	/**
+	 * @pinmux_property_set: Enable a pinmux group
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @pinmux_group: A u32 representing the pin identifier and mux
+	 *                settings. The exact format of a pinmux group is left
+	 *                up to the driver.
+	 *
+	 * Mux a single pin to a single function based on a driver-specific
+	 * pinmux group. This function is necessary for parsing the "pinmux"
+	 * property in DTS, and for pin-muxing against a pinmux group.
+	 *
+	 * @Return:
+	 *	Pin selector for the muxed pin if OK, or negative error code on
+	 *	failure
+	 */
+	int (*pinmux_property_set)(struct udevice *dev, u32 pinmux_group);
+
+	/**
+	 * @pinconf_num_params:
+	 *	Number of driver-specific parameters to be parsed from device
+	 *	trees. This member is necessary for pin configuration.
+	 */
 	unsigned int pinconf_num_params;
+
+	/**
+	 * @pinconf_params:
+	 *	List of driver-specific parameters to be parsed from the device
+	 *	tree. This member is necessary for pin configuration.
+	 */
 	const struct pinconf_param *pinconf_params;
+
+	/**
+	 * @pinconf_set: Configure an individual pin with a parameter
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @pin_selector: The pin selector
+	 *
+	 * @param: An &enum pin_config_param from @pinconf_params
+	 *
+	 * @argument: The argument to this param from the device tree, or
+	 *            @pinconf_params.default_value
+	 *
+	 * This function is necessary for pin configuration against a single
+	 * pin.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*pinconf_set)(struct udevice *dev, unsigned pin_selector,
 			   unsigned param, unsigned argument);
+
+	/**
+	 * @pinconf_group_set: Configure all pins in a group with a parameter
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @pin_selector: The group selector
+	 *
+	 * @param: A &enum pin_config_param from
+	 *         @pinconf_params
+	 *
+	 * @argument: The argument to this param from the device tree, or
+	 *            @pinconf_params.default_value
+	 *
+	 * This function is necessary for pin configuration against a group of
+	 * pins.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*pinconf_group_set)(struct udevice *dev, unsigned group_selector,
 				 unsigned param, unsigned argument);
+
+	/**
+	 * @set_state: Configure a pinctrl device
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @config: Pseudo device pointing a config node
+	 *
+	 * This function is required to be implemented by all pinctrl drivers.
+	 * Drivers may set this member to pinctrl_generic_set_state(), which
+	 * will call other functions in &struct pinctrl_ops to parse
+	 * @config.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*set_state)(struct udevice *dev, struct udevice *config);
 
-	/* for pinctrl-simple */
+	/**
+	 * @set_state_simple: Configure a pinctrl device
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @config: Pseudo-device pointing a config node
+	 *
+	 * This function is usually a simpler version of set_state(). Only the
+	 * first pinctrl device on the system is supported by this function.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
+	 */
 	int (*set_state_simple)(struct udevice *dev, struct udevice *periph);
+
 	/**
-	 * request() - Request a particular pinctrl function
+	 * @request: Request a particular pinctrl function
+	 *
+	 * @dev: Device to adjust (%UCLASS_PINCTRL)
+	 *
+	 * @func: Function number (driver-specific)
 	 *
 	 * This activates the selected function.
 	 *
-	 * @dev:	Device to adjust (UCLASS_PINCTRL)
-	 * @func:	Function number (driver-specific)
-	 * @return 0 if OK, -ve on error
+	 * @Return: 0 if OK, or negative error code on failure
 	 */
 	int (*request)(struct udevice *dev, int func, int flags);
 
 	/**
-	* get_periph_id() - get the peripheral ID for a device
+	* @get_periph_id: Get the peripheral ID for a device
+	*
+	* @dev: Pinctrl device to use for decoding
+	*
+	* @periph: Device to check
 	*
 	* This generally looks at the peripheral's device tree node to work
 	* out the peripheral ID. The return value is normally interpreted as
-	* enum periph_id. so long as this is defined by the platform (which it
+	* &enum periph_id. so long as this is defined by the platform (which it
 	* should be).
 	*
-	* @dev:		Pinctrl device to use for decoding
-	* @periph:	Device to check
-	* @return peripheral ID of @periph, or -ENOENT on error
+	* @Return:
+	*	Peripheral ID of @periph, or %-ENOENT on error
 	*/
 	int (*get_periph_id)(struct udevice *dev, struct udevice *periph);
 
 	/**
-	 * get_gpio_mux() - get the mux value for a particular GPIO
+	 * @get_gpio_mux: Get the mux value for a particular GPIO
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @banknum: GPIO bank number
+	 *
+	 * @index: GPIO index within the bank
 	 *
 	 * This allows the raw mux value for a GPIO to be obtained. It is
 	 * useful for displaying the function being used by that GPIO, such
@@ -134,46 +301,60 @@ struct pinctrl_ops {
 	 * subsystem and should not be used by generic code. Typically it is
 	 * used by a GPIO driver with knowledge of the SoC pinctrl setup.
 	 *
-	* @dev:		Pinctrl device to use
-	* @banknum:	GPIO bank number
-	* @index:	GPIO index within the bank
-	* @return mux value (SoC-specific, e.g. 0 for input, 1 for output)
+	 * @Return:
+	 *	Mux value (SoC-specific, e.g. 0 for input, 1 for output)
 	 */
 	int (*get_gpio_mux)(struct udevice *dev, int banknum, int index);
 
 	/**
-	 * get_pin_muxing() - show pin muxing
+	 * @get_pin_muxing: Show pin muxing
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @selector: Pin selector
+	 *
+	 * @buf: Buffer to fill with pin muxing description
+	 *
+	 * @size: Size of @buf
 	 *
 	 * This allows to display the muxing of a given pin. It's useful for
-	 * debug purpose to know if a pin is configured as GPIO or as an
-	 * alternate function and which one.
-	 * Typically it is used by a PINCTRL driver with knowledge of the SoC
-	 * pinctrl setup.
-	 *
-	 * @dev:	Pinctrl device to use
-	 * @selector:	Pin selector
-	 * @buf		Pin's muxing description
-	 * @size	Pin's muxing description length
-	 * return 0 if OK, -ve on error
+	 * debug purposes to know if a pin is configured as GPIO or as an
+	 * alternate function and which one. Typically it is used by a PINCTRL
+	 * driver with knowledge of the SoC pinctrl setup.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
 	 */
 	 int (*get_pin_muxing)(struct udevice *dev, unsigned int selector,
 			       char *buf, int size);
 
 	/**
-	 * gpio_request_enable: requests and enables GPIO on a certain pin.
+	 * @gpio_request_enable: Request and enable GPIO on a certain pin.
+	 *
+	 * @dev: Pinctrl device to use
+	 *
+	 * @selector: Pin selector
+	 *
+	 * Implement this only if you can mux every pin individually as GPIO.
+	 * The affected GPIO range is passed along with an offset(pin number)
+	 * into that specific GPIO range - function selectors and pin groups are
+	 * orthogonal to this, the core will however make sure the pins do not
+	 * collide.
 	 *
-	 * @dev:	Pinctrl device to use
-	 * @selector:	Pin selector
-	 * return 0 if OK, -ve on error
+	 * @Return:
+	 *	0 if OK, or negative error code on failure
 	 */
 	int (*gpio_request_enable)(struct udevice *dev, unsigned int selector);
 
 	/**
-	 * gpio_disable_free: free up GPIO muxing on a certain pin.
+	 * @gpio_disable_free: Free up GPIO muxing on a certain pin.
 	 *
-	 * @dev:	Pinctrl device to use
-	 * @selector:	Pin selector
-	 * return 0 if OK, -ve on error
+	 * @dev: Pinctrl device to use
+	 *
+	 * @selector: Pin selector
+	 *
+	 * This function is the reverse of @gpio_request_enable.
+	 *
+	 * @Return: 0 if OK, or negative error code on failure
 	 */
 	int (*gpio_disable_free)(struct udevice *dev, unsigned int selector);
 };
@@ -181,27 +362,26 @@ struct pinctrl_ops {
 #define pinctrl_get_ops(dev)	((struct pinctrl_ops *)(dev)->driver->ops)
 
 /**
- * Generic pin configuration paramters
+ * enum pin_config_param - Generic pin configuration parameters
  *
- * enum pin_config_param - possible pin configuration parameters
- * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ * @PIN_CONFIG_BIAS_BUS_HOLD: The pin will be set to weakly latch so that it
  *	weakly drives the last value on a tristate bus, also known as a "bus
  *	holder", "bus keeper" or "repeater". This allows another device on the
  *	bus to change the value by driving the bus high or low and switching to
  *	tristate. The argument is ignored.
- * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a
+ * @PIN_CONFIG_BIAS_DISABLE: Disable any pin bias on the pin, a
  *	transition from say pull-up to pull-down implies that you disable
  *	pull-up in the process, this setting disables all biasing.
- * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance
+ * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: The pin will be set to a high impedance
  *	mode, also know as "third-state" (tristate) or "high-Z" or "floating".
  *	On output pins this effectively disconnects the pin, which is useful
  *	if for example some other pin is going to drive the signal connected
  *	to it for a while. Pins used for input are usually always high
  *	impedance.
- * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
+ * @PIN_CONFIG_BIAS_PULL_DOWN: The pin will be pulled down (usually with high
  *	impedance to GROUND). If the argument is != 0 pull-down is enabled,
  *	if it is 0, pull-down is total, i.e. the pin is connected to GROUND.
- * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: The pin will be pulled up or down based
  *	on embedded knowledge of the controller hardware, like current mux
  *	function. The pull direction and possibly strength too will normally
  *	be decided completely inside the hardware block and not be readable
@@ -209,67 +389,67 @@ struct pinctrl_ops {
  *	If the argument is != 0 pull up/down is enabled, if it is 0, the
  *	configuration is ignored. The proper way to disable it is to use
  *	@PIN_CONFIG_BIAS_DISABLE.
- * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
+ * @PIN_CONFIG_BIAS_PULL_UP: The pin will be pulled up (usually with high
  *	impedance to VDD). If the argument is != 0 pull-up is enabled,
  *	if it is 0, pull-up is total, i.e. the pin is connected to VDD.
- * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open
+ * @PIN_CONFIG_DRIVE_OPEN_DRAIN: The pin will be driven with open drain (open
  *	collector) which means it is usually wired with other output ports
  *	which are then pulled up with an external resistor. Setting this
  *	config will enable open drain mode, the argument is ignored.
- * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
+ * @PIN_CONFIG_DRIVE_OPEN_SOURCE: The pin will be driven with open source
  *	(open emitter). Setting this config will enable open source mode, the
  *	argument is ignored.
- * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
+ * @PIN_CONFIG_DRIVE_PUSH_PULL: The pin will be driven actively high and
  *	low, this is the most typical case and is typically achieved with two
  *	active transistors on the output. Setting this config will enable
  *	push-pull mode, the argument is ignored.
- * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current
+ * @PIN_CONFIG_DRIVE_STRENGTH: The pin will sink or source at most the current
  *	passed as argument. The argument is in mA.
- * @PIN_CONFIG_DRIVE_STRENGTH_UA: the pin will sink or source at most the current
- *	passed as argument. The argument is in uA.
- * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
+ * @PIN_CONFIG_DRIVE_STRENGTH_UA: The pin will sink or source at most the
+ *	current passed as argument. The argument is in uA.
+ * @PIN_CONFIG_INPUT_DEBOUNCE: This will configure the pin to debounce mode,
  *	which means it will wait for signals to settle when reading inputs. The
  *	argument gives the debounce time in usecs. Setting the
  *	argument to zero turns debouncing off.
- * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input.  Note that this does not
+ * @PIN_CONFIG_INPUT_ENABLE: Enable the pin's input.  Note that this does not
  *	affect the pin's ability to drive output.  1 enables input, 0 disables
  *	input.
- * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
+ * @PIN_CONFIG_INPUT_SCHMITT: This will configure an input pin to run in
  *	schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
  *	the threshold value is given on a custom format as argument when
  *	setting pins to this mode.
- * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin.
+ * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: Control schmitt-trigger mode on the pin.
  *      If the argument != 0, schmitt-trigger mode is enabled. If it's 0,
  *      schmitt-trigger mode is disabled.
- * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
+ * @PIN_CONFIG_LOW_POWER_MODE: This will configure the pin for low power
  *	operation, if several modes of operation are supported these can be
  *	passed in the argument on a custom form, else just use argument 1
  *	to indicate low power mode, argument 0 turns low power mode off.
- * @PIN_CONFIG_OUTPUT_ENABLE: this will enable the pin's output mode
+ * @PIN_CONFIG_OUTPUT_ENABLE: This will enable the pin's output mode
  *	without driving a value there. For most platforms this reduces to
  *	enable the output buffers and then let the pin controller current
  *	configuration (eg. the currently selected mux function) drive values on
  *	the line. Use argument 1 to enable output mode, argument 0 to disable
  *	it.
- * @PIN_CONFIG_OUTPUT: this will configure the pin as an output and drive a
+ * @PIN_CONFIG_OUTPUT: This will configure the pin as an output and drive a
  *	value on the line. Use argument 1 to indicate high level, argument 0 to
  *	indicate low level. (Please see Documentation/driver-api/pinctl.rst,
  *	section "GPIO mode pitfalls" for a discussion around this parameter.)
- * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
+ * @PIN_CONFIG_POWER_SOURCE: If the pin can select between different power
  *	supplies, the argument to this parameter (on a custom format) tells
  *	the driver which alternative power source to use.
- * @PIN_CONFIG_SLEEP_HARDWARE_STATE: indicate this is sleep related state.
- * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
+ * @PIN_CONFIG_SLEEP_HARDWARE_STATE: Indicate this is sleep related state.
+ * @PIN_CONFIG_SLEW_RATE: If the pin can select slew rate, the argument to
  *	this parameter (on a custom format) tells the driver which alternative
  *	slew rate to use.
- * @PIN_CONFIG_SKEW_DELAY: if the pin has programmable skew rate (on inputs)
+ * @PIN_CONFIG_SKEW_DELAY: If the pin has programmable skew rate (on inputs)
  *	or latch delay (on outputs) this parameter (in a custom format)
  *	specifies the clock skew or latch delay. It typically controls how
  *	many double inverters are put in front of the line.
- * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
+ * @PIN_CONFIG_END: This is the last enumerator for pin configurations, if
  *	you need to pass in custom configurations to the pin controller, use
  *	PIN_CONFIG_END+1 as the base offset.
- * @PIN_CONFIG_MAX: this is the maximum configuration value that can be
+ * @PIN_CONFIG_MAX: This is the maximum configuration value that can be
  *	presented using the packed format.
  */
 enum pin_config_param {
@@ -301,13 +481,14 @@ enum pin_config_param {
 
 #if CONFIG_IS_ENABLED(PINCTRL_GENERIC)
 /**
- * pinctrl_generic_set_state() - generic set_state operation
+ * pinctrl_generic_set_state() - Generic set_state operation
+ * @pctldev:	Pinctrl device to use
+ * @config:	Config device (pseudo device), pointing a config node in DTS
+ *
  * Parse the DT node of @config and its children and handle generic properties
  * such as "pins", "groups", "functions", and pin configuration parameters.
  *
- * @pctldev: pinctrl device
- * @config: config device (pseudo device), pointing a config node in DTS
- * @return: 0 on success, or negative error code on failure
+ * Return: 0 on success, or negative error code on failure
  */
 int pinctrl_generic_set_state(struct udevice *pctldev, struct udevice *config);
 #else
@@ -320,11 +501,11 @@ static inline int pinctrl_generic_set_state(struct udevice *pctldev,
 
 #if CONFIG_IS_ENABLED(PINCTRL)
 /**
- * pinctrl_select_state() - set a device to a given state
+ * pinctrl_select_state() - Set a device to a given state
+ * @dev:	Peripheral device
+ * @statename:	State name, like "default"
  *
- * @dev: peripheral device
- * @statename: state name, like "default"
- * @return: 0 on success, or negative error code on failure
+ * Return: 0 on success, or negative error code on failure
  */
 int pinctrl_select_state(struct udevice *dev, const char *statename);
 #else
@@ -337,40 +518,43 @@ static inline int pinctrl_select_state(struct udevice *dev,
 
 /**
  * pinctrl_request() - Request a particular pinctrl function
- *
- * @dev:	Device to check (UCLASS_PINCTRL)
+ * @dev:	Pinctrl device to use
  * @func:	Function number (driver-specific)
  * @flags:	Flags (driver-specific)
- * @return 0 if OK, -ve on error
+ *
+ * Return: 0 if OK, or negative error code on failure
  */
 int pinctrl_request(struct udevice *dev, int func, int flags);
 
 /**
  * pinctrl_request_noflags() - Request a particular pinctrl function
+ * @dev:	Pinctrl device to use
+ * @func:	Function number (driver-specific)
  *
  * This is similar to pinctrl_request() but uses 0 for @flags.
  *
- * @dev:	Device to check (UCLASS_PINCTRL)
- * @func:	Function number (driver-specific)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, or negative error code on failure
  */
 int pinctrl_request_noflags(struct udevice *dev, int func);
 
 /**
- * pinctrl_get_periph_id() - get the peripheral ID for a device
+ * pinctrl_get_periph_id() - Get the peripheral ID for a device
+ * @dev:	Pinctrl device to use for decoding
+ * @periph:	Device to check
  *
  * This generally looks at the peripheral's device tree node to work out the
  * peripheral ID. The return value is normally interpreted as enum periph_id.
  * so long as this is defined by the platform (which it should be).
  *
- * @dev:	Pinctrl device to use for decoding
- * @periph:	Device to check
- * @return peripheral ID of @periph, or -ENOENT on error
+ * Return: Peripheral ID of @periph, or -ENOENT on error
  */
 int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph);
 
 /**
  * pinctrl_get_gpio_mux() - get the mux value for a particular GPIO
+ * @dev:	Pinctrl device to use
+ * @banknum:	GPIO bank number
+ * @index:	GPIO index within the bank
  *
  * This allows the raw mux value for a GPIO to be obtained. It is
  * useful for displaying the function being used by that GPIO, such
@@ -378,66 +562,64 @@ int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph);
  * subsystem and should not be used by generic code. Typically it is
  * used by a GPIO driver with knowledge of the SoC pinctrl setup.
  *
- * @dev:	Pinctrl device to use
- * @banknum:	GPIO bank number
- * @index:	GPIO index within the bank
- * @return mux value (SoC-specific, e.g. 0 for input, 1 for output)
+ * Return: Mux value (SoC-specific, e.g. 0 for input, 1 for output)
 */
 int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index);
 
 /**
  * pinctrl_get_pin_muxing() - Returns the muxing description
+ * @dev:	Pinctrl device to use
+ * @selector:	Pin index within pin-controller
+ * @buf:	Pin's muxing description
+ * @size:	Pin's muxing description length
  *
  * This allows to display the muxing description of the given pin for
  * debug purpose
  *
- * @dev:	Pinctrl device to use
- * @selector	Pin index within pin-controller
- * @buf		Pin's muxing description
- * @size	Pin's muxing description length
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, or negative error code on failure
  */
 int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf,
 			   int size);
 
 /**
- * pinctrl_get_pins_count() - display pin-controller pins number
+ * pinctrl_get_pins_count() - Display pin-controller pins number
+ * @dev:	Pinctrl device to use
  *
  * This allows to know the number of pins owned by a given pin-controller
  *
- * @dev:	Pinctrl device to use
- * @return pins number if OK, -ve on error
+ * Return: Number of pins if OK, or negative error code on failure
  */
 int pinctrl_get_pins_count(struct udevice *dev);
 
 /**
  * pinctrl_get_pin_name() - Returns the pin's name
+ * @dev:	Pinctrl device to use
+ * @selector:	Pin index within pin-controller
+ * @buf:	Buffer to fill with the name of the pin
+ * @size:	Size of @buf
  *
  * This allows to display the pin's name for debug purpose
  *
- * @dev:	Pinctrl device to use
- * @selector	Pin index within pin-controller
- * @buf		Pin's name
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, or negative error code on failure
  */
 int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf,
 			 int size);
 
 /**
- * pinctrl_gpio_request() - request a single pin to be used as GPIO
+ * pinctrl_gpio_request() - Request a single pin to be used as GPIO
+ * @dev:	GPIO peripheral device
+ * @offset:	GPIO pin offset from the GPIO controller
  *
- * @dev: GPIO peripheral device
- * @offset: the GPIO pin offset from the GPIO controller
- * @return: 0 on success, or negative error code on failure
+ * Return: 0 on success, or negative error code on failure
  */
 int pinctrl_gpio_request(struct udevice *dev, unsigned offset);
 
 /**
- * pinctrl_gpio_free() - free a single pin used as GPIO
+ * pinctrl_gpio_free() - Free a single pin used as GPIO
+ * @dev:	GPIO peripheral device
+ * @offset:	GPIO pin offset from the GPIO controller
  *
- * @dev: GPIO peripheral device
- * @offset: the GPIO pin offset from the GPIO controller
- * @return: 0 on success, or negative error code on failure
+ * Return: 0 on success, or negative error code on failure
  */
 int pinctrl_gpio_free(struct udevice *dev, unsigned offset);
 

+ 277 - 0
include/dt-bindings/pinctrl/k210-pinctrl.h

@@ -0,0 +1,277 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef DT_K210_PINCTRL_H
+#define DT_K210_PINCTRL_H
+
+/*
+ * Full list of FPIOA functions from
+ * kendryte-standalone-sdk/lib/drivers/include/fpioa.h
+ */
+#define K210_PCF_MASK GENMASK(7, 0)
+#define K210_PCF_JTAG_TCLK      0   /* JTAG Test Clock */
+#define K210_PCF_JTAG_TDI       1   /* JTAG Test Data In */
+#define K210_PCF_JTAG_TMS       2   /* JTAG Test Mode Select */
+#define K210_PCF_JTAG_TDO       3   /* JTAG Test Data Out */
+#define K210_PCF_SPI0_D0        4   /* SPI0 Data 0 */
+#define K210_PCF_SPI0_D1        5   /* SPI0 Data 1 */
+#define K210_PCF_SPI0_D2        6   /* SPI0 Data 2 */
+#define K210_PCF_SPI0_D3        7   /* SPI0 Data 3 */
+#define K210_PCF_SPI0_D4        8   /* SPI0 Data 4 */
+#define K210_PCF_SPI0_D5        9   /* SPI0 Data 5 */
+#define K210_PCF_SPI0_D6        10  /* SPI0 Data 6 */
+#define K210_PCF_SPI0_D7        11  /* SPI0 Data 7 */
+#define K210_PCF_SPI0_SS0       12  /* SPI0 Chip Select 0 */
+#define K210_PCF_SPI0_SS1       13  /* SPI0 Chip Select 1 */
+#define K210_PCF_SPI0_SS2       14  /* SPI0 Chip Select 2 */
+#define K210_PCF_SPI0_SS3       15  /* SPI0 Chip Select 3 */
+#define K210_PCF_SPI0_ARB       16  /* SPI0 Arbitration */
+#define K210_PCF_SPI0_SCLK      17  /* SPI0 Serial Clock */
+#define K210_PCF_UARTHS_RX      18  /* UART High speed Receiver */
+#define K210_PCF_UARTHS_TX      19  /* UART High speed Transmitter */
+#define K210_PCF_RESV6          20  /* Reserved function */
+#define K210_PCF_RESV7          21  /* Reserved function */
+#define K210_PCF_CLK_SPI1       22  /* Clock SPI1 */
+#define K210_PCF_CLK_I2C1       23  /* Clock I2C1 */
+#define K210_PCF_GPIOHS0        24  /* GPIO High speed 0 */
+#define K210_PCF_GPIOHS1        25  /* GPIO High speed 1 */
+#define K210_PCF_GPIOHS2        26  /* GPIO High speed 2 */
+#define K210_PCF_GPIOHS3        27  /* GPIO High speed 3 */
+#define K210_PCF_GPIOHS4        28  /* GPIO High speed 4 */
+#define K210_PCF_GPIOHS5        29  /* GPIO High speed 5 */
+#define K210_PCF_GPIOHS6        30  /* GPIO High speed 6 */
+#define K210_PCF_GPIOHS7        31  /* GPIO High speed 7 */
+#define K210_PCF_GPIOHS8        32  /* GPIO High speed 8 */
+#define K210_PCF_GPIOHS9        33  /* GPIO High speed 9 */
+#define K210_PCF_GPIOHS10       34  /* GPIO High speed 10 */
+#define K210_PCF_GPIOHS11       35  /* GPIO High speed 11 */
+#define K210_PCF_GPIOHS12       36  /* GPIO High speed 12 */
+#define K210_PCF_GPIOHS13       37  /* GPIO High speed 13 */
+#define K210_PCF_GPIOHS14       38  /* GPIO High speed 14 */
+#define K210_PCF_GPIOHS15       39  /* GPIO High speed 15 */
+#define K210_PCF_GPIOHS16       40  /* GPIO High speed 16 */
+#define K210_PCF_GPIOHS17       41  /* GPIO High speed 17 */
+#define K210_PCF_GPIOHS18       42  /* GPIO High speed 18 */
+#define K210_PCF_GPIOHS19       43  /* GPIO High speed 19 */
+#define K210_PCF_GPIOHS20       44  /* GPIO High speed 20 */
+#define K210_PCF_GPIOHS21       45  /* GPIO High speed 21 */
+#define K210_PCF_GPIOHS22       46  /* GPIO High speed 22 */
+#define K210_PCF_GPIOHS23       47  /* GPIO High speed 23 */
+#define K210_PCF_GPIOHS24       48  /* GPIO High speed 24 */
+#define K210_PCF_GPIOHS25       49  /* GPIO High speed 25 */
+#define K210_PCF_GPIOHS26       50  /* GPIO High speed 26 */
+#define K210_PCF_GPIOHS27       51  /* GPIO High speed 27 */
+#define K210_PCF_GPIOHS28       52  /* GPIO High speed 28 */
+#define K210_PCF_GPIOHS29       53  /* GPIO High speed 29 */
+#define K210_PCF_GPIOHS30       54  /* GPIO High speed 30 */
+#define K210_PCF_GPIOHS31       55  /* GPIO High speed 31 */
+#define K210_PCF_GPIO0          56  /* GPIO pin 0 */
+#define K210_PCF_GPIO1          57  /* GPIO pin 1 */
+#define K210_PCF_GPIO2          58  /* GPIO pin 2 */
+#define K210_PCF_GPIO3          59  /* GPIO pin 3 */
+#define K210_PCF_GPIO4          60  /* GPIO pin 4 */
+#define K210_PCF_GPIO5          61  /* GPIO pin 5 */
+#define K210_PCF_GPIO6          62  /* GPIO pin 6 */
+#define K210_PCF_GPIO7          63  /* GPIO pin 7 */
+#define K210_PCF_UART1_RX       64  /* UART1 Receiver */
+#define K210_PCF_UART1_TX       65  /* UART1 Transmitter */
+#define K210_PCF_UART2_RX       66  /* UART2 Receiver */
+#define K210_PCF_UART2_TX       67  /* UART2 Transmitter */
+#define K210_PCF_UART3_RX       68  /* UART3 Receiver */
+#define K210_PCF_UART3_TX       69  /* UART3 Transmitter */
+#define K210_PCF_SPI1_D0        70  /* SPI1 Data 0 */
+#define K210_PCF_SPI1_D1        71  /* SPI1 Data 1 */
+#define K210_PCF_SPI1_D2        72  /* SPI1 Data 2 */
+#define K210_PCF_SPI1_D3        73  /* SPI1 Data 3 */
+#define K210_PCF_SPI1_D4        74  /* SPI1 Data 4 */
+#define K210_PCF_SPI1_D5        75  /* SPI1 Data 5 */
+#define K210_PCF_SPI1_D6        76  /* SPI1 Data 6 */
+#define K210_PCF_SPI1_D7        77  /* SPI1 Data 7 */
+#define K210_PCF_SPI1_SS0       78  /* SPI1 Chip Select 0 */
+#define K210_PCF_SPI1_SS1       79  /* SPI1 Chip Select 1 */
+#define K210_PCF_SPI1_SS2       80  /* SPI1 Chip Select 2 */
+#define K210_PCF_SPI1_SS3       81  /* SPI1 Chip Select 3 */
+#define K210_PCF_SPI1_ARB       82  /* SPI1 Arbitration */
+#define K210_PCF_SPI1_SCLK      83  /* SPI1 Serial Clock */
+#define K210_PCF_SPI2_D0        84  /* SPI2 Data 0 */
+#define K210_PCF_SPI2_SS        85  /* SPI2 Select */
+#define K210_PCF_SPI2_SCLK      86  /* SPI2 Serial Clock */
+#define K210_PCF_I2S0_MCLK      87  /* I2S0 Master Clock */
+#define K210_PCF_I2S0_SCLK      88  /* I2S0 Serial Clock(BCLK) */
+#define K210_PCF_I2S0_WS        89  /* I2S0 Word Select(LRCLK) */
+#define K210_PCF_I2S0_IN_D0     90  /* I2S0 Serial Data Input 0 */
+#define K210_PCF_I2S0_IN_D1     91  /* I2S0 Serial Data Input 1 */
+#define K210_PCF_I2S0_IN_D2     92  /* I2S0 Serial Data Input 2 */
+#define K210_PCF_I2S0_IN_D3     93  /* I2S0 Serial Data Input 3 */
+#define K210_PCF_I2S0_OUT_D0    94  /* I2S0 Serial Data Output 0 */
+#define K210_PCF_I2S0_OUT_D1    95  /* I2S0 Serial Data Output 1 */
+#define K210_PCF_I2S0_OUT_D2    96  /* I2S0 Serial Data Output 2 */
+#define K210_PCF_I2S0_OUT_D3    97  /* I2S0 Serial Data Output 3 */
+#define K210_PCF_I2S1_MCLK      98  /* I2S1 Master Clock */
+#define K210_PCF_I2S1_SCLK      99  /* I2S1 Serial Clock(BCLK) */
+#define K210_PCF_I2S1_WS        100 /* I2S1 Word Select(LRCLK) */
+#define K210_PCF_I2S1_IN_D0     101 /* I2S1 Serial Data Input 0 */
+#define K210_PCF_I2S1_IN_D1     102 /* I2S1 Serial Data Input 1 */
+#define K210_PCF_I2S1_IN_D2     103 /* I2S1 Serial Data Input 2 */
+#define K210_PCF_I2S1_IN_D3     104 /* I2S1 Serial Data Input 3 */
+#define K210_PCF_I2S1_OUT_D0    105 /* I2S1 Serial Data Output 0 */
+#define K210_PCF_I2S1_OUT_D1    106 /* I2S1 Serial Data Output 1 */
+#define K210_PCF_I2S1_OUT_D2    107 /* I2S1 Serial Data Output 2 */
+#define K210_PCF_I2S1_OUT_D3    108 /* I2S1 Serial Data Output 3 */
+#define K210_PCF_I2S2_MCLK      109 /* I2S2 Master Clock */
+#define K210_PCF_I2S2_SCLK      110 /* I2S2 Serial Clock(BCLK) */
+#define K210_PCF_I2S2_WS        111 /* I2S2 Word Select(LRCLK) */
+#define K210_PCF_I2S2_IN_D0     112 /* I2S2 Serial Data Input 0 */
+#define K210_PCF_I2S2_IN_D1     113 /* I2S2 Serial Data Input 1 */
+#define K210_PCF_I2S2_IN_D2     114 /* I2S2 Serial Data Input 2 */
+#define K210_PCF_I2S2_IN_D3     115 /* I2S2 Serial Data Input 3 */
+#define K210_PCF_I2S2_OUT_D0    116 /* I2S2 Serial Data Output 0 */
+#define K210_PCF_I2S2_OUT_D1    117 /* I2S2 Serial Data Output 1 */
+#define K210_PCF_I2S2_OUT_D2    118 /* I2S2 Serial Data Output 2 */
+#define K210_PCF_I2S2_OUT_D3    119 /* I2S2 Serial Data Output 3 */
+#define K210_PCF_RESV0          120 /* Reserved function */
+#define K210_PCF_RESV1          121 /* Reserved function */
+#define K210_PCF_RESV2          122 /* Reserved function */
+#define K210_PCF_RESV3          123 /* Reserved function */
+#define K210_PCF_RESV4          124 /* Reserved function */
+#define K210_PCF_RESV5          125 /* Reserved function */
+#define K210_PCF_I2C0_SCLK      126 /* I2C0 Serial Clock */
+#define K210_PCF_I2C0_SDA       127 /* I2C0 Serial Data */
+#define K210_PCF_I2C1_SCLK      128 /* I2C1 Serial Clock */
+#define K210_PCF_I2C1_SDA       129 /* I2C1 Serial Data */
+#define K210_PCF_I2C2_SCLK      130 /* I2C2 Serial Clock */
+#define K210_PCF_I2C2_SDA       131 /* I2C2 Serial Data */
+#define K210_PCF_DVP_XCLK       132 /* DVP System Clock */
+#define K210_PCF_DVP_RST        133 /* DVP System Reset */
+#define K210_PCF_DVP_PWDN       134 /* DVP Power Down Mode */
+#define K210_PCF_DVP_VSYNC      135 /* DVP Vertical Sync */
+#define K210_PCF_DVP_HSYNC      136 /* DVP Horizontal Sync */
+#define K210_PCF_DVP_PCLK       137 /* Pixel Clock */
+#define K210_PCF_DVP_D0         138 /* Data Bit 0 */
+#define K210_PCF_DVP_D1         139 /* Data Bit 1 */
+#define K210_PCF_DVP_D2         140 /* Data Bit 2 */
+#define K210_PCF_DVP_D3         141 /* Data Bit 3 */
+#define K210_PCF_DVP_D4         142 /* Data Bit 4 */
+#define K210_PCF_DVP_D5         143 /* Data Bit 5 */
+#define K210_PCF_DVP_D6         144 /* Data Bit 6 */
+#define K210_PCF_DVP_D7         145 /* Data Bit 7 */
+#define K210_PCF_SCCB_SCLK      146 /* Serial Camera Control Bus Clock */
+#define K210_PCF_SCCB_SDA       147 /* Serial Camera Control Bus Data */
+#define K210_PCF_UART1_CTS      148 /* UART1 Clear To Send */
+#define K210_PCF_UART1_DSR      149 /* UART1 Data Set Ready */
+#define K210_PCF_UART1_DCD      150 /* UART1 Data Carrier Detect */
+#define K210_PCF_UART1_RI       151 /* UART1 Ring Indicator */
+#define K210_PCF_UART1_SIR_IN   152 /* UART1 Serial Infrared Input */
+#define K210_PCF_UART1_DTR      153 /* UART1 Data Terminal Ready */
+#define K210_PCF_UART1_RTS      154 /* UART1 Request To Send */
+#define K210_PCF_UART1_OUT2     155 /* UART1 User-designated Output 2 */
+#define K210_PCF_UART1_OUT1     156 /* UART1 User-designated Output 1 */
+#define K210_PCF_UART1_SIR_OUT  157 /* UART1 Serial Infrared Output */
+#define K210_PCF_UART1_BAUD     158 /* UART1 Transmit Clock Output */
+#define K210_PCF_UART1_RE       159 /* UART1 Receiver Output Enable */
+#define K210_PCF_UART1_DE       160 /* UART1 Driver Output Enable */
+#define K210_PCF_UART1_RS485_EN 161 /* UART1 RS485 Enable */
+#define K210_PCF_UART2_CTS      162 /* UART2 Clear To Send */
+#define K210_PCF_UART2_DSR      163 /* UART2 Data Set Ready */
+#define K210_PCF_UART2_DCD      164 /* UART2 Data Carrier Detect */
+#define K210_PCF_UART2_RI       165 /* UART2 Ring Indicator */
+#define K210_PCF_UART2_SIR_IN   166 /* UART2 Serial Infrared Input */
+#define K210_PCF_UART2_DTR      167 /* UART2 Data Terminal Ready */
+#define K210_PCF_UART2_RTS      168 /* UART2 Request To Send */
+#define K210_PCF_UART2_OUT2     169 /* UART2 User-designated Output 2 */
+#define K210_PCF_UART2_OUT1     170 /* UART2 User-designated Output 1 */
+#define K210_PCF_UART2_SIR_OUT  171 /* UART2 Serial Infrared Output */
+#define K210_PCF_UART2_BAUD     172 /* UART2 Transmit Clock Output */
+#define K210_PCF_UART2_RE       173 /* UART2 Receiver Output Enable */
+#define K210_PCF_UART2_DE       174 /* UART2 Driver Output Enable */
+#define K210_PCF_UART2_RS485_EN 175 /* UART2 RS485 Enable */
+#define K210_PCF_UART3_CTS      176 /* UART3 Clear To Send */
+#define K210_PCF_UART3_DSR      177 /* UART3 Data Set Ready */
+#define K210_PCF_UART3_DCD      178 /* UART3 Data Carrier Detect */
+#define K210_PCF_UART3_RI       179 /* UART3 Ring Indicator */
+#define K210_PCF_UART3_SIR_IN   180 /* UART3 Serial Infrared Input */
+#define K210_PCF_UART3_DTR      181 /* UART3 Data Terminal Ready */
+#define K210_PCF_UART3_RTS      182 /* UART3 Request To Send */
+#define K210_PCF_UART3_OUT2     183 /* UART3 User-designated Output 2 */
+#define K210_PCF_UART3_OUT1     184 /* UART3 User-designated Output 1 */
+#define K210_PCF_UART3_SIR_OUT  185 /* UART3 Serial Infrared Output */
+#define K210_PCF_UART3_BAUD     186 /* UART3 Transmit Clock Output */
+#define K210_PCF_UART3_RE       187 /* UART3 Receiver Output Enable */
+#define K210_PCF_UART3_DE       188 /* UART3 Driver Output Enable */
+#define K210_PCF_UART3_RS485_EN 189 /* UART3 RS485 Enable */
+#define K210_PCF_TIMER0_TOGGLE1 190 /* TIMER0 Toggle Output 1 */
+#define K210_PCF_TIMER0_TOGGLE2 191 /* TIMER0 Toggle Output 2 */
+#define K210_PCF_TIMER0_TOGGLE3 192 /* TIMER0 Toggle Output 3 */
+#define K210_PCF_TIMER0_TOGGLE4 193 /* TIMER0 Toggle Output 4 */
+#define K210_PCF_TIMER1_TOGGLE1 194 /* TIMER1 Toggle Output 1 */
+#define K210_PCF_TIMER1_TOGGLE2 195 /* TIMER1 Toggle Output 2 */
+#define K210_PCF_TIMER1_TOGGLE3 196 /* TIMER1 Toggle Output 3 */
+#define K210_PCF_TIMER1_TOGGLE4 197 /* TIMER1 Toggle Output 4 */
+#define K210_PCF_TIMER2_TOGGLE1 198 /* TIMER2 Toggle Output 1 */
+#define K210_PCF_TIMER2_TOGGLE2 199 /* TIMER2 Toggle Output 2 */
+#define K210_PCF_TIMER2_TOGGLE3 200 /* TIMER2 Toggle Output 3 */
+#define K210_PCF_TIMER2_TOGGLE4 201 /* TIMER2 Toggle Output 4 */
+#define K210_PCF_CLK_SPI2       202 /* Clock SPI2 */
+#define K210_PCF_CLK_I2C2       203 /* Clock I2C2 */
+#define K210_PCF_INTERNAL0      204 /* Internal function signal 0 */
+#define K210_PCF_INTERNAL1      205 /* Internal function signal 1 */
+#define K210_PCF_INTERNAL2      206 /* Internal function signal 2 */
+#define K210_PCF_INTERNAL3      207 /* Internal function signal 3 */
+#define K210_PCF_INTERNAL4      208 /* Internal function signal 4 */
+#define K210_PCF_INTERNAL5      209 /* Internal function signal 5 */
+#define K210_PCF_INTERNAL6      210 /* Internal function signal 6 */
+#define K210_PCF_INTERNAL7      211 /* Internal function signal 7 */
+#define K210_PCF_INTERNAL8      212 /* Internal function signal 8 */
+#define K210_PCF_INTERNAL9      213 /* Internal function signal 9 */
+#define K210_PCF_INTERNAL10     214 /* Internal function signal 10 */
+#define K210_PCF_INTERNAL11     215 /* Internal function signal 11 */
+#define K210_PCF_INTERNAL12     216 /* Internal function signal 12 */
+#define K210_PCF_INTERNAL13     217 /* Internal function signal 13 */
+#define K210_PCF_INTERNAL14     218 /* Internal function signal 14 */
+#define K210_PCF_INTERNAL15     219 /* Internal function signal 15 */
+#define K210_PCF_INTERNAL16     220 /* Internal function signal 16 */
+#define K210_PCF_INTERNAL17     221 /* Internal function signal 17 */
+#define K210_PCF_CONSTANT       222 /* Constant function */
+#define K210_PCF_INTERNAL18     223 /* Internal function signal 18 */
+#define K210_PCF_DEBUG0         224 /* Debug function 0 */
+#define K210_PCF_DEBUG1         225 /* Debug function 1 */
+#define K210_PCF_DEBUG2         226 /* Debug function 2 */
+#define K210_PCF_DEBUG3         227 /* Debug function 3 */
+#define K210_PCF_DEBUG4         228 /* Debug function 4 */
+#define K210_PCF_DEBUG5         229 /* Debug function 5 */
+#define K210_PCF_DEBUG6         230 /* Debug function 6 */
+#define K210_PCF_DEBUG7         231 /* Debug function 7 */
+#define K210_PCF_DEBUG8         232 /* Debug function 8 */
+#define K210_PCF_DEBUG9         233 /* Debug function 9 */
+#define K210_PCF_DEBUG10        234 /* Debug function 10 */
+#define K210_PCF_DEBUG11        235 /* Debug function 11 */
+#define K210_PCF_DEBUG12        236 /* Debug function 12 */
+#define K210_PCF_DEBUG13        237 /* Debug function 13 */
+#define K210_PCF_DEBUG14        238 /* Debug function 14 */
+#define K210_PCF_DEBUG15        239 /* Debug function 15 */
+#define K210_PCF_DEBUG16        240 /* Debug function 16 */
+#define K210_PCF_DEBUG17        241 /* Debug function 17 */
+#define K210_PCF_DEBUG18        242 /* Debug function 18 */
+#define K210_PCF_DEBUG19        243 /* Debug function 19 */
+#define K210_PCF_DEBUG20        244 /* Debug function 20 */
+#define K210_PCF_DEBUG21        245 /* Debug function 21 */
+#define K210_PCF_DEBUG22        246 /* Debug function 22 */
+#define K210_PCF_DEBUG23        247 /* Debug function 23 */
+#define K210_PCF_DEBUG24        248 /* Debug function 24 */
+#define K210_PCF_DEBUG25        249 /* Debug function 25 */
+#define K210_PCF_DEBUG26        250 /* Debug function 26 */
+#define K210_PCF_DEBUG27        251 /* Debug function 27 */
+#define K210_PCF_DEBUG28        252 /* Debug function 28 */
+#define K210_PCF_DEBUG29        253 /* Debug function 29 */
+#define K210_PCF_DEBUG30        254 /* Debug function 30 */
+#define K210_PCF_DEBUG31        255 /* Debug function 31 */
+
+#define K210_FPIOA(pin, func) (((pin) << 16) | (func))
+#define K210_FPIOA_DO(pin, func) (((pin) << 16) | (1 << 8) | (func))
+
+#define K210_PC_POWER_3V3 0
+#define K210_PC_POWER_1V8 1
+
+#endif /* DT_K210_PINCTRL_H */

+ 19 - 0
include/dt-bindings/pinctrl/sandbox-pinmux.h

@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef SANDBOX_PINMUX_H
+#define SANDBOX_PINMUX_H
+
+#define SANDBOX_PINMUX_UART 0
+#define SANDBOX_PINMUX_I2C  1
+#define SANDBOX_PINMUX_SPI  2
+#define SANDBOX_PINMUX_I2S  3
+#define SANDBOX_PINMUX_GPIO 4
+#define SANDBOX_PINMUX_CS   5
+#define SANDBOX_PINMUX_PWM  6
+
+#define SANDBOX_PINMUX(pin, func) ((func) << 16 | (pin))
+
+#endif /* SANDBOX_PINMUX_H */

+ 3 - 0
test/dm/Makefile

@@ -81,4 +81,7 @@ obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o
 obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
 obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
 obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
+ifneq ($(CONFIG_PINMUX),)
+obj-$(CONFIG_PINCONF) += pinmux.o
+endif
 endif

+ 2 - 1
test/dm/led.c

@@ -40,7 +40,8 @@ static int dm_test_led_default_state(struct unit_test_state *uts)
 	ut_assertok(led_get_by_label("sandbox:default_on", &dev));
 	ut_asserteq(LEDST_ON, led_get_state(dev));
 
-	ut_assertok(led_get_by_label("sandbox:default_off", &dev));
+	/* Also tests default label behaviour */
+	ut_assertok(led_get_by_label("default_off", &dev));
 	ut_asserteq(LEDST_OFF, led_get_state(dev));
 
 	return 0;

+ 57 - 0
test/dm/pinmux.c

@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int dm_test_pinmux(struct unit_test_state *uts)
+{
+	char buf[64];
+	struct udevice *dev;
+
+#define test_muxing(selector, expected) do { \
+	ut_assertok(pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf))); \
+	ut_asserteq_str(expected, (char *)&buf); \
+} while (0)
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, "pinctrl", &dev));
+	test_muxing(0, "UART TX.");
+	test_muxing(1, "UART RX.");
+	test_muxing(2, "I2S SCK.");
+	test_muxing(3, "I2S SD.");
+	test_muxing(4, "I2S WS.");
+	test_muxing(5, "GPIO0 bias-pull-up input-disable.");
+	test_muxing(6, "GPIO1 drive-open-drain.");
+	test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+	test_muxing(8, "GPIO3 bias-disable.");
+
+	ut_assertok(pinctrl_select_state(dev, "alternate"));
+	test_muxing(0, "I2C SCL drive-open-drain.");
+	test_muxing(1, "I2C SDA drive-open-drain.");
+	test_muxing(2, "SPI SCLK.");
+	test_muxing(3, "SPI MOSI.");
+	test_muxing(4, "SPI MISO.");
+	test_muxing(5, "SPI CS0.");
+	test_muxing(6, "SPI CS1.");
+	test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+	test_muxing(8, "GPIO3 bias-disable.");
+
+	ut_assertok(pinctrl_select_state(dev, "0"));
+	test_muxing(0, "I2C SCL drive-open-drain.");
+	test_muxing(1, "I2C SDA drive-open-drain.");
+	test_muxing(2, "I2S SCK.");
+	test_muxing(3, "I2S SD.");
+	test_muxing(4, "I2S WS.");
+	test_muxing(5, "GPIO0 bias-pull-up input-disable.");
+	test_muxing(6, "GPIO1 drive-open-drain.");
+	test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+	test_muxing(8, "GPIO3 bias-disable.");
+
+	return 0;
+}
+DM_TEST(dm_test_pinmux, UT_TESTF_SCAN_FDT);

+ 18 - 18
test/py/tests/test_pinmux.py

@@ -28,15 +28,15 @@ def test_pinmux_status_all(u_boot_console):
     assert ('a6        : gpio output .' in output)
 
     assert ('pinctrl:' in output)
-    assert ('SCL       : I2C SCL.' in output)
-    assert ('SDA       : I2C SDA.' in output)
-    assert ('TX        : Uart TX.' in output)
-    assert ('RX        : Uart RX.' in output)
-    assert ('W1        : 1-wire gpio.' in output)
-    assert ('GPIO0     : gpio bias-pull-up input-disable.' in output)
-    assert ('GPIO1     : gpio drive-open-drain.' in output)
-    assert ('GPIO2     : gpio bias-pull-down input-enable.' in output)
-    assert ('GPIO3     : gpio bias-disable.' in output)
+    assert ('P0        : UART TX.' in output)
+    assert ('P1        : UART RX.' in output)
+    assert ('P2        : I2S SCK.' in output)
+    assert ('P3        : I2S SD.' in output)
+    assert ('P4        : I2S WS.' in output)
+    assert ('P5        : GPIO0 bias-pull-up input-disable.' in output)
+    assert ('P6        : GPIO1 drive-open-drain.' in output)
+    assert ('P7        : GPIO2 bias-pull-down input-enable.' in output)
+    assert ('P8        : GPIO3 bias-disable.' in output)
 
 @pytest.mark.buildconfigspec('cmd_pinmux')
 @pytest.mark.boardspec('sandbox')
@@ -73,12 +73,12 @@ def test_pinmux_status(u_boot_console):
     assert (not 'pinctrl-gpio:' in output)
     assert (not 'pinctrl:' in output)
 
-    assert ('SCL       : I2C SCL.' in output)
-    assert ('SDA       : I2C SDA.' in output)
-    assert ('TX        : Uart TX.' in output)
-    assert ('RX        : Uart RX.' in output)
-    assert ('W1        : 1-wire gpio.' in output)
-    assert ('GPIO0     : gpio bias-pull-up input-disable.' in output)
-    assert ('GPIO1     : gpio drive-open-drain.' in output)
-    assert ('GPIO2     : gpio bias-pull-down input-enable.' in output)
-    assert ('GPIO3     : gpio bias-disable.' in output)
+    assert ('P0        : UART TX.' in output)
+    assert ('P1        : UART RX.' in output)
+    assert ('P2        : I2S SCK.' in output)
+    assert ('P3        : I2S SD.' in output)
+    assert ('P4        : I2S WS.' in output)
+    assert ('P5        : GPIO0 bias-pull-up input-disable.' in output)
+    assert ('P6        : GPIO1 drive-open-drain.' in output)
+    assert ('P7        : GPIO2 bias-pull-down input-enable.' in output)
+    assert ('P8        : GPIO3 bias-disable.' in output)