]> Git Repo - u-boot.git/commitdiff
k210: use the board vendor name rather than the marketing name
authorDamien Le Moal <[email protected]>
Tue, 1 Mar 2022 10:35:39 +0000 (10:35 +0000)
committerLeo Yu-Chi Liang <[email protected]>
Tue, 15 Mar 2022 09:43:11 +0000 (17:43 +0800)
"kendryte" is the marketing name for the K210 RISC-V SoC produced by
Canaan Inc. Rather than "kendryte,k210", use the usual "canaan,k210"
vendor,SoC compatibility string format in the device tree files and
use the SoC name for file names.
With these changes, the device tree files are more in sync with the
Linux kernel DTS and drivers, making uboot device tree usable by the
kernel.

Signed-off-by: Damien Le Moal <[email protected]>
Signed-off-by: Niklas Cassel <[email protected]>
Reviewed-by: Leo Yu-Chi Liang <[email protected]>
21 files changed:
MAINTAINERS
arch/riscv/dts/k210-maix-bit.dts
arch/riscv/dts/k210.dtsi
board/sipeed/maix/maix.c
doc/board/sipeed/maix.rst
doc/device-tree-bindings/mfd/canaan,k210-sysctl.txt [new file with mode: 0644]
doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt [deleted file]
doc/device-tree-bindings/pinctrl/canaan,k210-fpioa.txt [new file with mode: 0644]
doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt [deleted file]
doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt
drivers/clk/Makefile
drivers/clk/clk_k210.c [new file with mode: 0644]
drivers/clk/clk_kendryte.c [deleted file]
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-k210.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-kendryte.c [deleted file]
drivers/spi/designware_spi.c
include/configs/sipeed-maix.h
include/k210/pll.h [new file with mode: 0644]
include/kendryte/pll.h [deleted file]
test/dm/k210_pll.c

index 82fc49e31d4fdc848d83dd971953ac9a298616a4..8defd09a645bc68a515d45dfa09f97c401bcbe40 100644 (file)
@@ -1115,14 +1115,14 @@ F:      drivers/timer/andes_plmt_timer.c
 F:     drivers/timer/sifive_clint_timer.c
 F:     tools/prelink-riscv.c
 
-RISC-V KENDRYTE
+RISC-V CANAAN KENDRYTE K210
 M:     Sean Anderson <[email protected]>
 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/clk_kendryte.c
-F:     drivers/pinctrl/pinctrl-kendryte.c
-F:     include/kendryte/
+F:     doc/device-tree-bindings/mfd/canaan,k210-sysctl.txt
+F:     doc/device-tree-bindings/pinctrl/canaan,k210-fpioa.txt
+F:     drivers/clk/clk_k210.c
+F:     drivers/pinctrl/pinctrl-k210.c
+F:     include/k210/
 
 RNG
 M:     Sughosh Ganu <[email protected]>
index 902dcfd08a9894afbf92e8901149e904b1f09d0c..c4bbf6b0186aaaf5e71047f5aa94dce19dbd3886 100644 (file)
@@ -12,7 +12,8 @@
 
 / {
        model = "Sipeed Maix Bit 2.0";
-       compatible = "sipeed,maix-bitm", "sipeed,maix-bit", "kendryte,k210";
+       compatible = "sipeed,maix-bitm", "sipeed,maix-bit",
+                    "canaan,kendryte-k210";
 
        chosen {
                stdout-path = "serial0:115200";
index 8bcd3cebdef741ca13c58e153938b6bd7d73d8ce..7dc2785a3e10fc4fd858ae1c89044f40ce074838 100644 (file)
@@ -15,7 +15,7 @@
         */
        #address-cells = <1>;
        #size-cells = <1>;
-       compatible = "kendryte,k210";
+       compatible = "canaan,kendryte-k210";
 
        aliases {
                cpu0 = &cpu0;
@@ -46,7 +46,7 @@
                timebase-frequency = <7800000>;
                cpu0: cpu@0 {
                        device_type = "cpu";
-                       compatible = "kendryte,k210", "sifive,rocket0", "riscv";
+                       compatible = "canaan,k210", "sifive,rocket0", "riscv";
                        reg = <0>;
                        riscv,isa = "rv64imafdgc";
                        mmu-type = "sv39";
@@ -63,7 +63,7 @@
                };
                cpu1: cpu@1 {
                        device_type = "cpu";
-                       compatible = "kendryte,k210", "sifive,rocket0", "riscv";
+                       compatible = "canaan,k210", "sifive,rocket0", "riscv";
                        reg = <1>;
                        riscv,isa = "rv64imafdgc";
                        mmu-type = "sv39";
@@ -82,7 +82,7 @@
 
        sram: memory@80000000 {
                device_type = "memory";
-               compatible = "kendryte,k210-sram";
+               compatible = "canaan,k210-sram";
                reg = <0x80000000 0x400000>,
                      <0x80400000 0x200000>,
                      <0x80600000 0x200000>;
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "kendryte,k210-soc", "simple-bus";
+               compatible = "canaan,k210-soc", "simple-bus";
                ranges;
                interrupt-parent = <&plic0>;
 
                debug0: debug@0 {
-                       compatible = "kendryte,k210-debug", "riscv,debug";
+                       compatible = "canaan,k210-debug", "riscv,debug";
                        reg = <0x0 0x1000>;
                };
 
 
                clint0: clint@2000000 {
                        #interrupt-cells = <1>;
-                       compatible = "kendryte,k210-clint", "riscv,clint0";
+                       compatible = "canaan,k210-clint", "sifive,clint0", "riscv,clint0";
                        reg = <0x2000000 0xC000>;
                        interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
                                              <&cpu1_intc 3>, <&cpu1_intc 7>;
 
                plic0: interrupt-controller@C000000 {
                        #interrupt-cells = <1>;
-                       compatible = "kendryte,k210-plic", "riscv,plic0";
+                       compatible = "canaan,k210-plic", "sifive,plic-1.0.0", "riscv,plic0";
                        reg = <0xC000000 0x4000000>;
                        interrupt-controller;
                        interrupts-extended = <&cpu0_intc 9>, <&cpu0_intc 11>,
                };
 
                uarths0: serial@38000000 {
-                       compatible = "kendryte,k210-uarths", "sifive,uart0";
+                       compatible = "canaan,k210-uarths", "sifive,uart0";
                        reg = <0x38000000 0x1000>;
                        interrupts = <33>;
                        clocks = <&sysclk K210_CLK_CPU>;
                gpio0: gpio-controller@38001000 {
                        #interrupt-cells = <2>;
                        #gpio-cells = <2>;
-                       compatible = "kendryte,k210-gpiohs", "sifive,gpio0";
+                       compatible = "canaan,k210-gpiohs", "sifive,gpio0";
                        reg = <0x38001000 0x1000>;
                        interrupt-controller;
                        interrupts = <34 35 36 37 38 39 40 41
                };
 
                kpu0: kpu@40800000 {
-                       compatible = "kendryte,k210-kpu";
+                       compatible = "canaan,k210-kpu";
                        reg = <0x40800000 0xc00000>;
                        interrupts = <25>;
                        clocks = <&sysclk K210_CLK_AI>;
                };
 
                fft0: fft@42000000 {
-                       compatible = "kendryte,k210-fft";
+                       compatible = "canaan,k210-fft";
                        reg = <0x42000000 0x400000>;
                        interrupts = <26>;
                        clocks = <&sysclk K210_CLK_FFT>;
                };
 
                dmac0: dma-controller@50000000 {
-                       compatible = "kendryte,k210-dmac", "snps,axi-dma-1.01a";
+                       compatible = "canaan,k210-dmac", "snps,axi-dma-1.01a";
                        reg = <0x50000000 0x1000>;
                        interrupts = <27 28 29 30 31 32>;
                        clocks = <&sysclk K210_CLK_DMA>, <&sysclk K210_CLK_DMA>;
                apb0: bus@50200000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       compatible = "kendryte,k210-apb", "simple-pm-bus";
+                       compatible = "canaan,k210-apb", "simple-pm-bus";
                        ranges;
                        clocks = <&sysclk K210_CLK_APB0>;
 
                        gpio1: gpio-controller@50200000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "kendryte,k210-gpio",
+                               compatible = "canaan,k210-gpio",
                                             "snps,dw-apb-gpio";
                                reg = <0x50200000 0x80>;
                                clocks = <&sysclk K210_CLK_GPIO>;
                        };
 
                        uart1: serial@50210000 {
-                               compatible = "kendryte,k210-uart",
+                               compatible = "canaan,k210-uart",
                                             "snps,dw-apb-uart";
                                reg = <0x50210000 0x100>;
                                interrupts = <11>;
                        };
 
                        uart2: serial@50220000 {
-                               compatible = "kendryte,k210-uart",
+                               compatible = "canaan,k210-uart",
                                             "snps,dw-apb-uart";
                                reg = <0x50220000 0x100>;
                                interrupts = <12>;
                        };
 
                        uart3: serial@50230000 {
-                               compatible = "kendryte,k210-uart",
+                               compatible = "canaan,k210-uart",
                                             "snps,dw-apb-uart";
                                reg = <0x50230000 0x100>;
                                interrupts = <13>;
                        };
 
                        spi2: spi@50240000 {
-                               compatible = "canaan,kendryte-k210-spi",
+                               compatible = "canaan,k210-spi",
                                             "snps,dw-apb-ssi-4.01",
                                             "snps,dw-apb-ssi";
                                spi-slave;
                        };
 
                        i2s0: i2s@50250000 {
-                               compatible = "kendryte,k210-i2s",
+                               compatible = "canaan,k210-i2s",
                                             "snps,designware-i2s";
                                reg = <0x50250000 0x200>;
                                interrupts = <5>;
                        };
 
                        apu0: sound@520250200 {
-                               compatible = "kendryte,k210-apu";
+                               compatible = "canaan,k210-apu";
                                reg = <0x50250200 0x200>;
                                status = "disabled";
                        };
 
                        i2s1: i2s@50260000 {
-                               compatible = "kendryte,k210-i2s",
+                               compatible = "canaan,k210-i2s",
                                             "snps,designware-i2s";
                                reg = <0x50260000 0x200>;
                                interrupts = <6>;
                        };
 
                        i2s2: i2s@50270000 {
-                               compatible = "kendryte,k210-i2s",
+                               compatible = "canaan,k210-i2s",
                                             "snps,designware-i2s";
                                reg = <0x50270000 0x200>;
                                interrupts = <7>;
                        };
 
                        i2c0: i2c@50280000 {
-                               compatible = "kendryte,k210-i2c",
+                               compatible = "canaan,k210-i2c",
                                             "snps,designware-i2c";
                                reg = <0x50280000 0x100>;
                                interrupts = <8>;
                        };
 
                        i2c1: i2c@50290000 {
-                               compatible = "kendryte,k210-i2c",
+                               compatible = "canaan,k210-i2c",
                                             "snps,designware-i2c";
                                reg = <0x50290000 0x100>;
                                interrupts = <9>;
                        };
 
                        i2c2: i2c@502A0000 {
-                               compatible = "kendryte,k210-i2c",
+                               compatible = "canaan,k210-i2c",
                                             "snps,designware-i2c";
                                reg = <0x502A0000 0x100>;
                                interrupts = <10>;
                        };
 
                        fpioa: pinmux@502B0000 {
-                               compatible = "kendryte,k210-fpioa";
+                               compatible = "canaan,k210-fpioa";
                                reg = <0x502B0000 0x100>;
                                clocks = <&sysclk K210_CLK_FPIOA>;
                                resets = <&sysrst K210_RST_FPIOA>;
-                               kendryte,sysctl = <&sysctl>;
-                               kendryte,power-offset = <K210_SYSCTL_POWER_SEL>;
+                               canaan,k210-sysctl = <&sysctl>;
+                               canaan,k210-power-offset = <K210_SYSCTL_POWER_SEL>;
                                pinctrl-0 = <&fpioa_jtag>;
                                pinctrl-names = "default";
                                status = "disabled";
                        };
 
                        sha256: sha256@502C0000 {
-                               compatible = "kendryte,k210-sha256";
+                               compatible = "canaan,k210-sha256";
                                reg = <0x502C0000 0x100>;
                                clocks = <&sysclk K210_CLK_SHA>;
                                resets = <&sysrst K210_RST_SHA>;
                        };
 
                        timer0: timer@502D0000 {
-                               compatible = "kendryte,k210-timer",
+                               compatible = "canaan,k210-timer",
                                             "snps,dw-apb-timer";
                                reg = <0x502D0000 0x100>;
                                interrupts = <14 15>;
                        };
 
                        timer1: timer@502E0000 {
-                               compatible = "kendryte,k210-timer",
+                               compatible = "canaan,k210-timer",
                                             "snps,dw-apb-timer";
                                reg = <0x502E0000 0x100>;
                                interrupts = <16 17>;
                        };
 
                        timer2: timer@502F0000 {
-                               compatible = "kendryte,k210-timer",
+                               compatible = "canaan,k210-timer",
                                             "snps,dw-apb-timer";
                                reg = <0x502F0000 0x100>;
                                interrupts = <18 19>;
                apb1: bus@50400000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       compatible = "kendryte,k210-apb", "simple-pm-bus";
+                       compatible = "canaan,k210-apb", "simple-pm-bus";
                        ranges;
                        clocks = <&sysclk K210_CLK_APB1>;
 
                        wdt0: watchdog@50400000 {
-                               compatible = "kendryte,k210-wdt", "snps,dw-wdt";
+                               compatible = "canaan,k210-wdt", "snps,dw-wdt";
                                reg = <0x50400000 0x100>;
                                interrupts = <21>;
                                clocks = <&sysclk K210_CLK_WDT0>;
                        };
 
                        wdt1: watchdog@50410000 {
-                               compatible = "kendryte,k210-wdt", "snps,dw-wdt";
+                               compatible = "canaan,k210-wdt", "snps,dw-wdt";
                                reg = <0x50410000 0x100>;
                                interrupts = <22>;
                                clocks = <&sysclk K210_CLK_WDT1>;
                        otp0: nvmem@50420000 {
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               compatible = "kendryte,k210-otp";
+                               compatible = "canaan,k210-otp";
                                reg = <0x50420000 0x100>,
                                      <0x88000000 0x20000>;
                                reg-names = "reg", "mem";
                        };
 
                        dvp0: camera@50430000 {
-                               compatible = "kendryte,k210-dvp";
+                               compatible = "canaan,k210-dvp";
                                reg = <0x50430000 0x100>;
                                interrupts = <24>;
                                clocks = <&sysclk K210_CLK_DVP>;
                                resets = <&sysrst K210_RST_DVP>;
-                               kendryte,sysctl = <&sysctl>;
-                               kendryte,misc-offset = <K210_SYSCTL_MISC>;
+                               canaan,k210-sysctl = <&sysctl>;
+                               canaan,k210-misc-offset = <K210_SYSCTL_MISC>;
                                status = "disabled";
                        };
 
                        sysctl: syscon@50440000 {
-                               compatible = "kendryte,k210-sysctl",
+                               compatible = "canaan,k210-sysctl",
                                             "syscon", "simple-mfd";
                                reg = <0x50440000 0x100>;
                                reg-io-width = <4>;
 
                                sysclk: clock-controller {
                                        #clock-cells = <1>;
-                                       compatible = "kendryte,k210-clk";
+                                       compatible = "canaan,k210-clk";
                                        clocks = <&in0>;
                                        assigned-clocks = <&sysclk K210_CLK_PLL1>;
                                        assigned-clock-rates = <390000000>;
                                };
 
                                sysrst: reset-controller {
-                                       compatible = "kendryte,k210-rst",
+                                       compatible = "canaan,k210-rst",
                                                     "syscon-reset";
                                        #reset-cells = <1>;
                                        regmap = <&sysctl>;
                        };
 
                        aes0: aes@50450000 {
-                               compatible = "kendryte,k210-aes";
+                               compatible = "canaan,k210-aes";
                                reg = <0x50450000 0x100>;
                                clocks = <&sysclk K210_CLK_AES>;
                                resets = <&sysrst K210_RST_AES>;
                        };
 
                        rtc: rtc@50460000 {
-                               compatible = "kendryte,k210-rtc";
+                               compatible = "canaan,k210-rtc";
                                reg = <0x50460000 0x100>;
                                clocks = <&in0>;
                                resets = <&sysrst K210_RST_RTC>;
                apb2: bus@52000000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       compatible = "kendryte,k210-apb", "simple-pm-bus";
+                       compatible = "canaan,k210-apb", "simple-pm-bus";
                        ranges;
                        clocks = <&sysclk K210_CLK_APB2>;
 
                        spi0: spi@52000000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "canaan,kendryte-k210-spi",
+                               compatible = "canaan,k210-spi",
                                             "snps,dw-apb-ssi-4.01",
                                             "snps,dw-apb-ssi";
                                reg = <0x52000000 0x100>;
                        spi1: spi@53000000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "canaan,kendryte-k210-spi",
+                               compatible = "canaan,k210-spi",
                                             "snps,dw-apb-ssi-4.01",
                                             "snps,dw-apb-ssi";
                                reg = <0x53000000 0x100>;
                        spi3: spi@54000000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "canaan,kendryte-k210-ssi",
+                               compatible = "canaan,k210-ssi",
                                             "snps,dwc-ssi-1.01a";
                                reg = <0x54000000 0x200>;
                                interrupts = <4>;
index 52e4fee2f0acf6b556274bc3625752e97da5bb55..a218278cb34ef138707ab3d1a9569b8b8e7840b1 100644 (file)
@@ -22,7 +22,7 @@ static int sram_init(void)
        struct clk clk;
 
        /* Enable RAM clocks */
-       memory = ofnode_by_compatible(ofnode_null(), "kendryte,k210-sram");
+       memory = ofnode_by_compatible(ofnode_null(), "canaan,k210-sram");
        if (ofnode_equal(memory, ofnode_null()))
                return -ENOENT;
 
index ef79297ef00eed64ceab5c84fbb8590095ab7190..903f8831d70f80e95656214c34168d11428deea5 100644 (file)
@@ -4,16 +4,16 @@
 MAIX
 ====
 
-Several of the Sipeed Maix series of boards cotain the Kendryte K210 processor,
-a 64-bit RISC-V CPU. This processor contains several peripherals to accelerate
-neural network processing and other "ai" tasks. This includes a "KPU" neural
-network processor, an audio processor supporting beamforming reception, and a
-digital video port supporting capture and output at VGA resolution. Other
-peripherals include 8M of SRAM (accessible with and without caching); remappable
-pins, including 40 GPIOs; AES, FFT, and SHA256 accelerators; a DMA controller;
-and I2C, I2S, and SPI controllers. Maix peripherals vary, but include spi flash;
-on-board usb-serial bridges; ports for cameras, displays, and sd cards; and
-ESP32 chips.
+Several of the Sipeed Maix series of boards contain the Kendryte K210 processor,
+a 64-bit RISC-V CPU produced by Canaan Inc. This processor contains several
+peripherals to accelerate neural network processing and other "ai" tasks. This
+includes a "KPU" neural network processor, an audio processor supporting
+beamforming reception, and a digital video port supporting capture and output at
+VGA resolution. Other peripherals include 8M of SRAM (accessible with and
+without caching); remappable pins, including 40 GPIOs; AES, FFT, and SHA256
+accelerators; a DMA controller; and I2C, I2S, and SPI controllers. Maix
+peripherals vary, but include spi flash; on-board usb-serial bridges; ports for
+cameras, displays, and sd cards; and ESP32 chips.
 
 Currently, only the Sipeed MAIX BiT V2.0 (bitm) and Sipeed MAIXDUINO are
 supported, but the boards are fairly similar.
diff --git a/doc/device-tree-bindings/mfd/canaan,k210-sysctl.txt b/doc/device-tree-bindings/mfd/canaan,k210-sysctl.txt
new file mode 100644 (file)
index 0000000..e48b164
--- /dev/null
@@ -0,0 +1,33 @@
+Kendryte K210 Sysctl
+
+This binding describes the K210 sysctl device, which contains many miscellaneous
+registers controlling system functionality. This node is a register map and can
+be reference by other bindings which need a phandle to the K210 sysctl regmap.
+
+Required properties:
+- compatible: should be
+       "canaan,k210-sysctl", "syscon", "simple-mfd"
+- reg: address and length of the sysctl registers
+- reg-io-width: must be <4>
+
+Clock sub-node
+
+This node is a binding for the clock tree driver
+
+Required properties:
+- compatible: should be "canaan,k210-clk"
+- clocks: phandle to the "in0" external oscillator
+- #clock-cells: must be <1>
+
+Example:
+sysctl: syscon@50440000 {
+       compatible = "canaan,k210-sysctl", "syscon", "simple-mfd";
+       reg = <0x50440000 0x100>;
+       reg-io-width = <4>;
+
+       sysclk: clock-controller {
+               compatible = "canaan,k210-clk";
+               clocks = <&in0>;
+               #clock-cells = <1>;
+       };
+};
diff --git a/doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt b/doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
deleted file mode 100644 (file)
index 5b24abc..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Kendryte K210 Sysctl
-
-This binding describes the K210 sysctl device, which contains many miscellaneous
-registers controlling system functionality. This node is a register map and can
-be reference by other bindings which need a phandle to the K210 sysctl regmap.
-
-Required properties:
-- compatible: should be
-       "kendryte,k210-sysctl", "syscon", "simple-mfd"
-- reg: address and length of the sysctl registers
-- reg-io-width: must be <4>
-
-Clock sub-node
-
-This node is a binding for the clock tree driver
-
-Required properties:
-- compatible: should be "kendryte,k210-clk"
-- clocks: phandle to the "in0" external oscillator
-- #clock-cells: must be <1>
-
-Example:
-sysctl: syscon@50440000 {
-       compatible = "kendryte,k210-sysctl", "syscon", "simple-mfd";
-       reg = <0x50440000 0x100>;
-       reg-io-width = <4>;
-
-       sysclk: clock-controller {
-               compatible = "kendryte,k210-clk";
-               clocks = <&in0>;
-               #clock-cells = <1>;
-       };
-};
diff --git a/doc/device-tree-bindings/pinctrl/canaan,k210-fpioa.txt b/doc/device-tree-bindings/pinctrl/canaan,k210-fpioa.txt
new file mode 100644 (file)
index 0000000..deca0cf
--- /dev/null
@@ -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 "canaan,k210-fpioa"
+- reg: address and length of the FPIOA registers
+- canaan,sysctl: phandle to the "sysctl" register map node
+- canaan,k210-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, B3, B4, B5, C6, C7
+  (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 = "canaan,k210-fpioa";
+       reg = <0x502B0000 0x100>;
+       canaan,k210-sysctl = <&sysctl>;
+       canaan,k210-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)>;
+               };
+       };
+};
diff --git a/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt b/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
deleted file mode 100644 (file)
index 73871f5..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-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, B3, B4, B5, C6, C7
-  (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)>;
-               };
-       };
-};
index 8d2888fbe303c7fe382aa4949c9134c20b772cb6..7a0f11c53bf38b91d86cf7568542a8b49b780a32 100644 (file)
@@ -5,8 +5,8 @@ Required properties:
 - compatible : One of
   "altr,socfpga-spi",
   "altr,socfpga-arria10-spi",
-  "canaan,kendryte-k210-spi",
-  "canaan,kendryte-k210-ssi",
+  "canaan,k210-spi",
+  "canaan,k210-ssi",
   "intel,stratix10-spi",
   "intel,agilex-spi",
   "mscc,ocelot-spi",
index f922a7c323d49552d7fdd0dea9913c6c40737044..bb4eee5d99bd50cc1633545a2df20da80066b131 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
 obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
 obj-$(CONFIG_CLK_EXYNOS) += exynos/
 obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
-obj-$(CONFIG_CLK_K210) += clk_kendryte.o
+obj-$(CONFIG_CLK_K210) += clk_k210.o
 obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
 obj-$(CONFIG_CLK_MPFS) += microchip/
 obj-$(CONFIG_CLK_MVEBU) += mvebu/
diff --git a/drivers/clk/clk_k210.c b/drivers/clk/clk_k210.c
new file mode 100644 (file)
index 0000000..1961efa
--- /dev/null
@@ -0,0 +1,1344 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <[email protected]>
+ */
+#define LOG_CATEGORY UCLASS_CLK
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <log.h>
+#include <mapmem.h>
+#include <serial.h>
+#include <dt-bindings/clock/k210-sysctl.h>
+#include <dt-bindings/mfd/k210-sysctl.h>
+#include <k210/pll.h>
+#include <linux/bitfield.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct k210_clk_priv - K210 clock driver private data
+ * @base: The base address of the sysctl device
+ * @in0: The "in0" external oscillator
+ */
+struct k210_clk_priv {
+       void __iomem *base;
+       struct clk in0;
+};
+
+/*
+ * All parameters for different sub-clocks are collected into parameter arrays.
+ * These parameters are then initialized by the clock which uses them during
+ * probe. To save space, ids are automatically generated for each sub-clock by
+ * using an enum. Instead of storing a parameter struct for each clock, even for
+ * those clocks which don't use a particular type of sub-clock, we can just
+ * store the parameters for the clocks which need them.
+ *
+ * So why do it like this? Arranging all the sub-clocks together makes it very
+ * easy to find bugs in the code.
+ */
+
+/**
+ * enum k210_clk_div_type - The type of divider
+ * @K210_DIV_ONE: freq = parent / (reg + 1)
+ * @K210_DIV_EVEN: freq = parent / 2 / (reg + 1)
+ * @K210_DIV_POWER: freq = parent / (2 << reg)
+ * @K210_DIV_FIXED: freq = parent / factor
+ */
+enum k210_clk_div_type {
+       K210_DIV_ONE,
+       K210_DIV_EVEN,
+       K210_DIV_POWER,
+       K210_DIV_FIXED,
+};
+
+/**
+ * struct k210_div_params - Parameters for dividing clocks
+ * @type: An &enum k210_clk_div_type specifying the dividing formula
+ * @off: The offset of the divider from the sysctl base address
+ * @shift: The offset of the LSB of the divider
+ * @width: The number of bits in the divider
+ * @div: The fixed divisor for this divider
+ */
+struct k210_div_params {
+       u8 type;
+       union {
+               struct {
+                       u8 off;
+                       u8 shift;
+                       u8 width;
+               };
+               u8 div;
+       };
+};
+
+#define DIV_LIST \
+       DIV(K210_CLK_ACLK,   K210_SYSCTL_SEL0,  1,  2, K210_DIV_POWER) \
+       DIV(K210_CLK_APB0,   K210_SYSCTL_SEL0,  3,  3, K210_DIV_ONE) \
+       DIV(K210_CLK_APB1,   K210_SYSCTL_SEL0,  6,  3, K210_DIV_ONE) \
+       DIV(K210_CLK_APB2,   K210_SYSCTL_SEL0,  9,  3, K210_DIV_ONE) \
+       DIV(K210_CLK_SRAM0,  K210_SYSCTL_THR0,  0,  4, K210_DIV_ONE) \
+       DIV(K210_CLK_SRAM1,  K210_SYSCTL_THR0,  4,  4, K210_DIV_ONE) \
+       DIV(K210_CLK_AI,     K210_SYSCTL_THR0,  8,  4, K210_DIV_ONE) \
+       DIV(K210_CLK_DVP,    K210_SYSCTL_THR0, 12,  4, K210_DIV_ONE) \
+       DIV(K210_CLK_ROM,    K210_SYSCTL_THR0, 16,  4, K210_DIV_ONE) \
+       DIV(K210_CLK_SPI0,   K210_SYSCTL_THR1,  0,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_SPI1,   K210_SYSCTL_THR1,  8,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_SPI2,   K210_SYSCTL_THR1, 16,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_SPI3,   K210_SYSCTL_THR1, 24,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_TIMER0, K210_SYSCTL_THR2,  0,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_TIMER1, K210_SYSCTL_THR2,  8,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_TIMER2, K210_SYSCTL_THR2, 16,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S0,   K210_SYSCTL_THR3,  0, 16, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S1,   K210_SYSCTL_THR3, 16, 16, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S2,   K210_SYSCTL_THR4,  0, 16, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S0_M, K210_SYSCTL_THR4, 16,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S1_M, K210_SYSCTL_THR4, 24,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2S2_M, K210_SYSCTL_THR4,  0,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2C0,   K210_SYSCTL_THR5,  8,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2C1,   K210_SYSCTL_THR5, 16,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_I2C2,   K210_SYSCTL_THR5, 24,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_WDT0,   K210_SYSCTL_THR6,  0,  8, K210_DIV_EVEN) \
+       DIV(K210_CLK_WDT1,   K210_SYSCTL_THR6,  8,  8, K210_DIV_EVEN) \
+       DIV_FIXED(K210_CLK_CLINT, 50) \
+
+#define _DIVIFY(id) K210_CLK_DIV_##id
+#define DIVIFY(id) _DIVIFY(id)
+
+enum k210_div_id {
+#define DIV(id, ...) DIVIFY(id),
+#define DIV_FIXED DIV
+       DIV_LIST
+#undef DIV
+#undef DIV_FIXED
+       K210_CLK_DIV_NONE,
+};
+
+static const struct k210_div_params k210_divs[] = {
+#define DIV(id, _off, _shift, _width, _type) \
+       [DIVIFY(id)] = { \
+               .type = (_type), \
+               .off = (_off), \
+               .shift = (_shift), \
+               .width = (_width), \
+       },
+#define DIV_FIXED(id, _div) \
+       [DIVIFY(id)] = { \
+               .type = K210_DIV_FIXED, \
+               .div = (_div) \
+       },
+       DIV_LIST
+#undef DIV
+#undef DIV_FIXED
+};
+
+#undef DIV
+#undef DIV_LIST
+
+/**
+ * struct k210_gate_params - Parameters for gated clocks
+ * @off: The offset of the gate from the sysctl base address
+ * @bit_idx: The index of the bit within the register
+ */
+struct k210_gate_params {
+       u8 off;
+       u8 bit_idx;
+};
+
+#define GATE_LIST \
+       GATE(K210_CLK_CPU,    K210_SYSCTL_EN_CENT,  0) \
+       GATE(K210_CLK_SRAM0,  K210_SYSCTL_EN_CENT,  1) \
+       GATE(K210_CLK_SRAM1,  K210_SYSCTL_EN_CENT,  2) \
+       GATE(K210_CLK_APB0,   K210_SYSCTL_EN_CENT,  3) \
+       GATE(K210_CLK_APB1,   K210_SYSCTL_EN_CENT,  4) \
+       GATE(K210_CLK_APB2,   K210_SYSCTL_EN_CENT,  5) \
+       GATE(K210_CLK_ROM,    K210_SYSCTL_EN_PERI,  0) \
+       GATE(K210_CLK_DMA,    K210_SYSCTL_EN_PERI,  1) \
+       GATE(K210_CLK_AI,     K210_SYSCTL_EN_PERI,  2) \
+       GATE(K210_CLK_DVP,    K210_SYSCTL_EN_PERI,  3) \
+       GATE(K210_CLK_FFT,    K210_SYSCTL_EN_PERI,  4) \
+       GATE(K210_CLK_GPIO,   K210_SYSCTL_EN_PERI,  5) \
+       GATE(K210_CLK_SPI0,   K210_SYSCTL_EN_PERI,  6) \
+       GATE(K210_CLK_SPI1,   K210_SYSCTL_EN_PERI,  7) \
+       GATE(K210_CLK_SPI2,   K210_SYSCTL_EN_PERI,  8) \
+       GATE(K210_CLK_SPI3,   K210_SYSCTL_EN_PERI,  9) \
+       GATE(K210_CLK_I2S0,   K210_SYSCTL_EN_PERI, 10) \
+       GATE(K210_CLK_I2S1,   K210_SYSCTL_EN_PERI, 11) \
+       GATE(K210_CLK_I2S2,   K210_SYSCTL_EN_PERI, 12) \
+       GATE(K210_CLK_I2C0,   K210_SYSCTL_EN_PERI, 13) \
+       GATE(K210_CLK_I2C1,   K210_SYSCTL_EN_PERI, 14) \
+       GATE(K210_CLK_I2C2,   K210_SYSCTL_EN_PERI, 15) \
+       GATE(K210_CLK_UART1,  K210_SYSCTL_EN_PERI, 16) \
+       GATE(K210_CLK_UART2,  K210_SYSCTL_EN_PERI, 17) \
+       GATE(K210_CLK_UART3,  K210_SYSCTL_EN_PERI, 18) \
+       GATE(K210_CLK_AES,    K210_SYSCTL_EN_PERI, 19) \
+       GATE(K210_CLK_FPIOA,  K210_SYSCTL_EN_PERI, 20) \
+       GATE(K210_CLK_TIMER0, K210_SYSCTL_EN_PERI, 21) \
+       GATE(K210_CLK_TIMER1, K210_SYSCTL_EN_PERI, 22) \
+       GATE(K210_CLK_TIMER2, K210_SYSCTL_EN_PERI, 23) \
+       GATE(K210_CLK_WDT0,   K210_SYSCTL_EN_PERI, 24) \
+       GATE(K210_CLK_WDT1,   K210_SYSCTL_EN_PERI, 25) \
+       GATE(K210_CLK_SHA,    K210_SYSCTL_EN_PERI, 26) \
+       GATE(K210_CLK_OTP,    K210_SYSCTL_EN_PERI, 27) \
+       GATE(K210_CLK_RTC,    K210_SYSCTL_EN_PERI, 29)
+
+#define _GATEIFY(id) K210_CLK_GATE_##id
+#define GATEIFY(id) _GATEIFY(id)
+
+enum k210_gate_id {
+#define GATE(id, ...) GATEIFY(id),
+       GATE_LIST
+#undef GATE
+       K210_CLK_GATE_NONE,
+};
+
+static const struct k210_gate_params k210_gates[] = {
+#define GATE(id, _off, _idx) \
+       [GATEIFY(id)] = { \
+               .off = (_off), \
+               .bit_idx = (_idx), \
+       },
+       GATE_LIST
+#undef GATE
+};
+
+#undef GATE_LIST
+
+/* The most parents is PLL2 */
+#define K210_CLK_MAX_PARENTS 3
+
+/**
+ * struct k210_mux_params - Parameters for muxed clocks
+ * @parents: A list of parent clock ids
+ * @num_parents: The number of parent clocks
+ * @off: The offset of the mux from the base sysctl address
+ * @shift: The offset of the LSB of the mux selector
+ * @width: The number of bits in the mux selector
+ */
+struct k210_mux_params {
+       u8 parents[K210_CLK_MAX_PARENTS];
+       u8 num_parents;
+       u8 off;
+       u8 shift;
+       u8 width;
+};
+
+#define MUX(id, reg, shift, width) \
+       MUX_PARENTS(id, reg, shift, width, K210_CLK_IN0, K210_CLK_PLL0)
+#define MUX_LIST \
+       MUX_PARENTS(K210_CLK_PLL2, K210_SYSCTL_PLL2, 26, 2, \
+                   K210_CLK_IN0, K210_CLK_PLL0, K210_CLK_PLL1) \
+       MUX(K210_CLK_ACLK, K210_SYSCTL_SEL0, 0, 1) \
+       MUX(K210_CLK_SPI3,   K210_SYSCTL_SEL0, 12, 1) \
+       MUX(K210_CLK_TIMER0, K210_SYSCTL_SEL0, 13, 1) \
+       MUX(K210_CLK_TIMER1, K210_SYSCTL_SEL0, 14, 1) \
+       MUX(K210_CLK_TIMER2, K210_SYSCTL_SEL0, 15, 1)
+
+#define _MUXIFY(id) K210_CLK_MUX_##id
+#define MUXIFY(id) _MUXIFY(id)
+
+enum k210_mux_id {
+#define MUX_PARENTS(id, ...) MUXIFY(id),
+       MUX_LIST
+#undef MUX_PARENTS
+       K210_CLK_MUX_NONE,
+};
+
+static const struct k210_mux_params k210_muxes[] = {
+#define MUX_PARENTS(id, _off, _shift, _width, ...) \
+       [MUXIFY(id)] = { \
+               .parents = { __VA_ARGS__ }, \
+               .num_parents = __count_args(__VA_ARGS__), \
+               .off = (_off), \
+               .shift = (_shift), \
+               .width = (_width), \
+       },
+       MUX_LIST
+#undef MUX_PARENTS
+};
+
+#undef MUX
+#undef MUX_LIST
+
+/**
+ * struct k210_pll_params - K210 PLL parameters
+ * @off: The offset of the PLL from the base sysctl address
+ * @shift: The offset of the LSB of the lock status
+ * @width: The number of bits in the lock status
+ */
+struct k210_pll_params {
+       u8 off;
+       u8 shift;
+       u8 width;
+};
+
+static const struct k210_pll_params k210_plls[] = {
+#define PLL(_off, _shift, _width) { \
+       .off = (_off), \
+       .shift = (_shift), \
+       .width = (_width), \
+}
+       [0] = PLL(K210_SYSCTL_PLL0,  0, 2),
+       [1] = PLL(K210_SYSCTL_PLL1,  8, 1),
+       [2] = PLL(K210_SYSCTL_PLL2, 16, 1),
+#undef PLL
+};
+
+/**
+ * enum k210_clk_flags - The type of a K210 clock
+ * @K210_CLKF_MUX: This clock has a mux and not a static parent
+ * @K210_CLKF_PLL: This clock is a PLL
+ */
+enum k210_clk_flags {
+       K210_CLKF_MUX = BIT(0),
+       K210_CLKF_PLL = BIT(1),
+};
+
+/**
+ * struct k210_clk_params - The parameters defining a K210 clock
+ * @name: The name of the clock
+ * @flags: A set of &enum k210_clk_flags defining which fields are valid
+ * @mux: An &enum k210_mux_id of this clock's mux
+ * @parent: The clock id of this clock's parent
+ * @pll: The id of the PLL (if this clock is a PLL)
+ * @div: An &enum k210_div_id of this clock's divider
+ * @gate: An &enum k210_gate_id of this clock's gate
+ */
+struct k210_clk_params {
+#if CONFIG_IS_ENABLED(CMD_CLK)
+       const char *name;
+#endif
+       u8 flags;
+       union {
+               u8 parent;
+               u8 mux;
+       };
+       union {
+               u8 pll;
+               struct {
+                       u8 div;
+                       u8 gate;
+               };
+       };
+};
+
+static const struct k210_clk_params k210_clks[] = {
+#if CONFIG_IS_ENABLED(CMD_CLK)
+#define NAME(_name) .name = (_name),
+#else
+#define NAME(name)
+#endif
+#define CLK(id, _name, _parent, _div, _gate) \
+       [id] = { \
+               NAME(_name) \
+               .parent = (_parent), \
+               .div = (_div), \
+               .gate = (_gate), \
+       }
+#define CLK_MUX(id, _name, _mux, _div, _gate) \
+       [id] = { \
+               NAME(_name) \
+               .flags = K210_CLKF_MUX, \
+               .mux = (_mux), \
+               .div = (_div), \
+               .gate = (_gate), \
+       }
+#define CLK_PLL(id, _pll, _parent) \
+       [id] = { \
+               NAME("pll" #_pll) \
+               .flags = K210_CLKF_PLL, \
+               .parent = (_parent), \
+               .pll = (_pll), \
+       }
+#define CLK_FULL(id, name) \
+       CLK_MUX(id, name, MUXIFY(id), DIVIFY(id), GATEIFY(id))
+#define CLK_NOMUX(id, name, parent) \
+       CLK(id, name, parent, DIVIFY(id), GATEIFY(id))
+#define CLK_DIV(id, name, parent) \
+       CLK(id, name, parent, DIVIFY(id), K210_CLK_GATE_NONE)
+#define CLK_GATE(id, name, parent) \
+       CLK(id, name, parent, K210_CLK_DIV_NONE, GATEIFY(id))
+       CLK_PLL(K210_CLK_PLL0, 0, K210_CLK_IN0),
+       CLK_PLL(K210_CLK_PLL1, 1, K210_CLK_IN0),
+       [K210_CLK_PLL2] = {
+               NAME("pll2")
+               .flags = K210_CLKF_MUX | K210_CLKF_PLL,
+               .mux = MUXIFY(K210_CLK_PLL2),
+               .pll = 2,
+       },
+       CLK_MUX(K210_CLK_ACLK, "aclk", MUXIFY(K210_CLK_ACLK),
+               DIVIFY(K210_CLK_ACLK), K210_CLK_GATE_NONE),
+       CLK_FULL(K210_CLK_SPI3,   "spi3"),
+       CLK_FULL(K210_CLK_TIMER0, "timer0"),
+       CLK_FULL(K210_CLK_TIMER1, "timer1"),
+       CLK_FULL(K210_CLK_TIMER2, "timer2"),
+       CLK_NOMUX(K210_CLK_SRAM0, "sram0",  K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_SRAM1, "sram1",  K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_ROM,   "rom",    K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_DVP,   "dvp",    K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_APB0,  "apb0",   K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_APB1,  "apb1",   K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_APB2,  "apb2",   K210_CLK_ACLK),
+       CLK_NOMUX(K210_CLK_AI,    "ai",     K210_CLK_PLL1),
+       CLK_NOMUX(K210_CLK_I2S0,  "i2s0",   K210_CLK_PLL2),
+       CLK_NOMUX(K210_CLK_I2S1,  "i2s1",   K210_CLK_PLL2),
+       CLK_NOMUX(K210_CLK_I2S2,  "i2s2",   K210_CLK_PLL2),
+       CLK_NOMUX(K210_CLK_WDT0,  "wdt0",   K210_CLK_IN0),
+       CLK_NOMUX(K210_CLK_WDT1,  "wdt1",   K210_CLK_IN0),
+       CLK_NOMUX(K210_CLK_SPI0,  "spi0",   K210_CLK_PLL0),
+       CLK_NOMUX(K210_CLK_SPI1,  "spi1",   K210_CLK_PLL0),
+       CLK_NOMUX(K210_CLK_SPI2,  "spi2",   K210_CLK_PLL0),
+       CLK_NOMUX(K210_CLK_I2C0,  "i2c0",   K210_CLK_PLL0),
+       CLK_NOMUX(K210_CLK_I2C1,  "i2c1",   K210_CLK_PLL0),
+       CLK_NOMUX(K210_CLK_I2C2,  "i2c2",   K210_CLK_PLL0),
+       CLK_DIV(K210_CLK_I2S0_M,  "i2s0_m", K210_CLK_PLL2),
+       CLK_DIV(K210_CLK_I2S1_M,  "i2s1_m", K210_CLK_PLL2),
+       CLK_DIV(K210_CLK_I2S2_M,  "i2s2_m", K210_CLK_PLL2),
+       CLK_DIV(K210_CLK_CLINT,   "clint",  K210_CLK_ACLK),
+       CLK_GATE(K210_CLK_CPU,    "cpu",    K210_CLK_ACLK),
+       CLK_GATE(K210_CLK_DMA,    "dma",    K210_CLK_ACLK),
+       CLK_GATE(K210_CLK_FFT,    "fft",    K210_CLK_ACLK),
+       CLK_GATE(K210_CLK_GPIO,   "gpio",   K210_CLK_APB0),
+       CLK_GATE(K210_CLK_UART1,  "uart1",  K210_CLK_APB0),
+       CLK_GATE(K210_CLK_UART2,  "uart2",  K210_CLK_APB0),
+       CLK_GATE(K210_CLK_UART3,  "uart3",  K210_CLK_APB0),
+       CLK_GATE(K210_CLK_FPIOA,  "fpioa",  K210_CLK_APB0),
+       CLK_GATE(K210_CLK_SHA,    "sha",    K210_CLK_APB0),
+       CLK_GATE(K210_CLK_AES,    "aes",    K210_CLK_APB1),
+       CLK_GATE(K210_CLK_OTP,    "otp",    K210_CLK_APB1),
+       CLK_GATE(K210_CLK_RTC,    "rtc",    K210_CLK_IN0),
+#undef NAME
+#undef CLK_PLL
+#undef CLK
+#undef CLK_FULL
+#undef CLK_NOMUX
+#undef CLK_DIV
+#undef CLK_GATE
+#undef CLK_LIST
+};
+
+#define K210_PLL_CLKR          GENMASK(3, 0)
+#define K210_PLL_CLKF          GENMASK(9, 4)
+#define K210_PLL_CLKOD         GENMASK(13, 10) /* Output Divider */
+#define K210_PLL_BWADJ         GENMASK(19, 14) /* BandWidth Adjust */
+#define K210_PLL_RESET         BIT(20)
+#define K210_PLL_PWRD          BIT(21) /* PoWeReD */
+#define K210_PLL_INTFB         BIT(22) /* Internal FeedBack */
+#define K210_PLL_BYPASS                BIT(23)
+#define K210_PLL_TEST          BIT(24)
+#define K210_PLL_EN            BIT(25)
+#define K210_PLL_TEST_EN       BIT(26)
+
+#define K210_PLL_LOCK          0
+#define K210_PLL_CLEAR_SLIP    2
+#define K210_PLL_TEST_OUT      3
+
+#ifdef CONFIG_CLK_K210_SET_RATE
+static int k210_pll_enable(struct k210_clk_priv *priv, int id);
+static int k210_pll_disable(struct k210_clk_priv *priv, int id);
+static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
+
+/*
+ * The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
+ * General-Purpose PLL. The logical layout of the PLL with internal feedback is
+ * approximately the following:
+ *
+ *  +---------------+
+ *  |reference clock|
+ *  +---------------+
+ *          |
+ *          v
+ *        +--+
+ *        |/r|
+ *        +--+
+ *          |
+ *          v
+ *   +-------------+
+ *   |divided clock|
+ *   +-------------+
+ *          |
+ *          v
+ *  +--------------+
+ *  |phase detector|<---+
+ *  +--------------+    |
+ *          |           |
+ *          v   +--------------+
+ *        +---+ |feedback clock|
+ *        |VCO| +--------------+
+ *        +---+         ^
+ *          |    +--+   |
+ *          +--->|/f|---+
+ *          |    +--+
+ *          v
+ *        +---+
+ *        |/od|
+ *        +---+
+ *          |
+ *          v
+ *       +------+
+ *       |output|
+ *       +------+
+ *
+ * The k210 PLLs have three factors: r, f, and od. Because of the feedback mode,
+ * the effect of the division by f is to multiply the input frequency. The
+ * equation for the output rate is
+ *   rate = (rate_in * f) / (r * od).
+ * Moving knowns to one side of the equation, we get
+ *   rate / rate_in = f / (r * od)
+ * Rearranging slightly,
+ *   abs_error = abs((rate / rate_in) - (f / (r * od))).
+ * To get relative, error, we divide by the expected ratio
+ *   error = abs((rate / rate_in) - (f / (r * od))) / (rate / rate_in).
+ * Simplifying,
+ *   error = abs(1 - f / (r * od)) / (rate / rate_in)
+ *   error = abs(1 - (f * rate_in) / (r * od * rate))
+ * Using the constants ratio = rate / rate_in and inv_ratio = rate_in / rate,
+ *   error = abs((f * inv_ratio) / (r * od) - 1)
+ * This is the error used in evaluating parameters.
+ *
+ * r and od are four bits each, while f is six bits. Because r and od are
+ * multiplied together, instead of the full 256 values possible if both bits
+ * were used fully, there are only 97 distinct products. Combined with f, there
+ * are 6208 theoretical settings for the PLL. However, most of these settings
+ * can be ruled out immediately because they do not have the correct ratio.
+ *
+ * In addition to the constraint of approximating the desired ratio, parameters
+ * must also keep internal pll frequencies within acceptable ranges. The divided
+ * clock's minimum and maximum frequencies have a ratio of around 128.  This
+ * leaves fairly substantial room to work with, especially since the only
+ * affected parameter is r. The VCO's minimum and maximum frequency have a ratio
+ * of 5, which is considerably more restrictive.
+ *
+ * The r and od factors are stored in a table. This is to make it easy to find
+ * the next-largest product. Some products have multiple factorizations, but
+ * only when one factor has at least a 2.5x ratio to the factors of the other
+ * factorization. This is because any smaller ratio would not make a difference
+ * when ensuring the VCO's frequency is within spec.
+ *
+ * Throughout the calculation function, fixed point arithmetic is used. Because
+ * the range of rate and rate_in may be up to 1.75 GHz, or around 2^30, 64-bit
+ * 32.32 fixed-point numbers are used to represent ratios. In general, to
+ * implement division, the numerator is first multiplied by 2^32. This gives a
+ * result where the whole number part is in the upper 32 bits, and the fraction
+ * is in the lower 32 bits.
+ *
+ * In general, rounding is done to the closest integer. This helps find the best
+ * approximation for the ratio. Rounding in one direction (e.g down) could cause
+ * the function to miss a better ratio with one of the parameters increased by
+ * one.
+ */
+
+/*
+ * The factors table was generated with the following python code:
+ *
+ * def p(x, y):
+ *    return (1.0*x/y > 2.5) or (1.0*y/x > 2.5)
+ *
+ * factors = {}
+ * for i in range(1, 17):
+ *    for j in range(1, 17):
+ *       fs = factors.get(i*j) or []
+ *       if fs == [] or all([
+ *             (p(i, x) and p(i, y)) or (p(j, x) and p(j, y))
+ *             for (x, y) in fs]):
+ *          fs.append((i, j))
+ *          factors[i*j] = fs
+ *
+ * for k, l in sorted(factors.items()):
+ *    for v in l:
+ *       print("PACK(%s, %s)," % v)
+ */
+#define PACK(r, od) (((((r) - 1) & 0xF) << 4) | (((od) - 1) & 0xF))
+#define UNPACK_R(val) ((((val) >> 4) & 0xF) + 1)
+#define UNPACK_OD(val) (((val) & 0xF) + 1)
+static const u8 factors[] = {
+       PACK(1, 1),
+       PACK(1, 2),
+       PACK(1, 3),
+       PACK(1, 4),
+       PACK(1, 5),
+       PACK(1, 6),
+       PACK(1, 7),
+       PACK(1, 8),
+       PACK(1, 9),
+       PACK(3, 3),
+       PACK(1, 10),
+       PACK(1, 11),
+       PACK(1, 12),
+       PACK(3, 4),
+       PACK(1, 13),
+       PACK(1, 14),
+       PACK(1, 15),
+       PACK(3, 5),
+       PACK(1, 16),
+       PACK(4, 4),
+       PACK(2, 9),
+       PACK(2, 10),
+       PACK(3, 7),
+       PACK(2, 11),
+       PACK(2, 12),
+       PACK(5, 5),
+       PACK(2, 13),
+       PACK(3, 9),
+       PACK(2, 14),
+       PACK(2, 15),
+       PACK(2, 16),
+       PACK(3, 11),
+       PACK(5, 7),
+       PACK(3, 12),
+       PACK(3, 13),
+       PACK(4, 10),
+       PACK(3, 14),
+       PACK(4, 11),
+       PACK(3, 15),
+       PACK(3, 16),
+       PACK(7, 7),
+       PACK(5, 10),
+       PACK(4, 13),
+       PACK(6, 9),
+       PACK(5, 11),
+       PACK(4, 14),
+       PACK(4, 15),
+       PACK(7, 9),
+       PACK(4, 16),
+       PACK(5, 13),
+       PACK(6, 11),
+       PACK(5, 14),
+       PACK(6, 12),
+       PACK(5, 15),
+       PACK(7, 11),
+       PACK(6, 13),
+       PACK(5, 16),
+       PACK(9, 9),
+       PACK(6, 14),
+       PACK(8, 11),
+       PACK(6, 15),
+       PACK(7, 13),
+       PACK(6, 16),
+       PACK(7, 14),
+       PACK(9, 11),
+       PACK(10, 10),
+       PACK(8, 13),
+       PACK(7, 15),
+       PACK(9, 12),
+       PACK(10, 11),
+       PACK(7, 16),
+       PACK(9, 13),
+       PACK(8, 15),
+       PACK(11, 11),
+       PACK(9, 14),
+       PACK(8, 16),
+       PACK(10, 13),
+       PACK(11, 12),
+       PACK(9, 15),
+       PACK(10, 14),
+       PACK(11, 13),
+       PACK(9, 16),
+       PACK(10, 15),
+       PACK(11, 14),
+       PACK(12, 13),
+       PACK(10, 16),
+       PACK(11, 15),
+       PACK(12, 14),
+       PACK(13, 13),
+       PACK(11, 16),
+       PACK(12, 15),
+       PACK(13, 14),
+       PACK(12, 16),
+       PACK(13, 15),
+       PACK(14, 14),
+       PACK(13, 16),
+       PACK(14, 15),
+       PACK(14, 16),
+       PACK(15, 15),
+       PACK(15, 16),
+       PACK(16, 16),
+};
+
+TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
+                                    struct k210_pll_config *best)
+{
+       int i;
+       s64 error, best_error;
+       u64 ratio, inv_ratio; /* fixed point 32.32 ratio of the rates */
+       u64 max_r;
+       u64 r, f, od;
+
+       /*
+        * Can't go over 1.75 GHz or under 21.25 MHz due to limitations on the
+        * VCO frequency. These are not the same limits as below because od can
+        * reduce the output frequency by 16.
+        */
+       if (rate > 1750000000 || rate < 21250000)
+               return -EINVAL;
+
+       /* Similar restrictions on the input rate */
+       if (rate_in > 1750000000 || rate_in < 13300000)
+               return -EINVAL;
+
+       ratio = DIV_ROUND_CLOSEST_ULL((u64)rate << 32, rate_in);
+       inv_ratio = DIV_ROUND_CLOSEST_ULL((u64)rate_in << 32, rate);
+       /* Can't increase by more than 64 or reduce by more than 256 */
+       if (rate > rate_in && ratio > (64ULL << 32))
+               return -EINVAL;
+       else if (rate <= rate_in && inv_ratio > (256ULL << 32))
+               return -EINVAL;
+
+       /*
+        * The divided clock (rate_in / r) must stay between 1.75 GHz and 13.3
+        * MHz. There is no minimum, since the only way to get a higher input
+        * clock than 26 MHz is to use a clock generated by a PLL. Because PLLs
+        * cannot output frequencies greater than 1.75 GHz, the minimum would
+        * never be greater than one.
+        */
+       max_r = DIV_ROUND_DOWN_ULL(rate_in, 13300000);
+
+       /* Variables get immediately incremented, so start at -1th iteration */
+       i = -1;
+       f = 0;
+       r = 0;
+       od = 0;
+       best_error = S64_MAX;
+       error = best_error;
+       /* do-while here so we always try at least one ratio */
+       do {
+               /*
+                * Whether we swapped r and od while enforcing frequency limits
+                */
+               bool swapped = false;
+               /*
+                * Whether the intermediate frequencies are out-of-spec
+                */
+               bool out_of_spec;
+               u64 last_od = od;
+               u64 last_r = r;
+
+               /*
+                * Try the next largest value for f (or r and od) and
+                * recalculate the other parameters based on that
+                */
+               if (rate > rate_in) {
+                       /*
+                        * Skip factors of the same product if we already tried
+                        * out that product
+                        */
+                       do {
+                               i++;
+                               r = UNPACK_R(factors[i]);
+                               od = UNPACK_OD(factors[i]);
+                       } while (i + 1 < ARRAY_SIZE(factors) &&
+                                r * od == last_r * last_od);
+
+                       /* Round close */
+                       f = (r * od * ratio + BIT(31)) >> 32;
+                       if (f > 64)
+                               f = 64;
+               } else {
+                       u64 tmp = ++f * inv_ratio;
+                       bool round_up = !!(tmp & BIT(31));
+                       u32 goal = (tmp >> 32) + round_up;
+                       u32 err, last_err;
+
+                       /* Get the next r/od pair in factors */
+                       while (r * od < goal && i + 1 < ARRAY_SIZE(factors)) {
+                               i++;
+                               r = UNPACK_R(factors[i]);
+                               od = UNPACK_OD(factors[i]);
+                       }
+
+                       /*
+                        * This is a case of double rounding. If we rounded up
+                        * above, we need to round down (in cases of ties) here.
+                        * This prevents off-by-one errors resulting from
+                        * choosing X+2 over X when X.Y rounds up to X+1 and
+                        * there is no r * od = X+1. For the converse, when X.Y
+                        * is rounded down to X, we should choose X+1 over X-1.
+                        */
+                       err = abs(r * od - goal);
+                       last_err = abs(last_r * last_od - goal);
+                       if (last_err < err || (round_up && last_err == err)) {
+                               i--;
+                               r = last_r;
+                               od = last_od;
+                       }
+               }
+
+               /*
+                * Enforce limits on internal clock frequencies. If we
+                * aren't in spec, try swapping r and od. If everything is
+                * in-spec, calculate the relative error.
+                */
+again:
+               out_of_spec = false;
+               if (r > max_r) {
+                       out_of_spec = true;
+               } else {
+                       /*
+                        * There is no way to only divide once; we need
+                        * to examine the frequency with and without the
+                        * effect of od.
+                        */
+                       u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r);
+
+                       if (vco > 1750000000 || vco < 340000000)
+                               out_of_spec = true;
+               }
+
+               if (out_of_spec) {
+                       u64 new_r, new_od;
+
+                       if (!swapped) {
+                               u64 tmp = r;
+
+                               r = od;
+                               od = tmp;
+                               swapped = true;
+                               goto again;
+                       }
+
+                       /*
+                        * Try looking ahead to see if there are additional
+                        * factors for the same product.
+                        */
+                       if (i + 1 < ARRAY_SIZE(factors)) {
+                               i++;
+                               new_r = UNPACK_R(factors[i]);
+                               new_od = UNPACK_OD(factors[i]);
+                               if (r * od == new_r * new_od) {
+                                       r = new_r;
+                                       od = new_od;
+                                       swapped = false;
+                                       goto again;
+                               }
+                               i--;
+                       }
+
+                       /*
+                        * Try looking back to see if there is a worse ratio
+                        * that we could try anyway
+                        */
+                       while (i > 0) {
+                               i--;
+                               new_r = UNPACK_R(factors[i]);
+                               new_od = UNPACK_OD(factors[i]);
+                               /*
+                                * Don't loop over factors for the same product
+                                * to avoid getting stuck because of the above
+                                * clause
+                                */
+                               if (r * od != new_r * new_od) {
+                                       if (new_r * new_od > last_r * last_od) {
+                                               r = new_r;
+                                               od = new_od;
+                                               swapped = false;
+                                               goto again;
+                                       }
+                                       break;
+                               }
+                       }
+
+                       /* We ran out of things to try */
+                       continue;
+               }
+
+               error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od);
+               /* The lower 16 bits are spurious */
+               error = abs((error - BIT(32))) >> 16;
+
+               if (error < best_error) {
+                       best->r = r;
+                       best->f = f;
+                       best->od = od;
+                       best_error = error;
+               }
+       } while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0);
+
+       log_debug("best error %lld\n", best_error);
+       if (best_error == S64_MAX)
+               return -EINVAL;
+
+       return 0;
+}
+
+static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+                              ulong rate_in)
+{
+       int err;
+       const struct k210_pll_params *pll = &k210_plls[id];
+       struct k210_pll_config config = {};
+       u32 reg;
+       ulong calc_rate;
+
+       err = k210_pll_calc_config(rate, rate_in, &config);
+       if (err)
+               return err;
+       log_debug("Got r=%u f=%u od=%u\n", config.r, config.f, config.od);
+
+       /* Don't bother setting the rate if we're already at that rate */
+       calc_rate = DIV_ROUND_DOWN_ULL(((u64)rate_in) * config.f,
+                                      config.r * config.od);
+       if (calc_rate == k210_pll_get_rate(priv, id, rate))
+               return calc_rate;
+
+       k210_pll_disable(priv, id);
+
+       reg = readl(priv->base + pll->off);
+       reg &= ~K210_PLL_CLKR
+           &  ~K210_PLL_CLKF
+           &  ~K210_PLL_CLKOD
+           &  ~K210_PLL_BWADJ;
+       reg |= FIELD_PREP(K210_PLL_CLKR, config.r - 1)
+           |  FIELD_PREP(K210_PLL_CLKF, config.f - 1)
+           |  FIELD_PREP(K210_PLL_CLKOD, config.od - 1)
+           |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
+       writel(reg, priv->base + pll->off);
+
+       k210_pll_enable(priv, id);
+
+       serial_setbrg();
+       return k210_pll_get_rate(priv, id, rate);
+}
+#else
+static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+                              ulong rate_in)
+{
+       return -ENOSYS;
+}
+#endif /* CONFIG_CLK_K210_SET_RATE */
+
+static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id,
+                              ulong rate_in)
+{
+       u64 r, f, od;
+       u32 reg = readl(priv->base + k210_plls[id].off);
+
+       if (reg & K210_PLL_BYPASS)
+               return rate_in;
+
+       if (!(reg & K210_PLL_PWRD))
+               return 0;
+
+       r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
+       f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
+       od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
+
+       return DIV_ROUND_DOWN_ULL(((u64)rate_in) * f, r * od);
+}
+
+/*
+ * Wait for the PLL to be locked. If the PLL is not locked, try clearing the
+ * slip before retrying
+ */
+static void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
+{
+       const struct k210_pll_params *pll = &k210_plls[id];
+       u32 mask = (BIT(pll->width) - 1) << pll->shift;
+
+       while (true) {
+               u32 reg = readl(priv->base + K210_SYSCTL_PLL_LOCK);
+
+               if ((reg & mask) == mask)
+                       break;
+
+               reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
+               writel(reg, priv->base + K210_SYSCTL_PLL_LOCK);
+       }
+}
+
+static bool k210_pll_enabled(u32 reg)
+{
+       return (reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
+               !(reg & K210_PLL_RESET);
+}
+
+/* Adapted from sysctl_pll_enable */
+static int k210_pll_enable(struct k210_clk_priv *priv, int id)
+{
+       const struct k210_pll_params *pll = &k210_plls[id];
+       u32 reg = readl(priv->base + pll->off);
+
+       if (k210_pll_enabled(reg))
+               return 0;
+
+       reg |= K210_PLL_PWRD;
+       writel(reg, priv->base + pll->off);
+
+       /* Ensure reset is low before asserting it */
+       reg &= ~K210_PLL_RESET;
+       writel(reg, priv->base + pll->off);
+       reg |= K210_PLL_RESET;
+       writel(reg, priv->base + pll->off);
+       nop();
+       nop();
+       reg &= ~K210_PLL_RESET;
+       writel(reg, priv->base + pll->off);
+
+       k210_pll_waitfor_lock(priv, id);
+
+       reg &= ~K210_PLL_BYPASS;
+       reg |= K210_PLL_EN;
+       writel(reg, priv->base + pll->off);
+
+       return 0;
+}
+
+static int k210_pll_disable(struct k210_clk_priv *priv, int id)
+{
+       const struct k210_pll_params *pll = &k210_plls[id];
+       u32 reg = readl(priv->base + pll->off);
+
+       /*
+        * Bypassing before powering off is important so child clocks don't stop
+        * working. This is especially important for pll0, the indirect parent
+        * of the cpu clock.
+        */
+       reg |= K210_PLL_BYPASS;
+       writel(reg, priv->base + pll->off);
+
+       reg &= ~K210_PLL_PWRD;
+       reg &= ~K210_PLL_EN;
+       writel(reg, priv->base + pll->off);
+       return 0;
+}
+
+static u32 k210_clk_readl(struct k210_clk_priv *priv, u8 off, u8 shift,
+                         u8 width)
+{
+       u32 reg = readl(priv->base + off);
+
+       return (reg >> shift) & (BIT(width) - 1);
+}
+
+static void k210_clk_writel(struct k210_clk_priv *priv, u8 off, u8 shift,
+                           u8 width, u32 val)
+{
+       u32 reg = readl(priv->base + off);
+       u32 mask = (BIT(width) - 1) << shift;
+
+       reg &= ~mask;
+       reg |= mask & (val << shift);
+       writel(reg, priv->base + off);
+}
+
+static int k210_clk_get_parent(struct k210_clk_priv *priv, int id)
+{
+       u32 sel;
+       const struct k210_mux_params *mux;
+
+       if (!(k210_clks[id].flags & K210_CLKF_MUX))
+               return k210_clks[id].parent;
+       mux = &k210_muxes[k210_clks[id].mux];
+
+       sel = k210_clk_readl(priv, mux->off, mux->shift, mux->width);
+       assert(sel < mux->num_parents);
+       return mux->parents[sel];
+}
+
+static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id)
+{
+       int parent;
+       u32 val;
+       ulong parent_rate;
+       const struct k210_div_params *div;
+
+       if (id == K210_CLK_IN0)
+               return clk_get_rate(&priv->in0);
+
+       parent = k210_clk_get_parent(priv, id);
+       parent_rate = do_k210_clk_get_rate(priv, parent);
+       if (IS_ERR_VALUE(parent_rate))
+               return parent_rate;
+
+       if (k210_clks[id].flags & K210_CLKF_PLL)
+               return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate);
+
+       if (k210_clks[id].div == K210_CLK_DIV_NONE)
+               return parent_rate;
+       div = &k210_divs[k210_clks[id].div];
+
+       if (div->type == K210_DIV_FIXED)
+               return parent_rate / div->div;
+
+       val = k210_clk_readl(priv, div->off, div->shift, div->width);
+       switch (div->type) {
+       case K210_DIV_ONE:
+               return parent_rate / (val + 1);
+       case K210_DIV_EVEN:
+               return parent_rate / 2 / (val + 1);
+       case K210_DIV_POWER:
+               /* This is ACLK, which has no divider on IN0 */
+               if (parent == K210_CLK_IN0)
+                       return parent_rate;
+               return parent_rate / (2 << val);
+       default:
+               assert(false);
+               return -EINVAL;
+       };
+}
+
+static ulong k210_clk_get_rate(struct clk *clk)
+{
+       return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
+}
+
+static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
+{
+       int i;
+       const struct k210_mux_params *mux;
+
+       if (!(k210_clks[id].flags & K210_CLKF_MUX))
+               return -ENOSYS;
+       mux = &k210_muxes[k210_clks[id].mux];
+
+       for (i = 0; i < mux->num_parents; i++) {
+               if (mux->parents[i] == new) {
+                       k210_clk_writel(priv, mux->off, mux->shift, mux->width,
+                                       i);
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       return do_k210_clk_set_parent(dev_get_priv(clk->dev), clk->id,
+                                     parent->id);
+}
+
+static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int parent, ret, err;
+       ulong rate_in, val;
+       const struct k210_div_params *div;
+       struct k210_clk_priv *priv = dev_get_priv(clk->dev);
+
+       if (clk->id == K210_CLK_IN0)
+               return clk_set_rate(&priv->in0, rate);
+
+       parent = k210_clk_get_parent(priv, clk->id);
+       rate_in = do_k210_clk_get_rate(priv, parent);
+       if (IS_ERR_VALUE(rate_in))
+               return rate_in;
+
+       log_debug("id=%ld rate=%lu rate_in=%lu\n", clk->id, rate, rate_in);
+
+       if (clk->id == K210_CLK_PLL0) {
+               /* Bypass ACLK so the CPU keeps going */
+               ret = do_k210_clk_set_parent(priv, K210_CLK_ACLK, K210_CLK_IN0);
+               if (ret)
+                       return ret;
+       } else if (clk->id == K210_CLK_PLL1 && gd->flags & GD_FLG_RELOC) {
+               /*
+                * We can't bypass the AI clock like we can ACLK, and after
+                * relocation we are using the AI ram.
+                */
+               return -EPERM;
+       }
+
+       if (k210_clks[clk->id].flags & K210_CLKF_PLL) {
+               ret = k210_pll_set_rate(priv, k210_clks[clk->id].pll, rate,
+                                       rate_in);
+               if (!IS_ERR_VALUE(ret) && clk->id == K210_CLK_PLL0) {
+                       /*
+                        * This may have the side effect of reparenting ACLK,
+                        * but I don't really want to keep track of what the old
+                        * parent was.
+                        */
+                       err = do_k210_clk_set_parent(priv, K210_CLK_ACLK,
+                                                    K210_CLK_PLL0);
+                       if (err)
+                               return err;
+               }
+               return ret;
+       }
+
+       if (k210_clks[clk->id].div == K210_CLK_DIV_NONE)
+               return -ENOSYS;
+       div = &k210_divs[k210_clks[clk->id].div];
+
+       switch (div->type) {
+       case K210_DIV_ONE:
+               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
+               val = val ? val - 1 : 0;
+               break;
+       case K210_DIV_EVEN:
+               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, 2 * rate);
+               break;
+       case K210_DIV_POWER:
+               /* This is ACLK, which has no divider on IN0 */
+               if (parent == K210_CLK_IN0)
+                       return -ENOSYS;
+
+               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
+               val = __ffs(val);
+               break;
+       default:
+               assert(false);
+               return -EINVAL;
+       };
+
+       val = val ? val - 1 : 0;
+       k210_clk_writel(priv, div->off, div->shift, div->width, val);
+       return do_k210_clk_get_rate(priv, clk->id);
+}
+
+static int k210_clk_endisable(struct k210_clk_priv *priv, int id, bool enable)
+{
+       int parent = k210_clk_get_parent(priv, id);
+       const struct k210_gate_params *gate;
+
+       if (id == K210_CLK_IN0) {
+               if (enable)
+                       return clk_enable(&priv->in0);
+               else
+                       return clk_disable(&priv->in0);
+       }
+
+       /* Only recursively enable clocks since we don't track refcounts */
+       if (enable) {
+               int ret = k210_clk_endisable(priv, parent, true);
+
+               if (ret && ret != -ENOSYS)
+                       return ret;
+       }
+
+       if (k210_clks[id].flags & K210_CLKF_PLL) {
+               if (enable)
+                       return k210_pll_enable(priv, k210_clks[id].pll);
+               else
+                       return k210_pll_disable(priv, k210_clks[id].pll);
+       }
+
+       if (k210_clks[id].gate == K210_CLK_GATE_NONE)
+               return -ENOSYS;
+       gate = &k210_gates[k210_clks[id].gate];
+
+       k210_clk_writel(priv, gate->off, gate->bit_idx, 1, enable);
+       return 0;
+}
+
+static int k210_clk_enable(struct clk *clk)
+{
+       return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, true);
+}
+
+static int k210_clk_disable(struct clk *clk)
+{
+       return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, false);
+}
+
+static int k210_clk_request(struct clk *clk)
+{
+       if (clk->id >= ARRAY_SIZE(k210_clks))
+               return -EINVAL;
+       return 0;
+}
+
+static const struct clk_ops k210_clk_ops = {
+       .request = k210_clk_request,
+       .set_rate = k210_clk_set_rate,
+       .get_rate = k210_clk_get_rate,
+       .set_parent = k210_clk_set_parent,
+       .enable = k210_clk_enable,
+       .disable = k210_clk_disable,
+};
+
+static int k210_clk_probe(struct udevice *dev)
+{
+       int ret;
+       struct k210_clk_priv *priv = dev_get_priv(dev);
+
+       priv->base = dev_read_addr_ptr(dev_get_parent(dev));
+       if (!priv->base)
+               return -EINVAL;
+
+       ret = clk_get_by_index(dev, 0, &priv->in0);
+       if (ret)
+               return ret;
+
+       /*
+        * Force setting defaults, even before relocation. This is so we can
+        * set the clock rate for PLL1 before we relocate into aisram.
+        */
+       if (!(gd->flags & GD_FLG_RELOC))
+               clk_set_defaults(dev, CLK_DEFAULTS_POST_FORCE);
+
+       return 0;
+}
+
+static const struct udevice_id k210_clk_ids[] = {
+       { .compatible = "canaan,k210-clk" },
+       { },
+};
+
+U_BOOT_DRIVER(k210_clk) = {
+       .name = "k210_clk",
+       .id = UCLASS_CLK,
+       .of_match = k210_clk_ids,
+       .ops = &k210_clk_ops,
+       .probe = k210_clk_probe,
+       .priv_auto = sizeof(struct k210_clk_priv),
+};
+
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static char show_enabled(struct k210_clk_priv *priv, int id)
+{
+       bool enabled;
+
+       if (k210_clks[id].flags & K210_CLKF_PLL) {
+               const struct k210_pll_params *pll =
+                       &k210_plls[k210_clks[id].pll];
+
+               enabled = k210_pll_enabled(readl(priv->base + pll->off));
+       } else if (k210_clks[id].gate == K210_CLK_GATE_NONE) {
+               return '-';
+       } else {
+               const struct k210_gate_params *gate =
+                       &k210_gates[k210_clks[id].gate];
+
+               enabled = k210_clk_readl(priv, gate->off, gate->bit_idx, 1);
+       }
+
+       return enabled ? 'y' : 'n';
+}
+
+static void show_clks(struct k210_clk_priv *priv, int id, int depth)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(k210_clks); i++) {
+               if (k210_clk_get_parent(priv, i) != id)
+                       continue;
+
+               printf(" %-9lu %-7c %*s%s\n", do_k210_clk_get_rate(priv, i),
+                      show_enabled(priv, i), depth * 4, "",
+                      k210_clks[i].name);
+
+               show_clks(priv, i, depth + 1);
+       }
+}
+
+int soc_clk_dump(void)
+{
+       int ret;
+       struct udevice *dev;
+       struct k210_clk_priv *priv;
+
+       ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(k210_clk),
+                                         &dev);
+       if (ret)
+               return ret;
+       priv = dev_get_priv(dev);
+
+       puts(" Rate      Enabled Name\n");
+       puts("------------------------\n");
+       printf(" %-9lu %-7c %*s%s\n", clk_get_rate(&priv->in0), 'y', 0, "",
+              priv->in0.dev->name);
+       show_clks(priv, K210_CLK_IN0, 1);
+       return 0;
+}
+#endif
diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c
deleted file mode 100644 (file)
index 97efda5..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019-20 Sean Anderson <[email protected]>
- */
-#define LOG_CATEGORY UCLASS_CLK
-
-#include <common.h>
-#include <clk.h>
-#include <clk-uclass.h>
-#include <div64.h>
-#include <dm.h>
-#include <log.h>
-#include <mapmem.h>
-#include <serial.h>
-#include <dt-bindings/clock/k210-sysctl.h>
-#include <dt-bindings/mfd/k210-sysctl.h>
-#include <kendryte/pll.h>
-#include <linux/bitfield.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/**
- * struct k210_clk_priv - K210 clock driver private data
- * @base: The base address of the sysctl device
- * @in0: The "in0" external oscillator
- */
-struct k210_clk_priv {
-       void __iomem *base;
-       struct clk in0;
-};
-
-/*
- * All parameters for different sub-clocks are collected into parameter arrays.
- * These parameters are then initialized by the clock which uses them during
- * probe. To save space, ids are automatically generated for each sub-clock by
- * using an enum. Instead of storing a parameter struct for each clock, even for
- * those clocks which don't use a particular type of sub-clock, we can just
- * store the parameters for the clocks which need them.
- *
- * So why do it like this? Arranging all the sub-clocks together makes it very
- * easy to find bugs in the code.
- */
-
-/**
- * enum k210_clk_div_type - The type of divider
- * @K210_DIV_ONE: freq = parent / (reg + 1)
- * @K210_DIV_EVEN: freq = parent / 2 / (reg + 1)
- * @K210_DIV_POWER: freq = parent / (2 << reg)
- * @K210_DIV_FIXED: freq = parent / factor
- */
-enum k210_clk_div_type {
-       K210_DIV_ONE,
-       K210_DIV_EVEN,
-       K210_DIV_POWER,
-       K210_DIV_FIXED,
-};
-
-/**
- * struct k210_div_params - Parameters for dividing clocks
- * @type: An &enum k210_clk_div_type specifying the dividing formula
- * @off: The offset of the divider from the sysctl base address
- * @shift: The offset of the LSB of the divider
- * @width: The number of bits in the divider
- * @div: The fixed divisor for this divider
- */
-struct k210_div_params {
-       u8 type;
-       union {
-               struct {
-                       u8 off;
-                       u8 shift;
-                       u8 width;
-               };
-               u8 div;
-       };
-};
-
-#define DIV_LIST \
-       DIV(K210_CLK_ACLK,   K210_SYSCTL_SEL0,  1,  2, K210_DIV_POWER) \
-       DIV(K210_CLK_APB0,   K210_SYSCTL_SEL0,  3,  3, K210_DIV_ONE) \
-       DIV(K210_CLK_APB1,   K210_SYSCTL_SEL0,  6,  3, K210_DIV_ONE) \
-       DIV(K210_CLK_APB2,   K210_SYSCTL_SEL0,  9,  3, K210_DIV_ONE) \
-       DIV(K210_CLK_SRAM0,  K210_SYSCTL_THR0,  0,  4, K210_DIV_ONE) \
-       DIV(K210_CLK_SRAM1,  K210_SYSCTL_THR0,  4,  4, K210_DIV_ONE) \
-       DIV(K210_CLK_AI,     K210_SYSCTL_THR0,  8,  4, K210_DIV_ONE) \
-       DIV(K210_CLK_DVP,    K210_SYSCTL_THR0, 12,  4, K210_DIV_ONE) \
-       DIV(K210_CLK_ROM,    K210_SYSCTL_THR0, 16,  4, K210_DIV_ONE) \
-       DIV(K210_CLK_SPI0,   K210_SYSCTL_THR1,  0,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_SPI1,   K210_SYSCTL_THR1,  8,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_SPI2,   K210_SYSCTL_THR1, 16,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_SPI3,   K210_SYSCTL_THR1, 24,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_TIMER0, K210_SYSCTL_THR2,  0,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_TIMER1, K210_SYSCTL_THR2,  8,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_TIMER2, K210_SYSCTL_THR2, 16,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S0,   K210_SYSCTL_THR3,  0, 16, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S1,   K210_SYSCTL_THR3, 16, 16, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S2,   K210_SYSCTL_THR4,  0, 16, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S0_M, K210_SYSCTL_THR4, 16,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S1_M, K210_SYSCTL_THR4, 24,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2S2_M, K210_SYSCTL_THR4,  0,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2C0,   K210_SYSCTL_THR5,  8,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2C1,   K210_SYSCTL_THR5, 16,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_I2C2,   K210_SYSCTL_THR5, 24,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_WDT0,   K210_SYSCTL_THR6,  0,  8, K210_DIV_EVEN) \
-       DIV(K210_CLK_WDT1,   K210_SYSCTL_THR6,  8,  8, K210_DIV_EVEN) \
-       DIV_FIXED(K210_CLK_CLINT, 50) \
-
-#define _DIVIFY(id) K210_CLK_DIV_##id
-#define DIVIFY(id) _DIVIFY(id)
-
-enum k210_div_id {
-#define DIV(id, ...) DIVIFY(id),
-#define DIV_FIXED DIV
-       DIV_LIST
-#undef DIV
-#undef DIV_FIXED
-       K210_CLK_DIV_NONE,
-};
-
-static const struct k210_div_params k210_divs[] = {
-#define DIV(id, _off, _shift, _width, _type) \
-       [DIVIFY(id)] = { \
-               .type = (_type), \
-               .off = (_off), \
-               .shift = (_shift), \
-               .width = (_width), \
-       },
-#define DIV_FIXED(id, _div) \
-       [DIVIFY(id)] = { \
-               .type = K210_DIV_FIXED, \
-               .div = (_div) \
-       },
-       DIV_LIST
-#undef DIV
-#undef DIV_FIXED
-};
-
-#undef DIV
-#undef DIV_LIST
-
-/**
- * struct k210_gate_params - Parameters for gated clocks
- * @off: The offset of the gate from the sysctl base address
- * @bit_idx: The index of the bit within the register
- */
-struct k210_gate_params {
-       u8 off;
-       u8 bit_idx;
-};
-
-#define GATE_LIST \
-       GATE(K210_CLK_CPU,    K210_SYSCTL_EN_CENT,  0) \
-       GATE(K210_CLK_SRAM0,  K210_SYSCTL_EN_CENT,  1) \
-       GATE(K210_CLK_SRAM1,  K210_SYSCTL_EN_CENT,  2) \
-       GATE(K210_CLK_APB0,   K210_SYSCTL_EN_CENT,  3) \
-       GATE(K210_CLK_APB1,   K210_SYSCTL_EN_CENT,  4) \
-       GATE(K210_CLK_APB2,   K210_SYSCTL_EN_CENT,  5) \
-       GATE(K210_CLK_ROM,    K210_SYSCTL_EN_PERI,  0) \
-       GATE(K210_CLK_DMA,    K210_SYSCTL_EN_PERI,  1) \
-       GATE(K210_CLK_AI,     K210_SYSCTL_EN_PERI,  2) \
-       GATE(K210_CLK_DVP,    K210_SYSCTL_EN_PERI,  3) \
-       GATE(K210_CLK_FFT,    K210_SYSCTL_EN_PERI,  4) \
-       GATE(K210_CLK_GPIO,   K210_SYSCTL_EN_PERI,  5) \
-       GATE(K210_CLK_SPI0,   K210_SYSCTL_EN_PERI,  6) \
-       GATE(K210_CLK_SPI1,   K210_SYSCTL_EN_PERI,  7) \
-       GATE(K210_CLK_SPI2,   K210_SYSCTL_EN_PERI,  8) \
-       GATE(K210_CLK_SPI3,   K210_SYSCTL_EN_PERI,  9) \
-       GATE(K210_CLK_I2S0,   K210_SYSCTL_EN_PERI, 10) \
-       GATE(K210_CLK_I2S1,   K210_SYSCTL_EN_PERI, 11) \
-       GATE(K210_CLK_I2S2,   K210_SYSCTL_EN_PERI, 12) \
-       GATE(K210_CLK_I2C0,   K210_SYSCTL_EN_PERI, 13) \
-       GATE(K210_CLK_I2C1,   K210_SYSCTL_EN_PERI, 14) \
-       GATE(K210_CLK_I2C2,   K210_SYSCTL_EN_PERI, 15) \
-       GATE(K210_CLK_UART1,  K210_SYSCTL_EN_PERI, 16) \
-       GATE(K210_CLK_UART2,  K210_SYSCTL_EN_PERI, 17) \
-       GATE(K210_CLK_UART3,  K210_SYSCTL_EN_PERI, 18) \
-       GATE(K210_CLK_AES,    K210_SYSCTL_EN_PERI, 19) \
-       GATE(K210_CLK_FPIOA,  K210_SYSCTL_EN_PERI, 20) \
-       GATE(K210_CLK_TIMER0, K210_SYSCTL_EN_PERI, 21) \
-       GATE(K210_CLK_TIMER1, K210_SYSCTL_EN_PERI, 22) \
-       GATE(K210_CLK_TIMER2, K210_SYSCTL_EN_PERI, 23) \
-       GATE(K210_CLK_WDT0,   K210_SYSCTL_EN_PERI, 24) \
-       GATE(K210_CLK_WDT1,   K210_SYSCTL_EN_PERI, 25) \
-       GATE(K210_CLK_SHA,    K210_SYSCTL_EN_PERI, 26) \
-       GATE(K210_CLK_OTP,    K210_SYSCTL_EN_PERI, 27) \
-       GATE(K210_CLK_RTC,    K210_SYSCTL_EN_PERI, 29)
-
-#define _GATEIFY(id) K210_CLK_GATE_##id
-#define GATEIFY(id) _GATEIFY(id)
-
-enum k210_gate_id {
-#define GATE(id, ...) GATEIFY(id),
-       GATE_LIST
-#undef GATE
-       K210_CLK_GATE_NONE,
-};
-
-static const struct k210_gate_params k210_gates[] = {
-#define GATE(id, _off, _idx) \
-       [GATEIFY(id)] = { \
-               .off = (_off), \
-               .bit_idx = (_idx), \
-       },
-       GATE_LIST
-#undef GATE
-};
-
-#undef GATE_LIST
-
-/* The most parents is PLL2 */
-#define K210_CLK_MAX_PARENTS 3
-
-/**
- * struct k210_mux_params - Parameters for muxed clocks
- * @parents: A list of parent clock ids
- * @num_parents: The number of parent clocks
- * @off: The offset of the mux from the base sysctl address
- * @shift: The offset of the LSB of the mux selector
- * @width: The number of bits in the mux selector
- */
-struct k210_mux_params {
-       u8 parents[K210_CLK_MAX_PARENTS];
-       u8 num_parents;
-       u8 off;
-       u8 shift;
-       u8 width;
-};
-
-#define MUX(id, reg, shift, width) \
-       MUX_PARENTS(id, reg, shift, width, K210_CLK_IN0, K210_CLK_PLL0)
-#define MUX_LIST \
-       MUX_PARENTS(K210_CLK_PLL2, K210_SYSCTL_PLL2, 26, 2, \
-                   K210_CLK_IN0, K210_CLK_PLL0, K210_CLK_PLL1) \
-       MUX(K210_CLK_ACLK, K210_SYSCTL_SEL0, 0, 1) \
-       MUX(K210_CLK_SPI3,   K210_SYSCTL_SEL0, 12, 1) \
-       MUX(K210_CLK_TIMER0, K210_SYSCTL_SEL0, 13, 1) \
-       MUX(K210_CLK_TIMER1, K210_SYSCTL_SEL0, 14, 1) \
-       MUX(K210_CLK_TIMER2, K210_SYSCTL_SEL0, 15, 1)
-
-#define _MUXIFY(id) K210_CLK_MUX_##id
-#define MUXIFY(id) _MUXIFY(id)
-
-enum k210_mux_id {
-#define MUX_PARENTS(id, ...) MUXIFY(id),
-       MUX_LIST
-#undef MUX_PARENTS
-       K210_CLK_MUX_NONE,
-};
-
-static const struct k210_mux_params k210_muxes[] = {
-#define MUX_PARENTS(id, _off, _shift, _width, ...) \
-       [MUXIFY(id)] = { \
-               .parents = { __VA_ARGS__ }, \
-               .num_parents = __count_args(__VA_ARGS__), \
-               .off = (_off), \
-               .shift = (_shift), \
-               .width = (_width), \
-       },
-       MUX_LIST
-#undef MUX_PARENTS
-};
-
-#undef MUX
-#undef MUX_LIST
-
-/**
- * struct k210_pll_params - K210 PLL parameters
- * @off: The offset of the PLL from the base sysctl address
- * @shift: The offset of the LSB of the lock status
- * @width: The number of bits in the lock status
- */
-struct k210_pll_params {
-       u8 off;
-       u8 shift;
-       u8 width;
-};
-
-static const struct k210_pll_params k210_plls[] = {
-#define PLL(_off, _shift, _width) { \
-       .off = (_off), \
-       .shift = (_shift), \
-       .width = (_width), \
-}
-       [0] = PLL(K210_SYSCTL_PLL0,  0, 2),
-       [1] = PLL(K210_SYSCTL_PLL1,  8, 1),
-       [2] = PLL(K210_SYSCTL_PLL2, 16, 1),
-#undef PLL
-};
-
-/**
- * enum k210_clk_flags - The type of a K210 clock
- * @K210_CLKF_MUX: This clock has a mux and not a static parent
- * @K210_CLKF_PLL: This clock is a PLL
- */
-enum k210_clk_flags {
-       K210_CLKF_MUX = BIT(0),
-       K210_CLKF_PLL = BIT(1),
-};
-
-/**
- * struct k210_clk_params - The parameters defining a K210 clock
- * @name: The name of the clock
- * @flags: A set of &enum k210_clk_flags defining which fields are valid
- * @mux: An &enum k210_mux_id of this clock's mux
- * @parent: The clock id of this clock's parent
- * @pll: The id of the PLL (if this clock is a PLL)
- * @div: An &enum k210_div_id of this clock's divider
- * @gate: An &enum k210_gate_id of this clock's gate
- */
-struct k210_clk_params {
-#if CONFIG_IS_ENABLED(CMD_CLK)
-       const char *name;
-#endif
-       u8 flags;
-       union {
-               u8 parent;
-               u8 mux;
-       };
-       union {
-               u8 pll;
-               struct {
-                       u8 div;
-                       u8 gate;
-               };
-       };
-};
-
-static const struct k210_clk_params k210_clks[] = {
-#if CONFIG_IS_ENABLED(CMD_CLK)
-#define NAME(_name) .name = (_name),
-#else
-#define NAME(name)
-#endif
-#define CLK(id, _name, _parent, _div, _gate) \
-       [id] = { \
-               NAME(_name) \
-               .parent = (_parent), \
-               .div = (_div), \
-               .gate = (_gate), \
-       }
-#define CLK_MUX(id, _name, _mux, _div, _gate) \
-       [id] = { \
-               NAME(_name) \
-               .flags = K210_CLKF_MUX, \
-               .mux = (_mux), \
-               .div = (_div), \
-               .gate = (_gate), \
-       }
-#define CLK_PLL(id, _pll, _parent) \
-       [id] = { \
-               NAME("pll" #_pll) \
-               .flags = K210_CLKF_PLL, \
-               .parent = (_parent), \
-               .pll = (_pll), \
-       }
-#define CLK_FULL(id, name) \
-       CLK_MUX(id, name, MUXIFY(id), DIVIFY(id), GATEIFY(id))
-#define CLK_NOMUX(id, name, parent) \
-       CLK(id, name, parent, DIVIFY(id), GATEIFY(id))
-#define CLK_DIV(id, name, parent) \
-       CLK(id, name, parent, DIVIFY(id), K210_CLK_GATE_NONE)
-#define CLK_GATE(id, name, parent) \
-       CLK(id, name, parent, K210_CLK_DIV_NONE, GATEIFY(id))
-       CLK_PLL(K210_CLK_PLL0, 0, K210_CLK_IN0),
-       CLK_PLL(K210_CLK_PLL1, 1, K210_CLK_IN0),
-       [K210_CLK_PLL2] = {
-               NAME("pll2")
-               .flags = K210_CLKF_MUX | K210_CLKF_PLL,
-               .mux = MUXIFY(K210_CLK_PLL2),
-               .pll = 2,
-       },
-       CLK_MUX(K210_CLK_ACLK, "aclk", MUXIFY(K210_CLK_ACLK),
-               DIVIFY(K210_CLK_ACLK), K210_CLK_GATE_NONE),
-       CLK_FULL(K210_CLK_SPI3,   "spi3"),
-       CLK_FULL(K210_CLK_TIMER0, "timer0"),
-       CLK_FULL(K210_CLK_TIMER1, "timer1"),
-       CLK_FULL(K210_CLK_TIMER2, "timer2"),
-       CLK_NOMUX(K210_CLK_SRAM0, "sram0",  K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_SRAM1, "sram1",  K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_ROM,   "rom",    K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_DVP,   "dvp",    K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_APB0,  "apb0",   K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_APB1,  "apb1",   K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_APB2,  "apb2",   K210_CLK_ACLK),
-       CLK_NOMUX(K210_CLK_AI,    "ai",     K210_CLK_PLL1),
-       CLK_NOMUX(K210_CLK_I2S0,  "i2s0",   K210_CLK_PLL2),
-       CLK_NOMUX(K210_CLK_I2S1,  "i2s1",   K210_CLK_PLL2),
-       CLK_NOMUX(K210_CLK_I2S2,  "i2s2",   K210_CLK_PLL2),
-       CLK_NOMUX(K210_CLK_WDT0,  "wdt0",   K210_CLK_IN0),
-       CLK_NOMUX(K210_CLK_WDT1,  "wdt1",   K210_CLK_IN0),
-       CLK_NOMUX(K210_CLK_SPI0,  "spi0",   K210_CLK_PLL0),
-       CLK_NOMUX(K210_CLK_SPI1,  "spi1",   K210_CLK_PLL0),
-       CLK_NOMUX(K210_CLK_SPI2,  "spi2",   K210_CLK_PLL0),
-       CLK_NOMUX(K210_CLK_I2C0,  "i2c0",   K210_CLK_PLL0),
-       CLK_NOMUX(K210_CLK_I2C1,  "i2c1",   K210_CLK_PLL0),
-       CLK_NOMUX(K210_CLK_I2C2,  "i2c2",   K210_CLK_PLL0),
-       CLK_DIV(K210_CLK_I2S0_M,  "i2s0_m", K210_CLK_PLL2),
-       CLK_DIV(K210_CLK_I2S1_M,  "i2s1_m", K210_CLK_PLL2),
-       CLK_DIV(K210_CLK_I2S2_M,  "i2s2_m", K210_CLK_PLL2),
-       CLK_DIV(K210_CLK_CLINT,   "clint",  K210_CLK_ACLK),
-       CLK_GATE(K210_CLK_CPU,    "cpu",    K210_CLK_ACLK),
-       CLK_GATE(K210_CLK_DMA,    "dma",    K210_CLK_ACLK),
-       CLK_GATE(K210_CLK_FFT,    "fft",    K210_CLK_ACLK),
-       CLK_GATE(K210_CLK_GPIO,   "gpio",   K210_CLK_APB0),
-       CLK_GATE(K210_CLK_UART1,  "uart1",  K210_CLK_APB0),
-       CLK_GATE(K210_CLK_UART2,  "uart2",  K210_CLK_APB0),
-       CLK_GATE(K210_CLK_UART3,  "uart3",  K210_CLK_APB0),
-       CLK_GATE(K210_CLK_FPIOA,  "fpioa",  K210_CLK_APB0),
-       CLK_GATE(K210_CLK_SHA,    "sha",    K210_CLK_APB0),
-       CLK_GATE(K210_CLK_AES,    "aes",    K210_CLK_APB1),
-       CLK_GATE(K210_CLK_OTP,    "otp",    K210_CLK_APB1),
-       CLK_GATE(K210_CLK_RTC,    "rtc",    K210_CLK_IN0),
-#undef NAME
-#undef CLK_PLL
-#undef CLK
-#undef CLK_FULL
-#undef CLK_NOMUX
-#undef CLK_DIV
-#undef CLK_GATE
-#undef CLK_LIST
-};
-
-#define K210_PLL_CLKR          GENMASK(3, 0)
-#define K210_PLL_CLKF          GENMASK(9, 4)
-#define K210_PLL_CLKOD         GENMASK(13, 10) /* Output Divider */
-#define K210_PLL_BWADJ         GENMASK(19, 14) /* BandWidth Adjust */
-#define K210_PLL_RESET         BIT(20)
-#define K210_PLL_PWRD          BIT(21) /* PoWeReD */
-#define K210_PLL_INTFB         BIT(22) /* Internal FeedBack */
-#define K210_PLL_BYPASS                BIT(23)
-#define K210_PLL_TEST          BIT(24)
-#define K210_PLL_EN            BIT(25)
-#define K210_PLL_TEST_EN       BIT(26)
-
-#define K210_PLL_LOCK          0
-#define K210_PLL_CLEAR_SLIP    2
-#define K210_PLL_TEST_OUT      3
-
-#ifdef CONFIG_CLK_K210_SET_RATE
-static int k210_pll_enable(struct k210_clk_priv *priv, int id);
-static int k210_pll_disable(struct k210_clk_priv *priv, int id);
-static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
-
-/*
- * The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
- * General-Purpose PLL. The logical layout of the PLL with internal feedback is
- * approximately the following:
- *
- *  +---------------+
- *  |reference clock|
- *  +---------------+
- *          |
- *          v
- *        +--+
- *        |/r|
- *        +--+
- *          |
- *          v
- *   +-------------+
- *   |divided clock|
- *   +-------------+
- *          |
- *          v
- *  +--------------+
- *  |phase detector|<---+
- *  +--------------+    |
- *          |           |
- *          v   +--------------+
- *        +---+ |feedback clock|
- *        |VCO| +--------------+
- *        +---+         ^
- *          |    +--+   |
- *          +--->|/f|---+
- *          |    +--+
- *          v
- *        +---+
- *        |/od|
- *        +---+
- *          |
- *          v
- *       +------+
- *       |output|
- *       +------+
- *
- * The k210 PLLs have three factors: r, f, and od. Because of the feedback mode,
- * the effect of the division by f is to multiply the input frequency. The
- * equation for the output rate is
- *   rate = (rate_in * f) / (r * od).
- * Moving knowns to one side of the equation, we get
- *   rate / rate_in = f / (r * od)
- * Rearranging slightly,
- *   abs_error = abs((rate / rate_in) - (f / (r * od))).
- * To get relative, error, we divide by the expected ratio
- *   error = abs((rate / rate_in) - (f / (r * od))) / (rate / rate_in).
- * Simplifying,
- *   error = abs(1 - f / (r * od)) / (rate / rate_in)
- *   error = abs(1 - (f * rate_in) / (r * od * rate))
- * Using the constants ratio = rate / rate_in and inv_ratio = rate_in / rate,
- *   error = abs((f * inv_ratio) / (r * od) - 1)
- * This is the error used in evaluating parameters.
- *
- * r and od are four bits each, while f is six bits. Because r and od are
- * multiplied together, instead of the full 256 values possible if both bits
- * were used fully, there are only 97 distinct products. Combined with f, there
- * are 6208 theoretical settings for the PLL. However, most of these settings
- * can be ruled out immediately because they do not have the correct ratio.
- *
- * In addition to the constraint of approximating the desired ratio, parameters
- * must also keep internal pll frequencies within acceptable ranges. The divided
- * clock's minimum and maximum frequencies have a ratio of around 128.  This
- * leaves fairly substantial room to work with, especially since the only
- * affected parameter is r. The VCO's minimum and maximum frequency have a ratio
- * of 5, which is considerably more restrictive.
- *
- * The r and od factors are stored in a table. This is to make it easy to find
- * the next-largest product. Some products have multiple factorizations, but
- * only when one factor has at least a 2.5x ratio to the factors of the other
- * factorization. This is because any smaller ratio would not make a difference
- * when ensuring the VCO's frequency is within spec.
- *
- * Throughout the calculation function, fixed point arithmetic is used. Because
- * the range of rate and rate_in may be up to 1.75 GHz, or around 2^30, 64-bit
- * 32.32 fixed-point numbers are used to represent ratios. In general, to
- * implement division, the numerator is first multiplied by 2^32. This gives a
- * result where the whole number part is in the upper 32 bits, and the fraction
- * is in the lower 32 bits.
- *
- * In general, rounding is done to the closest integer. This helps find the best
- * approximation for the ratio. Rounding in one direction (e.g down) could cause
- * the function to miss a better ratio with one of the parameters increased by
- * one.
- */
-
-/*
- * The factors table was generated with the following python code:
- *
- * def p(x, y):
- *    return (1.0*x/y > 2.5) or (1.0*y/x > 2.5)
- *
- * factors = {}
- * for i in range(1, 17):
- *    for j in range(1, 17):
- *       fs = factors.get(i*j) or []
- *       if fs == [] or all([
- *             (p(i, x) and p(i, y)) or (p(j, x) and p(j, y))
- *             for (x, y) in fs]):
- *          fs.append((i, j))
- *          factors[i*j] = fs
- *
- * for k, l in sorted(factors.items()):
- *    for v in l:
- *       print("PACK(%s, %s)," % v)
- */
-#define PACK(r, od) (((((r) - 1) & 0xF) << 4) | (((od) - 1) & 0xF))
-#define UNPACK_R(val) ((((val) >> 4) & 0xF) + 1)
-#define UNPACK_OD(val) (((val) & 0xF) + 1)
-static const u8 factors[] = {
-       PACK(1, 1),
-       PACK(1, 2),
-       PACK(1, 3),
-       PACK(1, 4),
-       PACK(1, 5),
-       PACK(1, 6),
-       PACK(1, 7),
-       PACK(1, 8),
-       PACK(1, 9),
-       PACK(3, 3),
-       PACK(1, 10),
-       PACK(1, 11),
-       PACK(1, 12),
-       PACK(3, 4),
-       PACK(1, 13),
-       PACK(1, 14),
-       PACK(1, 15),
-       PACK(3, 5),
-       PACK(1, 16),
-       PACK(4, 4),
-       PACK(2, 9),
-       PACK(2, 10),
-       PACK(3, 7),
-       PACK(2, 11),
-       PACK(2, 12),
-       PACK(5, 5),
-       PACK(2, 13),
-       PACK(3, 9),
-       PACK(2, 14),
-       PACK(2, 15),
-       PACK(2, 16),
-       PACK(3, 11),
-       PACK(5, 7),
-       PACK(3, 12),
-       PACK(3, 13),
-       PACK(4, 10),
-       PACK(3, 14),
-       PACK(4, 11),
-       PACK(3, 15),
-       PACK(3, 16),
-       PACK(7, 7),
-       PACK(5, 10),
-       PACK(4, 13),
-       PACK(6, 9),
-       PACK(5, 11),
-       PACK(4, 14),
-       PACK(4, 15),
-       PACK(7, 9),
-       PACK(4, 16),
-       PACK(5, 13),
-       PACK(6, 11),
-       PACK(5, 14),
-       PACK(6, 12),
-       PACK(5, 15),
-       PACK(7, 11),
-       PACK(6, 13),
-       PACK(5, 16),
-       PACK(9, 9),
-       PACK(6, 14),
-       PACK(8, 11),
-       PACK(6, 15),
-       PACK(7, 13),
-       PACK(6, 16),
-       PACK(7, 14),
-       PACK(9, 11),
-       PACK(10, 10),
-       PACK(8, 13),
-       PACK(7, 15),
-       PACK(9, 12),
-       PACK(10, 11),
-       PACK(7, 16),
-       PACK(9, 13),
-       PACK(8, 15),
-       PACK(11, 11),
-       PACK(9, 14),
-       PACK(8, 16),
-       PACK(10, 13),
-       PACK(11, 12),
-       PACK(9, 15),
-       PACK(10, 14),
-       PACK(11, 13),
-       PACK(9, 16),
-       PACK(10, 15),
-       PACK(11, 14),
-       PACK(12, 13),
-       PACK(10, 16),
-       PACK(11, 15),
-       PACK(12, 14),
-       PACK(13, 13),
-       PACK(11, 16),
-       PACK(12, 15),
-       PACK(13, 14),
-       PACK(12, 16),
-       PACK(13, 15),
-       PACK(14, 14),
-       PACK(13, 16),
-       PACK(14, 15),
-       PACK(14, 16),
-       PACK(15, 15),
-       PACK(15, 16),
-       PACK(16, 16),
-};
-
-TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
-                                    struct k210_pll_config *best)
-{
-       int i;
-       s64 error, best_error;
-       u64 ratio, inv_ratio; /* fixed point 32.32 ratio of the rates */
-       u64 max_r;
-       u64 r, f, od;
-
-       /*
-        * Can't go over 1.75 GHz or under 21.25 MHz due to limitations on the
-        * VCO frequency. These are not the same limits as below because od can
-        * reduce the output frequency by 16.
-        */
-       if (rate > 1750000000 || rate < 21250000)
-               return -EINVAL;
-
-       /* Similar restrictions on the input rate */
-       if (rate_in > 1750000000 || rate_in < 13300000)
-               return -EINVAL;
-
-       ratio = DIV_ROUND_CLOSEST_ULL((u64)rate << 32, rate_in);
-       inv_ratio = DIV_ROUND_CLOSEST_ULL((u64)rate_in << 32, rate);
-       /* Can't increase by more than 64 or reduce by more than 256 */
-       if (rate > rate_in && ratio > (64ULL << 32))
-               return -EINVAL;
-       else if (rate <= rate_in && inv_ratio > (256ULL << 32))
-               return -EINVAL;
-
-       /*
-        * The divided clock (rate_in / r) must stay between 1.75 GHz and 13.3
-        * MHz. There is no minimum, since the only way to get a higher input
-        * clock than 26 MHz is to use a clock generated by a PLL. Because PLLs
-        * cannot output frequencies greater than 1.75 GHz, the minimum would
-        * never be greater than one.
-        */
-       max_r = DIV_ROUND_DOWN_ULL(rate_in, 13300000);
-
-       /* Variables get immediately incremented, so start at -1th iteration */
-       i = -1;
-       f = 0;
-       r = 0;
-       od = 0;
-       best_error = S64_MAX;
-       error = best_error;
-       /* do-while here so we always try at least one ratio */
-       do {
-               /*
-                * Whether we swapped r and od while enforcing frequency limits
-                */
-               bool swapped = false;
-               /*
-                * Whether the intermediate frequencies are out-of-spec
-                */
-               bool out_of_spec;
-               u64 last_od = od;
-               u64 last_r = r;
-
-               /*
-                * Try the next largest value for f (or r and od) and
-                * recalculate the other parameters based on that
-                */
-               if (rate > rate_in) {
-                       /*
-                        * Skip factors of the same product if we already tried
-                        * out that product
-                        */
-                       do {
-                               i++;
-                               r = UNPACK_R(factors[i]);
-                               od = UNPACK_OD(factors[i]);
-                       } while (i + 1 < ARRAY_SIZE(factors) &&
-                                r * od == last_r * last_od);
-
-                       /* Round close */
-                       f = (r * od * ratio + BIT(31)) >> 32;
-                       if (f > 64)
-                               f = 64;
-               } else {
-                       u64 tmp = ++f * inv_ratio;
-                       bool round_up = !!(tmp & BIT(31));
-                       u32 goal = (tmp >> 32) + round_up;
-                       u32 err, last_err;
-
-                       /* Get the next r/od pair in factors */
-                       while (r * od < goal && i + 1 < ARRAY_SIZE(factors)) {
-                               i++;
-                               r = UNPACK_R(factors[i]);
-                               od = UNPACK_OD(factors[i]);
-                       }
-
-                       /*
-                        * This is a case of double rounding. If we rounded up
-                        * above, we need to round down (in cases of ties) here.
-                        * This prevents off-by-one errors resulting from
-                        * choosing X+2 over X when X.Y rounds up to X+1 and
-                        * there is no r * od = X+1. For the converse, when X.Y
-                        * is rounded down to X, we should choose X+1 over X-1.
-                        */
-                       err = abs(r * od - goal);
-                       last_err = abs(last_r * last_od - goal);
-                       if (last_err < err || (round_up && last_err == err)) {
-                               i--;
-                               r = last_r;
-                               od = last_od;
-                       }
-               }
-
-               /*
-                * Enforce limits on internal clock frequencies. If we
-                * aren't in spec, try swapping r and od. If everything is
-                * in-spec, calculate the relative error.
-                */
-again:
-               out_of_spec = false;
-               if (r > max_r) {
-                       out_of_spec = true;
-               } else {
-                       /*
-                        * There is no way to only divide once; we need
-                        * to examine the frequency with and without the
-                        * effect of od.
-                        */
-                       u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r);
-
-                       if (vco > 1750000000 || vco < 340000000)
-                               out_of_spec = true;
-               }
-
-               if (out_of_spec) {
-                       u64 new_r, new_od;
-
-                       if (!swapped) {
-                               u64 tmp = r;
-
-                               r = od;
-                               od = tmp;
-                               swapped = true;
-                               goto again;
-                       }
-
-                       /*
-                        * Try looking ahead to see if there are additional
-                        * factors for the same product.
-                        */
-                       if (i + 1 < ARRAY_SIZE(factors)) {
-                               i++;
-                               new_r = UNPACK_R(factors[i]);
-                               new_od = UNPACK_OD(factors[i]);
-                               if (r * od == new_r * new_od) {
-                                       r = new_r;
-                                       od = new_od;
-                                       swapped = false;
-                                       goto again;
-                               }
-                               i--;
-                       }
-
-                       /*
-                        * Try looking back to see if there is a worse ratio
-                        * that we could try anyway
-                        */
-                       while (i > 0) {
-                               i--;
-                               new_r = UNPACK_R(factors[i]);
-                               new_od = UNPACK_OD(factors[i]);
-                               /*
-                                * Don't loop over factors for the same product
-                                * to avoid getting stuck because of the above
-                                * clause
-                                */
-                               if (r * od != new_r * new_od) {
-                                       if (new_r * new_od > last_r * last_od) {
-                                               r = new_r;
-                                               od = new_od;
-                                               swapped = false;
-                                               goto again;
-                                       }
-                                       break;
-                               }
-                       }
-
-                       /* We ran out of things to try */
-                       continue;
-               }
-
-               error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od);
-               /* The lower 16 bits are spurious */
-               error = abs((error - BIT(32))) >> 16;
-
-               if (error < best_error) {
-                       best->r = r;
-                       best->f = f;
-                       best->od = od;
-                       best_error = error;
-               }
-       } while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0);
-
-       log_debug("best error %lld\n", best_error);
-       if (best_error == S64_MAX)
-               return -EINVAL;
-
-       return 0;
-}
-
-static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
-                              ulong rate_in)
-{
-       int err;
-       const struct k210_pll_params *pll = &k210_plls[id];
-       struct k210_pll_config config = {};
-       u32 reg;
-       ulong calc_rate;
-
-       err = k210_pll_calc_config(rate, rate_in, &config);
-       if (err)
-               return err;
-       log_debug("Got r=%u f=%u od=%u\n", config.r, config.f, config.od);
-
-       /* Don't bother setting the rate if we're already at that rate */
-       calc_rate = DIV_ROUND_DOWN_ULL(((u64)rate_in) * config.f,
-                                      config.r * config.od);
-       if (calc_rate == k210_pll_get_rate(priv, id, rate))
-               return calc_rate;
-
-       k210_pll_disable(priv, id);
-
-       reg = readl(priv->base + pll->off);
-       reg &= ~K210_PLL_CLKR
-           &  ~K210_PLL_CLKF
-           &  ~K210_PLL_CLKOD
-           &  ~K210_PLL_BWADJ;
-       reg |= FIELD_PREP(K210_PLL_CLKR, config.r - 1)
-           |  FIELD_PREP(K210_PLL_CLKF, config.f - 1)
-           |  FIELD_PREP(K210_PLL_CLKOD, config.od - 1)
-           |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
-       writel(reg, priv->base + pll->off);
-
-       k210_pll_enable(priv, id);
-
-       serial_setbrg();
-       return k210_pll_get_rate(priv, id, rate);
-}
-#else
-static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
-                              ulong rate_in)
-{
-       return -ENOSYS;
-}
-#endif /* CONFIG_CLK_K210_SET_RATE */
-
-static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id,
-                              ulong rate_in)
-{
-       u64 r, f, od;
-       u32 reg = readl(priv->base + k210_plls[id].off);
-
-       if (reg & K210_PLL_BYPASS)
-               return rate_in;
-
-       if (!(reg & K210_PLL_PWRD))
-               return 0;
-
-       r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
-       f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
-       od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
-
-       return DIV_ROUND_DOWN_ULL(((u64)rate_in) * f, r * od);
-}
-
-/*
- * Wait for the PLL to be locked. If the PLL is not locked, try clearing the
- * slip before retrying
- */
-static void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
-{
-       const struct k210_pll_params *pll = &k210_plls[id];
-       u32 mask = (BIT(pll->width) - 1) << pll->shift;
-
-       while (true) {
-               u32 reg = readl(priv->base + K210_SYSCTL_PLL_LOCK);
-
-               if ((reg & mask) == mask)
-                       break;
-
-               reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
-               writel(reg, priv->base + K210_SYSCTL_PLL_LOCK);
-       }
-}
-
-static bool k210_pll_enabled(u32 reg)
-{
-       return (reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
-               !(reg & K210_PLL_RESET);
-}
-
-/* Adapted from sysctl_pll_enable */
-static int k210_pll_enable(struct k210_clk_priv *priv, int id)
-{
-       const struct k210_pll_params *pll = &k210_plls[id];
-       u32 reg = readl(priv->base + pll->off);
-
-       if (k210_pll_enabled(reg))
-               return 0;
-
-       reg |= K210_PLL_PWRD;
-       writel(reg, priv->base + pll->off);
-
-       /* Ensure reset is low before asserting it */
-       reg &= ~K210_PLL_RESET;
-       writel(reg, priv->base + pll->off);
-       reg |= K210_PLL_RESET;
-       writel(reg, priv->base + pll->off);
-       nop();
-       nop();
-       reg &= ~K210_PLL_RESET;
-       writel(reg, priv->base + pll->off);
-
-       k210_pll_waitfor_lock(priv, id);
-
-       reg &= ~K210_PLL_BYPASS;
-       reg |= K210_PLL_EN;
-       writel(reg, priv->base + pll->off);
-
-       return 0;
-}
-
-static int k210_pll_disable(struct k210_clk_priv *priv, int id)
-{
-       const struct k210_pll_params *pll = &k210_plls[id];
-       u32 reg = readl(priv->base + pll->off);
-
-       /*
-        * Bypassing before powering off is important so child clocks don't stop
-        * working. This is especially important for pll0, the indirect parent
-        * of the cpu clock.
-        */
-       reg |= K210_PLL_BYPASS;
-       writel(reg, priv->base + pll->off);
-
-       reg &= ~K210_PLL_PWRD;
-       reg &= ~K210_PLL_EN;
-       writel(reg, priv->base + pll->off);
-       return 0;
-}
-
-static u32 k210_clk_readl(struct k210_clk_priv *priv, u8 off, u8 shift,
-                         u8 width)
-{
-       u32 reg = readl(priv->base + off);
-
-       return (reg >> shift) & (BIT(width) - 1);
-}
-
-static void k210_clk_writel(struct k210_clk_priv *priv, u8 off, u8 shift,
-                           u8 width, u32 val)
-{
-       u32 reg = readl(priv->base + off);
-       u32 mask = (BIT(width) - 1) << shift;
-
-       reg &= ~mask;
-       reg |= mask & (val << shift);
-       writel(reg, priv->base + off);
-}
-
-static int k210_clk_get_parent(struct k210_clk_priv *priv, int id)
-{
-       u32 sel;
-       const struct k210_mux_params *mux;
-
-       if (!(k210_clks[id].flags & K210_CLKF_MUX))
-               return k210_clks[id].parent;
-       mux = &k210_muxes[k210_clks[id].mux];
-
-       sel = k210_clk_readl(priv, mux->off, mux->shift, mux->width);
-       assert(sel < mux->num_parents);
-       return mux->parents[sel];
-}
-
-static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id)
-{
-       int parent;
-       u32 val;
-       ulong parent_rate;
-       const struct k210_div_params *div;
-
-       if (id == K210_CLK_IN0)
-               return clk_get_rate(&priv->in0);
-
-       parent = k210_clk_get_parent(priv, id);
-       parent_rate = do_k210_clk_get_rate(priv, parent);
-       if (IS_ERR_VALUE(parent_rate))
-               return parent_rate;
-
-       if (k210_clks[id].flags & K210_CLKF_PLL)
-               return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate);
-
-       if (k210_clks[id].div == K210_CLK_DIV_NONE)
-               return parent_rate;
-       div = &k210_divs[k210_clks[id].div];
-
-       if (div->type == K210_DIV_FIXED)
-               return parent_rate / div->div;
-
-       val = k210_clk_readl(priv, div->off, div->shift, div->width);
-       switch (div->type) {
-       case K210_DIV_ONE:
-               return parent_rate / (val + 1);
-       case K210_DIV_EVEN:
-               return parent_rate / 2 / (val + 1);
-       case K210_DIV_POWER:
-               /* This is ACLK, which has no divider on IN0 */
-               if (parent == K210_CLK_IN0)
-                       return parent_rate;
-               return parent_rate / (2 << val);
-       default:
-               assert(false);
-               return -EINVAL;
-       };
-}
-
-static ulong k210_clk_get_rate(struct clk *clk)
-{
-       return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
-}
-
-static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
-{
-       int i;
-       const struct k210_mux_params *mux;
-
-       if (!(k210_clks[id].flags & K210_CLKF_MUX))
-               return -ENOSYS;
-       mux = &k210_muxes[k210_clks[id].mux];
-
-       for (i = 0; i < mux->num_parents; i++) {
-               if (mux->parents[i] == new) {
-                       k210_clk_writel(priv, mux->off, mux->shift, mux->width,
-                                       i);
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       return do_k210_clk_set_parent(dev_get_priv(clk->dev), clk->id,
-                                     parent->id);
-}
-
-static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       int parent, ret, err;
-       ulong rate_in, val;
-       const struct k210_div_params *div;
-       struct k210_clk_priv *priv = dev_get_priv(clk->dev);
-
-       if (clk->id == K210_CLK_IN0)
-               return clk_set_rate(&priv->in0, rate);
-
-       parent = k210_clk_get_parent(priv, clk->id);
-       rate_in = do_k210_clk_get_rate(priv, parent);
-       if (IS_ERR_VALUE(rate_in))
-               return rate_in;
-
-       log_debug("id=%ld rate=%lu rate_in=%lu\n", clk->id, rate, rate_in);
-
-       if (clk->id == K210_CLK_PLL0) {
-               /* Bypass ACLK so the CPU keeps going */
-               ret = do_k210_clk_set_parent(priv, K210_CLK_ACLK, K210_CLK_IN0);
-               if (ret)
-                       return ret;
-       } else if (clk->id == K210_CLK_PLL1 && gd->flags & GD_FLG_RELOC) {
-               /*
-                * We can't bypass the AI clock like we can ACLK, and after
-                * relocation we are using the AI ram.
-                */
-               return -EPERM;
-       }
-
-       if (k210_clks[clk->id].flags & K210_CLKF_PLL) {
-               ret = k210_pll_set_rate(priv, k210_clks[clk->id].pll, rate,
-                                       rate_in);
-               if (!IS_ERR_VALUE(ret) && clk->id == K210_CLK_PLL0) {
-                       /*
-                        * This may have the side effect of reparenting ACLK,
-                        * but I don't really want to keep track of what the old
-                        * parent was.
-                        */
-                       err = do_k210_clk_set_parent(priv, K210_CLK_ACLK,
-                                                    K210_CLK_PLL0);
-                       if (err)
-                               return err;
-               }
-               return ret;
-       }
-
-       if (k210_clks[clk->id].div == K210_CLK_DIV_NONE)
-               return -ENOSYS;
-       div = &k210_divs[k210_clks[clk->id].div];
-
-       switch (div->type) {
-       case K210_DIV_ONE:
-               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
-               val = val ? val - 1 : 0;
-               break;
-       case K210_DIV_EVEN:
-               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, 2 * rate);
-               break;
-       case K210_DIV_POWER:
-               /* This is ACLK, which has no divider on IN0 */
-               if (parent == K210_CLK_IN0)
-                       return -ENOSYS;
-
-               val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
-               val = __ffs(val);
-               break;
-       default:
-               assert(false);
-               return -EINVAL;
-       };
-
-       val = val ? val - 1 : 0;
-       k210_clk_writel(priv, div->off, div->shift, div->width, val);
-       return do_k210_clk_get_rate(priv, clk->id);
-}
-
-static int k210_clk_endisable(struct k210_clk_priv *priv, int id, bool enable)
-{
-       int parent = k210_clk_get_parent(priv, id);
-       const struct k210_gate_params *gate;
-
-       if (id == K210_CLK_IN0) {
-               if (enable)
-                       return clk_enable(&priv->in0);
-               else
-                       return clk_disable(&priv->in0);
-       }
-
-       /* Only recursively enable clocks since we don't track refcounts */
-       if (enable) {
-               int ret = k210_clk_endisable(priv, parent, true);
-
-               if (ret && ret != -ENOSYS)
-                       return ret;
-       }
-
-       if (k210_clks[id].flags & K210_CLKF_PLL) {
-               if (enable)
-                       return k210_pll_enable(priv, k210_clks[id].pll);
-               else
-                       return k210_pll_disable(priv, k210_clks[id].pll);
-       }
-
-       if (k210_clks[id].gate == K210_CLK_GATE_NONE)
-               return -ENOSYS;
-       gate = &k210_gates[k210_clks[id].gate];
-
-       k210_clk_writel(priv, gate->off, gate->bit_idx, 1, enable);
-       return 0;
-}
-
-static int k210_clk_enable(struct clk *clk)
-{
-       return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, true);
-}
-
-static int k210_clk_disable(struct clk *clk)
-{
-       return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, false);
-}
-
-static int k210_clk_request(struct clk *clk)
-{
-       if (clk->id >= ARRAY_SIZE(k210_clks))
-               return -EINVAL;
-       return 0;
-}
-
-static const struct clk_ops k210_clk_ops = {
-       .request = k210_clk_request,
-       .set_rate = k210_clk_set_rate,
-       .get_rate = k210_clk_get_rate,
-       .set_parent = k210_clk_set_parent,
-       .enable = k210_clk_enable,
-       .disable = k210_clk_disable,
-};
-
-static int k210_clk_probe(struct udevice *dev)
-{
-       int ret;
-       struct k210_clk_priv *priv = dev_get_priv(dev);
-
-       priv->base = dev_read_addr_ptr(dev_get_parent(dev));
-       if (!priv->base)
-               return -EINVAL;
-
-       ret = clk_get_by_index(dev, 0, &priv->in0);
-       if (ret)
-               return ret;
-
-       /*
-        * Force setting defaults, even before relocation. This is so we can
-        * set the clock rate for PLL1 before we relocate into aisram.
-        */
-       if (!(gd->flags & GD_FLG_RELOC))
-               clk_set_defaults(dev, CLK_DEFAULTS_POST_FORCE);
-
-       return 0;
-}
-
-static const struct udevice_id k210_clk_ids[] = {
-       { .compatible = "kendryte,k210-clk" },
-       { },
-};
-
-U_BOOT_DRIVER(k210_clk) = {
-       .name = "k210_clk",
-       .id = UCLASS_CLK,
-       .of_match = k210_clk_ids,
-       .ops = &k210_clk_ops,
-       .probe = k210_clk_probe,
-       .priv_auto = sizeof(struct k210_clk_priv),
-};
-
-#if CONFIG_IS_ENABLED(CMD_CLK)
-static char show_enabled(struct k210_clk_priv *priv, int id)
-{
-       bool enabled;
-
-       if (k210_clks[id].flags & K210_CLKF_PLL) {
-               const struct k210_pll_params *pll =
-                       &k210_plls[k210_clks[id].pll];
-
-               enabled = k210_pll_enabled(readl(priv->base + pll->off));
-       } else if (k210_clks[id].gate == K210_CLK_GATE_NONE) {
-               return '-';
-       } else {
-               const struct k210_gate_params *gate =
-                       &k210_gates[k210_clks[id].gate];
-
-               enabled = k210_clk_readl(priv, gate->off, gate->bit_idx, 1);
-       }
-
-       return enabled ? 'y' : 'n';
-}
-
-static void show_clks(struct k210_clk_priv *priv, int id, int depth)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(k210_clks); i++) {
-               if (k210_clk_get_parent(priv, i) != id)
-                       continue;
-
-               printf(" %-9lu %-7c %*s%s\n", do_k210_clk_get_rate(priv, i),
-                      show_enabled(priv, i), depth * 4, "",
-                      k210_clks[i].name);
-
-               show_clks(priv, i, depth + 1);
-       }
-}
-
-int soc_clk_dump(void)
-{
-       int ret;
-       struct udevice *dev;
-       struct k210_clk_priv *priv;
-
-       ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(k210_clk),
-                                         &dev);
-       if (ret)
-               return ret;
-       priv = dev_get_priv(dev);
-
-       puts(" Rate      Enabled Name\n");
-       puts("------------------------\n");
-       printf(" %-9lu %-7c %*s%s\n", clk_get_rate(&priv->in0), 'y', 0, "",
-              priv->in0.dev->name);
-       show_clks(priv, K210_CLK_IN0, 1);
-       return 0;
-}
-#endif
index fd736a7f640a95b1c47a27dded6c95b24b17702c..df37c32033fb3e7907cf1d1ff9593a088907ef6c 100644 (file)
@@ -18,7 +18,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_K210)     += pinctrl-k210.o
 obj-$(CONFIG_PINCTRL_MESON)    += meson/
 obj-$(CONFIG_PINCTRL_MTK)      += mediatek/
 obj-$(CONFIG_PINCTRL_MSCC)     += mscc/
diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c
new file mode 100644 (file)
index 0000000..bb5153c
--- /dev/null
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <[email protected]>
+ */
+
+#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_SL | K210_PC_OE | \
+                          K210_PC_PU)
+#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | K210_PC_OE_INV | K210_PC_IE_INV)
+#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] = "B3",
+       [4] = "B4",
+       [5] = "B5",
+       [6] = "C6",
+       [7] = "C7",
+};
+
+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_SCCB,
+       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(SCCB),
+       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,      SCCB),
+       FUNC(SCCB_SDA,       SCCB),
+       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, "canaan,k210-sysctl");
+       if (IS_ERR(priv->sysctl)) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = dev_read_u32(dev, "canaan,k210-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 = "canaan,k210-fpioa" },
+       { }
+};
+
+U_BOOT_DRIVER(pinctrl_k210) = {
+       .name = "pinctrl_k210",
+       .id = UCLASS_PINCTRL,
+       .of_match = k210_pc_ids,
+       .probe = k210_pc_probe,
+       .priv_auto      = sizeof(struct k210_pc_priv),
+       .ops = &k210_pc_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/pinctrl-kendryte.c b/drivers/pinctrl/pinctrl-kendryte.c
deleted file mode 100644 (file)
index 09d51ca..0000000
+++ /dev/null
@@ -1,740 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2020 Sean Anderson <[email protected]>
- */
-
-#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_SL | K210_PC_OE | \
-                          K210_PC_PU)
-#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | K210_PC_OE_INV | K210_PC_IE_INV)
-#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] = "B3",
-       [4] = "B4",
-       [5] = "B5",
-       [6] = "C6",
-       [7] = "C7",
-};
-
-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_SCCB,
-       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(SCCB),
-       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,      SCCB),
-       FUNC(SCCB_SDA,       SCCB),
-       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      = sizeof(struct k210_pc_priv),
-       .ops = &k210_pc_pinctrl_ops,
-};
index fc22f540fe63be203947599a19dea47fcd4d1a26..9200efced96aa9ce2d1baeb7e6b6d8d80ddb991b 100644 (file)
@@ -758,8 +758,8 @@ static const struct udevice_id dw_spi_ids[] = {
         */
        { .compatible = "altr,socfpga-spi", .data = (ulong)dw_spi_apb_init },
        { .compatible = "altr,socfpga-arria10-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "canaan,kendryte-k210-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "canaan,kendryte-k210-ssi", .data = (ulong)dw_spi_dwc_init },
+       { .compatible = "canaan,k210-spi", .data = (ulong)dw_spi_apb_init },
+       { .compatible = "canaan,k210-ssi", .data = (ulong)dw_spi_dwc_init },
        { .compatible = "intel,stratix10-spi", .data = (ulong)dw_spi_apb_init },
        { .compatible = "intel,agilex-spi", .data = (ulong)dw_spi_apb_init },
        { .compatible = "mscc,ocelot-spi", .data = (ulong)dw_spi_apb_init },
index 1f74702ea7fc6cfc7257b499b8e3d5d785054ec9..1cc2992c804565d8407d47090003e22071831226 100644 (file)
@@ -20,7 +20,7 @@
        "fdt_addr_r=0x80400000\0" \
        "scriptaddr=0x80020000\0" \
        "kernel_addr_r=0x80060000\0" \
-       "fdtfile=kendryte/" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" \
+       "fdtfile=k210/" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" \
        "k210_bootcmd=load mmc 0:1 $loadaddr /uImage && " \
                "load mmc 0:1 $fdt_addr_r /k210.dtb && " \
                "bootm $loadaddr - $fdt_addr_r\0"
diff --git a/include/k210/pll.h b/include/k210/pll.h
new file mode 100644 (file)
index 0000000..fd16a89
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019-20 Sean Anderson <[email protected]>
+ */
+#ifndef K210_PLL_H
+#define K210_PLL_H
+
+#include <test/export.h>
+
+struct k210_pll_config {
+       u8 r;
+       u8 f;
+       u8 od;
+};
+
+#ifdef CONFIG_UNIT_TEST
+TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
+                                    struct k210_pll_config *best);
+#ifndef nop
+#define nop()
+#endif
+
+#endif
+#endif /* K210_PLL_H */
diff --git a/include/kendryte/pll.h b/include/kendryte/pll.h
deleted file mode 100644 (file)
index fd16a89..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2019-20 Sean Anderson <[email protected]>
- */
-#ifndef K210_PLL_H
-#define K210_PLL_H
-
-#include <test/export.h>
-
-struct k210_pll_config {
-       u8 r;
-       u8 f;
-       u8 od;
-};
-
-#ifdef CONFIG_UNIT_TEST
-TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
-                                    struct k210_pll_config *best);
-#ifndef nop
-#define nop()
-#endif
-
-#endif
-#endif /* K210_PLL_H */
index f55379f33659b469e82a8dddab26d41e4125be71..a0cc84c396161acc7a951cdbcf74f226fa1a3aa2 100644 (file)
@@ -7,7 +7,7 @@
 /* For DIV_ROUND_DOWN_ULL, defined in linux/kernel.h */
 #include <div64.h>
 #include <dm/test.h>
-#include <kendryte/pll.h>
+#include <k210/pll.h>
 #include <test/ut.h>
 
 static int dm_test_k210_pll_calc_config(u32 rate, u32 rate_in,
This page took 0.204368 seconds and 4 git commands to generate.