diff --git a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml new file mode 100644 index 00000000000000..c7ed1f96382afc --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml @@ -0,0 +1,168 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/ultrarisc,dp1000-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: UltraRISC DP1000 Pin Controller +maintainers: + - Jia Wang + +description: | + UltraRISC RISC-V SoC DP1000 pin controller. + + The binding supports two child node styles under the same controller + compatible: + + - legacy DP1000-specific nodes using phandle-array properties + `pinctrl-pins` and `pinconf-pins` + - generic pinctrl nodes using `pins`, `function` and generic pin + configuration properties + +properties: + compatible: + const: ultrarisc,dp1000-pinctrl + + reg: + maxItems: 1 + + "#pinctrl-cells": + $ref: /schemas/types.yaml#/definitions/uint32 + +patternProperties: + '.*-pins$': + type: object + allOf: + - $ref: /schemas/pinctrl/pincfg-node.yaml# + - $ref: /schemas/pinctrl/pinmux-node.yaml# + additionalProperties: false + properties: + pinctrl-pins: + description: | + The list of pins and their mux settings that properties in the node + apply to. The format: `PORT PIN FUNCTION`. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + pinconf-pins: + description: | + The list of pins and their pad configuration that properties in the + node apply to. The format: `PORT PIN CONF`. + CONF is a DP1000-specific encoding of pull and drive strength as + defined in dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 32 + pins: + description: List of pins affected by this state node. + minItems: 1 + uniqueItems: true + items: + type: string + pattern: '^(PA([0-9]|1[0-5])|P[BCD][0-7]|LPC([0-9]|1[0-2]))$' + + function: + description: | + Mux function to select for the listed pins. + gpio maps to the hardware default mode. The default mode is + GPIO for PA/PB/PC/PD pins and LPC for LPC pins. + func1 is not supported on LPC pins. + enum: + - gpio + - func0 + - func1 + + bias-disable: true + bias-high-impedance: true + bias-pull-up: true + bias-pull-down: true + + drive-strength: + description: Output drive strength in mA. + enum: [20, 27, 33, 40] + + oneOf: + - allOf: + - anyOf: + - required: [pinctrl-pins] + - required: [pinconf-pins] + - not: + required: [pins] + - allOf: + - required: [pins] + - not: + anyOf: + - required: [pinctrl-pins] + - required: [pinconf-pins] + +unevaluatedProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + pinmux@11081000 { + compatible = "ultrarisc,dp1000-pinctrl"; + reg = <0x0 0x11081000 0x0 0x1000>; + #pinctrl-cells = <2>; + + i2c0-pins { + pins = "PA12", "PA13"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart0-pins { + pins = "PA8", "PA9"; + function = "func1"; + bias-pull-up; + drive-strength = <33>; + }; + }; + }; + + - | + /* Legacy example */ + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + pinmux@11081000 { + compatible = "ultrarisc,dp1000-pinctrl"; + reg = <0x0 0x11081000 0x0 0x1000>; + #pinctrl-cells = <2>; + + i2c0-pins { + pinctrl-pins = < + UR_DP1000_IOMUX_A 12 UR_DP1000_FUNC0 + UR_DP1000_IOMUX_A 13 UR_DP1000_FUNC0 + >; + + pinconf-pins = < + UR_DP1000_IOMUX_A 12 UR_DP1000_BIAS(UR_DP1000_PULL_UP, + UR_DP1000_DRIVE_DEF) + UR_DP1000_IOMUX_A 13 UR_DP1000_BIAS(UR_DP1000_PULL_UP, + UR_DP1000_DRIVE_DEF) + >; + }; + + uart0-pins { + pinctrl-pins = < + UR_DP1000_IOMUX_A 8 UR_DP1000_FUNC1 + UR_DP1000_IOMUX_A 9 UR_DP1000_FUNC1 + >; + + pinconf-pins = < + UR_DP1000_IOMUX_A 8 UR_DP1000_BIAS(UR_DP1000_PULL_UP, + UR_DP1000_DRIVE_DEF) + UR_DP1000_IOMUX_A 9 UR_DP1000_BIAS(UR_DP1000_PULL_UP, + UR_DP1000_DRIVE_DEF) + >; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml index 5feeb2203050ae..9f522671770191 100644 --- a/Documentation/devicetree/bindings/riscv/cpus.yaml +++ b/Documentation/devicetree/bindings/riscv/cpus.yaml @@ -67,6 +67,7 @@ properties: - thead,c908 - thead,c910 - thead,c920 + - ultrarisc,cp100 - const: riscv - items: - enum: diff --git a/Documentation/devicetree/bindings/riscv/ultrarisc.yaml b/Documentation/devicetree/bindings/riscv/ultrarisc.yaml new file mode 100644 index 00000000000000..d4421c2ef9456d --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/ultrarisc.yaml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/ultrarisc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: UltraRISC SoC-based boards + +maintainers: + - Jia Wang + +description: + UltraRISC DP1000 SoC-based boards + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - items: + - enum: + - rongda,m0 + - milkv,titan + - const: ultrarisc,dp1000 + +additionalProperties: true +... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 28784d66ae7ba5..04e593c66c7c4a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1407,6 +1407,8 @@ patternProperties: description: Rockchip Electronics Co., Ltd. "^rocktech,.*": description: ROCKTECH DISPLAYS LIMITED + "^rongda,.*": + description: Shenzhen Rongda Computer Co., Ltd. "^rohm,.*": description: ROHM Semiconductor Co., Ltd "^ronbo,.*": diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd1638..8e6d55e0504d8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23044,6 +23044,13 @@ F: include/dt-bindings/power/thead,th1520-power.h F: include/dt-bindings/reset/thead,th1520-reset.h F: include/linux/firmware/thead/thead,th1520-aon.h +RISC-V ULTRARISC SoC SUPPORT +M: Jia Wang +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/riscv/ultrarisc.yaml +F: arch/riscv/boot/dts/ultrarisc/ + RNBD BLOCK DRIVERS M: Md. Haris Iqbal M: Jack Wang @@ -27312,6 +27319,14 @@ S: Maintained F: drivers/usb/common/ulpi.c F: include/linux/ulpi/ +ULTRARISC DP1000 PINCTRL DRIVER +M: Jia Wang +L: linux-gpio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml +F: drivers/pinctrl/ultrarisc/* +F: include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h + ULTRATRONIK BOARD SUPPORT M: Goran Rađenović M: Börge Strümpfel diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index 69d8751fb17c80..70288297425182 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -12,3 +12,4 @@ subdir-y += spacemit subdir-y += starfive subdir-y += tenstorrent subdir-y += thead +subdir-y += ultrarisc diff --git a/arch/riscv/boot/dts/ultrarisc/Makefile b/arch/riscv/boot/dts/ultrarisc/Makefile new file mode 100644 index 00000000000000..9c27256a2f67f8 --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-milkv-titan.dtb +dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-rongda-m0.dtb diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan-pinctrl.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan-pinctrl.dtsi new file mode 100644 index 00000000000000..053206190ec75d --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan-pinctrl.dtsi @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +#include "dp1000.dtsi" + +&pmx0 { + i2c0_pins: i2c0-pins { + pins = "PA12", "PA13"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c1_pins: i2c1-pins { + pins = "PB6", "PB7"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c2_pins: i2c2-pins { + pins = "PC0", "PC1"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c3_pins: i2c3-pins { + pins = "PC2", "PC3"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + io_pins: io-pins { + pins = "PA10", "PA15", "PB0", "PB1", "PB2", "PD6", "PD7"; + function = "gpio"; + bias-pull-up; + drive-strength = <33>; + }; + + gpio_keys_pins: gpio-keys-pins { + pins = "PA4", "PA11", "PA14"; + function = "gpio"; + bias-pull-up; + drive-strength = <33>; + }; + + mux_dcdc_pins: mux-dcdc-pins { + pins = "PA5"; + function = "gpio"; + }; + + mux_i2c3_pins: mux-i2c3-pins { + pins = "PA6"; + function = "gpio"; + }; + + mux_uart0_pins: mux-uart0-pins { + pins = "PA7"; + function = "gpio"; + }; + + spi0_pins: spi0-pins { + pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5"; + function = "func1"; + bias-pull-up; + drive-strength = <33>; + }; + + spi1_pins: spi1-pins { + pins = "PA0", "PA1", "PA2", "PA3"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart0_pins: uart0-pins { + pins = "PA8", "PA9"; + function = "func1"; + bias-pull-up; + drive-strength = <33>; + }; + + uart1_pins: uart1-pins { + pins = "PB4", "PB5"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart2_pins: uart2-pins { + pins = "PC4", "PC5"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart3_pins: uart3-pins { + pins = "PC6", "PC7"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan.dts b/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan.dts new file mode 100644 index 00000000000000..21d85c03abe124 --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-milkv-titan.dts @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +#include "dp1000-milkv-titan-pinctrl.dtsi" +#include +#include +#include +#include + +/ { + model = "Milk-V Titan"; + compatible = "milkv,titan", "ultrarisc,dp1000"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio_b 0 GPIO_ACTIVE_LOW>; + active-delay-ms = <100>; + + status = "disabled"; + }; + + gpio-restart { + compatible = "gpio-restart"; + gpios = <&gpio_b 1 GPIO_ACTIVE_LOW>; + active-delay = <100>; + + status = "disabled"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_keys_pins>; + + key-wakeup-0 { + label = "Wake-Up"; + gpios = <&gpio_a 14 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <10>; + wakeup-source; + wakeup-event-action = ; + }; + + key-wakeup-1 { + label = "Power"; + gpios = <&gpio_a 11 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <10>; + wakeup-source; + wakeup-event-action = ; + }; + + key-wakeup-2 { + label = "Wake-Up-by-USB"; + gpios = <&gpio_a 4 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <10>; + wakeup-source; + wakeup-event-action = ; + }; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + + rtc@68 { + compatible = "st,m41t11"; + reg = <0x68>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; +}; + +&spi1 { + num-cs = <1>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + +&gpio { + pinctrl-names = "default"; + pinctrl-0 = <&io_pins &mux_dcdc_pins &mux_i2c3_pins &mux_uart0_pins>; +}; + +ðernet { + phy-handle = <&phy0>; + /* + * RTL8211F: board timing uses PHY strap delays; keep plain "rgmii". + * Enabling PHY internal delays via "rgmii-id" breaks Ethernet traffic. + */ + phy-mode = "rgmii"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: phy@0 { + reg = <0x00>; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + label = "eth-link"; + reg = <0x01>; + color = ; + function = LED_FUNCTION_INDICATOR; + default-state = "keep"; + linux,default-trigger = "netdev"; + }; + + led@2 { + label = "eth-activity"; + reg = <0x02>; + color = ; + function = LED_FUNCTION_ACTIVITY; + default-state = "keep"; + linux,default-trigger = "netdev"; + }; + }; + }; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0-pinctrl.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0-pinctrl.dtsi new file mode 100644 index 00000000000000..101b416b107923 --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0-pinctrl.dtsi @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +#include "dp1000.dtsi" + +&pmx0 { + i2c0_pins: i2c0-pins { + pins = "PA12", "PA13"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c1_pins: i2c1-pins { + pins = "PB6", "PB7"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c2_pins: i2c2-pins { + pins = "PC0", "PC1"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + i2c3_pins: i2c3-pins { + pins = "PC2", "PC3"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + pciex4a_link_pins: pciex4a-link-pins { + pins = "PC0"; + function = "func1"; + bias-pull-down; + drive-strength = <33>; + }; + + pciex4b_link_pins: pciex4b-link-pins { + pins = "PC1"; + function = "func1"; + bias-pull-down; + drive-strength = <33>; + }; + + spi0_pins: spi0-pins { + pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7"; + function = "func1"; + bias-pull-up; + drive-strength = <33>; + }; + + spi1_pins: spi1-pins { + pins = "PA0", "PA1", "PA2", "PA3"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart0_pins: uart0-pins { + pins = "PA8", "PA9"; + function = "func1"; + bias-pull-up; + drive-strength = <33>; + }; + + uart1_pins: uart1-pins { + pins = "PB4", "PB5"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; + + uart2_pins: uart2-pins { + pins = "PC4", "PC5"; + function = "func0"; + bias-pull-up; + drive-strength = <33>; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0.dts b/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0.dts new file mode 100644 index 00000000000000..6f72d60ad55e4d --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-rongda-m0.dts @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +#include "dp1000-rongda-m0-pinctrl.dtsi" +#include + +/ { + model = "Rongda M0 Board"; + compatible = "rongda,m0", "ultrarisc,dp1000"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio_b 0 GPIO_ACTIVE_HIGH>; + active-delay-ms = <100>; + + status = "disabled"; + }; + + gpio-restart { + compatible = "gpio-restart"; + gpios = <&gpio_b 1 GPIO_ACTIVE_HIGH>; + active-delay = <100>; + + status = "disabled"; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + + rtc@32 { + compatible = "whwave,sd3078"; + reg = <0x32>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; +}; + +&spi1 { + num-cs = <1>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + +ðernet { + phy-handle = <&phy0>; + /* + * YT8531 RGMII timing on this board requires no PHY internal delays. + * Using "rgmii-id" together with rx/tx-internal-delay-ps results in RX CRC + * errors and no usable traffic, so keep plain "rgmii" here. + */ + phy-mode = "rgmii"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: phy@0 { + reg = <0x00>; + }; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi new file mode 100644 index 00000000000000..1aae53fc1a2b1b --- /dev/null +++ b/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi @@ -0,0 +1,851 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +/dts-v1/; + +/ { + compatible = "ultrarisc,dp1000"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <10000000>; + + cpu0: cpu@0 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x0>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache0>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache0: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster0_l3>; + }; + }; + + cpu1: cpu@1 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x1>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache1>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu1_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache1: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster0_l3>; + }; + }; + + cpu2: cpu@2 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x2>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache2>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu2_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache2: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster0_l3>; + }; + }; + + cpu3: cpu@3 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x3>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache3>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu3_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache3: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster0_l3>; + }; + }; + + cpu4: cpu@4 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x10>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache4>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu4_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache4: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster1_l3>; + }; + }; + cpu5: cpu@5 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x11>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache5>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu5_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache5: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster1_l3>; + }; + }; + cpu6: cpu@6 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x12>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache6>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu6_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache6: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster1_l3>; + }; + }; + + cpu7: cpu@7 { + compatible = "ultrarisc,cp100", "riscv"; + reg = <0x13>; + device_type = "cpu"; + riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "h", + "zba", "zbb", "zbc", "zbs", "zicntr", + "zicsr", "zifencei", "zihpm", "ziccif", + "ziccrse", "ziccamoa", "za64rs", "zicbom", + "zicbop", "zicboz", "zkt", "svade", + "ssccptr", "sstvecd", "sscounterenw", + "shcounterenw", "shtvala", "shvstvecd", + "shvsatpa", "svvptc"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + /* L1 I-cache and D-cache: + * block-size 64B + * 4-way set associative, size 64KB + * per-core. + */ + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <0x10000>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <0x10000>; + next-level-cache = <&l2_cache7>; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + + cpu7_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <0x01>; + }; + + l2_cache7: l2-cache { + /* L2 cache: + * cache-unified, block-size 64B + * 8-way set associative, size 512KB + * per-core. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <0x80000>; + cache-sets = <1024>; + cache-unified; + next-level-cache = <&cluster1_l3>; + }; + }; + + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + + core2 { + cpu = <&cpu2>; + }; + + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1: cluster1 { + core0 { + cpu = <&cpu4>; + }; + + core1 { + cpu = <&cpu5>; + }; + + core2 { + cpu = <&cpu6>; + }; + + core3 { + cpu = <&cpu7>; + }; + }; + }; + + cluster0_l3: l3-cache0 { + /* L3 cache: + * cache-unified, block-size 64B + * 16-way set associative, size 4MB + * per-cluster. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <3>; + cache-size = <0x400000>; + cache-sets = <0x1000>; + cache-unified; + next-level-cache = <&l4_cache>; + }; + + cluster1_l3: l3-cache1 { + /* L3 cache: + * cache-unified, block-size 64B + * 16-way set associative, size 4MB + * per-cluster. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <3>; + cache-size = <0x400000>; + cache-sets = <0x1000>; + cache-unified; + next-level-cache = <&l4_cache>; + }; + }; + + clocks { + device_clk: device_clk { + compatible = "fixed-clock"; + clock-frequency = <62500000>; + #clock-cells = <0>; + }; + + timer_clk: timer_clk { + compatible = "fixed-clock"; + clock-frequency = <50000000>; + #clock-cells = <0>; + }; + + csr_clk: csr_clk { + compatible = "fixed-clock"; + clock-frequency = <250000000>; + #clock-cells = <0>; + }; + }; + + l4_cache: l4-cache { + /* L4 cache: + * cache-unified, block-size 64B + * 16-way set associative, size 16MB + * shared by the SoC. + */ + compatible = "cache"; + cache-block-size = <64>; + cache-level = <4>; + cache-size = <0x1000000>; + cache-sets = <0x4000>; + cache-unified; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00 0x80000000 0x4 0x00000000>; + }; + + soc { + compatible = "simple-bus"; + ranges; + #address-cells = <0x02>; + #size-cells = <0x02>; + + clint: clint@8000000 { + compatible = "sifive,clint0", "riscv,clint0"; + reg = <0x00 0x8000000 0x00 0x100000>; + interrupts-extended = <&cpu0_intc 0x03>, <&cpu0_intc 0x07>, + <&cpu1_intc 0x03>, <&cpu1_intc 0x07>, + <&cpu2_intc 0x03>, <&cpu2_intc 0x07>, + <&cpu3_intc 0x03>, <&cpu3_intc 0x07>, + <&cpu4_intc 0x03>, <&cpu4_intc 0x07>, + <&cpu5_intc 0x03>, <&cpu5_intc 0x07>, + <&cpu6_intc 0x03>, <&cpu6_intc 0x07>, + <&cpu7_intc 0x03>, <&cpu7_intc 0x07>; + }; + + plic: plic@9000000 { + compatible = "ultrarisc,dp1000-plic", "ultrarisc,cp100-plic"; + reg = <0x00 0x9000000 0x00 0x4000000>; + #interrupt-cells = <1>; + #address-cells = <0>; + interrupt-controller; + interrupts-extended = <&cpu0_intc 0xb>, <&cpu0_intc 0x9>, <&cpu0_intc 0xa>, + <&cpu1_intc 0xb>, <&cpu1_intc 0x9>, <&cpu1_intc 0xa>, + <&cpu2_intc 0xb>, <&cpu2_intc 0x9>, <&cpu2_intc 0xa>, + <&cpu3_intc 0xb>, <&cpu3_intc 0x9>, <&cpu3_intc 0xa>, + <&cpu4_intc 0xb>, <&cpu4_intc 0x9>, <&cpu4_intc 0xa>, + <&cpu5_intc 0xb>, <&cpu5_intc 0x9>, <&cpu5_intc 0xa>, + <&cpu6_intc 0xb>, <&cpu6_intc 0x9>, <&cpu6_intc 0xa>, + <&cpu7_intc 0xb>, <&cpu7_intc 0x9>, <&cpu7_intc 0xa>; + riscv,ndev = <160>; + }; + + pmx0: pinmux@11081000 { + compatible = "ultrarisc,dp1000-pinctrl"; + reg = <0x0 0x11081000 0x0 0x1000>; + #pinctrl-cells = <2>; + }; + + gpio: gpio@20200000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0x20200000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "bus", "db"; + clocks = <&csr_clk>, <&device_clk>; + + gpio_a: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <16>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&plic>; + interrupts = <34>; + gpio-ranges = <&pmx0 0 0 16>; + }; + + gpio_b: gpio-port@1 { + compatible = "snps,dw-apb-gpio-port"; + reg = <1>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + gpio-ranges = <&pmx0 16 0 8>; + }; + + gpio_c: gpio-port@2 { + compatible = "snps,dw-apb-gpio-port"; + reg = <2>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + gpio-ranges = <&pmx0 24 0 8>; + }; + + gpio_d: gpio-port@3 { + compatible = "snps,dw-apb-gpio-port"; + reg = <3>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + gpio-ranges = <&pmx0 32 0 8>; + }; + }; + + uart0: serial@20300000 { + compatible = "ultrarisc,dp1000-uart", "snps,dw-apb-uart"; + reg = <0x00 0x20300000 0x00 0x10000>; + interrupt-parent = <&plic>; + interrupts = <17>; + clock-frequency = <62500000>; + reg-io-width = <0x04>; + reg-shift = <0x02>; + }; + + uart1: serial@20310000 { + compatible = "ultrarisc,dp1000-uart", "snps,dw-apb-uart"; + reg = <0x00 0x20310000 0x00 0x10000>; + interrupt-parent = <&plic>; + interrupts = <18>; + clock-frequency = <62500000>; + reg-io-width = <0x04>; + reg-shift = <0x02>; + }; + + uart2: serial@20400000 { + compatible = "ultrarisc,dp1000-uart", "snps,dw-apb-uart"; + reg = <0x00 0x20400000 0x00 0x10000>; + interrupt-parent = <&plic>; + interrupts = <25>; + clock-frequency = <62500000>; + reg-io-width = <0x04>; + reg-shift = <0x02>; + }; + + uart3: serial@20410000 { + compatible = "ultrarisc,dp1000-uart", "snps,dw-apb-uart"; + reg = <0x00 0x20410000 0x00 0x10000>; + interrupt-parent = <&plic>; + interrupts = <26>; + clock-frequency = <62500000>; + reg-io-width = <0x04>; + reg-shift = <0x02>; + }; + + spi0: spi@20320000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x0 0x20320000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <19>; + num-cs = <3>; + }; + + spi1: spi@20420000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x0 0x20420000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <27>; + num-cs = <3>; + }; + + i2c0: i2c@20330000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20330000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <20>; + }; + + i2c1: i2c@20340000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20340000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <21>; + }; + + i2c2: i2c@20430000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20430000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <28>; + }; + + i2c3: i2c@20440000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20440000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <&plic>; + interrupts = <29>; + }; + + pcie_x16: pcie@21000000 { + compatible = "ultrarisc,dp1000-pcie"; + reg = <0x0 0x21000000 0x0 0x01000000>, + <0x0 0x4fff0000 0x0 0x00010000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, + <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <16>; + interrupt-parent = <&plic>; + interrupts = <43>, <44>, <45>, <46>, <47>; + interrupt-names = "msi", "inta", "intb", "intc", "intd"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 44>, + <0x0 0x0 0x0 0x2 &plic 45>, + <0x0 0x0 0x0 0x3 &plic 46>, + <0x0 0x0 0x0 0x4 &plic 47>; + }; + + pcie_x4a: pcie@23000000 { + compatible = "ultrarisc,dp1000-pcie"; + reg = <0x0 0x23000000 0x0 0x01000000>, + <0x0 0x6fff0000 0x0 0x00010000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, + <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + interrupt-parent = <&plic>; + interrupts = <63>, <64>, <65>, <66>, <67>; + interrupt-names = "msi", "inta", "intb", "intc", "intd"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 64>, + <0x0 0x0 0x0 0x2 &plic 65>, + <0x0 0x0 0x0 0x3 &plic 66>, + <0x0 0x0 0x0 0x4 &plic 67>; + }; + + pcie_x4b: pcie@24000000 { + compatible = "ultrarisc,dp1000-pcie"; + reg = <0x0 0x24000000 0x0 0x01000000>, + <0x0 0x7fff0000 0x0 0x00010000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, + <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + interrupt-parent = <&plic>; + interrupts = <73>, <74>, <75>, <76>, <77>; + interrupt-names = "msi", "inta", "intb", "intc", "intd"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 74>, + <0x0 0x0 0x0 0x2 &plic 75>, + <0x0 0x0 0x0 0x3 &plic 76>, + <0x0 0x0 0x0 0x4 &plic 77>; + }; + + ethernet: ethernet@38000000 { + compatible = "snps,dwmac", "snps,dwmac-5.10a"; + reg = <0x00 0x38000000 0x00 0x1000000>; + clocks = <&csr_clk>; + clock-names = "stmmaceth"; + interrupt-parent = <&plic>; + interrupts = <84>; + interrupt-names = "macirq"; + local-mac-address = [ff ff ff ff ff ff]; + max-speed = <1000>; + phy-mode = "rgmii-id"; + snps,txpbl = <8>; + snps,rxpbl = <8>; + }; + + dmac: dma-controller@39000000 { + compatible = "snps,axi-dma-1.01a"; + reg = <0x0 0x39000000 0x0 0x400>; + clocks = <&device_clk>, <&device_clk>; + clock-names = "core-clk", "cfgr-clk"; + #dma-cells = <1>; + dma-channels = <8>; + interrupt-parent = <&plic>; + interrupts = <152>; + snps,dma-masters = <1>; + snps,data-width = <4>; + snps,block-size = <512 512 512 512 512 512 512 512>; + snps,priority = <0 1 2 3 4 5 6 7>; + snps,axi-max-burst-len = <256>; + }; + }; +}; diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index c2c37327b9877f..9fdc4d1831ed93 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -32,6 +32,7 @@ CONFIG_SOC_STARFIVE=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_TENSTORRENT=y CONFIG_ARCH_THEAD=y +CONFIG_ARCH_ULTRARISC=y CONFIG_ARCH_VIRT=y CONFIG_ARCH_CANAAN=y CONFIG_SMP=y diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 03f2e3ee065f42..76105be8b3951b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -711,5 +711,6 @@ source "drivers/pinctrl/ti/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" source "drivers/pinctrl/visconti/Kconfig" source "drivers/pinctrl/vt8500/Kconfig" +source "drivers/pinctrl/ultrarisc/Kconfig" endif diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f7d5d5f76d0c8b..4df3e52518ea2e 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -98,3 +98,4 @@ obj-y += ti/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_VISCONTI) += visconti/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ +obj-$(CONFIG_ARCH_ULTRARISC) += ultrarisc/ diff --git a/drivers/pinctrl/ultrarisc/Kconfig b/drivers/pinctrl/ultrarisc/Kconfig new file mode 100644 index 00000000000000..ba8747b90127d6 --- /dev/null +++ b/drivers/pinctrl/ultrarisc/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PINCTRL_ULTRARISC + tristate + depends on OF + select PINMUX + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINCONF + select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select IRQ_DOMAIN_HIERARCHY + select MFD_SYSCON + +config PINCTRL_ULTRARISC_DP1000 + tristate "UltraRISC DP1000 SoC Pinctrl driver" + select PINCTRL_ULTRARISC + depends on OF && HAS_IOMEM + default ARCH_ULTRARISC + help + Say Y to select the pinctrl driver for UltraRISC DP1000 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-dp1000. diff --git a/drivers/pinctrl/ultrarisc/Makefile b/drivers/pinctrl/ultrarisc/Makefile new file mode 100644 index 00000000000000..5d49ce1c0af9e9 --- /dev/null +++ b/drivers/pinctrl/ultrarisc/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_PINCTRL_ULTRARISC) += pinctrl-ultrarisc.o +obj-$(CONFIG_PINCTRL_ULTRARISC_DP1000) += pinctrl-dp1000.o diff --git a/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c new file mode 100644 index 00000000000000..23b6cc51203180 --- /dev/null +++ b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + * + * Author: Jia Wang + */ + +#include +#include +#include + +#include "pinctrl-ultrarisc.h" + +static const struct pinctrl_pin_desc ur_dp1000_pins[] = { + PINCTRL_PIN(0, "PA0"), + PINCTRL_PIN(1, "PA1"), + PINCTRL_PIN(2, "PA2"), + PINCTRL_PIN(3, "PA3"), + PINCTRL_PIN(4, "PA4"), + PINCTRL_PIN(5, "PA5"), + PINCTRL_PIN(6, "PA6"), + PINCTRL_PIN(7, "PA7"), + PINCTRL_PIN(8, "PA8"), + PINCTRL_PIN(9, "PA9"), + PINCTRL_PIN(10, "PA10"), + PINCTRL_PIN(11, "PA11"), + PINCTRL_PIN(12, "PA12"), + PINCTRL_PIN(13, "PA13"), + PINCTRL_PIN(14, "PA14"), + PINCTRL_PIN(15, "PA15"), + PINCTRL_PIN(16, "PB0"), + PINCTRL_PIN(17, "PB1"), + PINCTRL_PIN(18, "PB2"), + PINCTRL_PIN(19, "PB3"), + PINCTRL_PIN(20, "PB4"), + PINCTRL_PIN(21, "PB5"), + PINCTRL_PIN(22, "PB6"), + PINCTRL_PIN(23, "PB7"), + PINCTRL_PIN(24, "PC0"), + PINCTRL_PIN(25, "PC1"), + PINCTRL_PIN(26, "PC2"), + PINCTRL_PIN(27, "PC3"), + PINCTRL_PIN(28, "PC4"), + PINCTRL_PIN(29, "PC5"), + PINCTRL_PIN(30, "PC6"), + PINCTRL_PIN(31, "PC7"), + PINCTRL_PIN(32, "PD0"), + PINCTRL_PIN(33, "PD1"), + PINCTRL_PIN(34, "PD2"), + PINCTRL_PIN(35, "PD3"), + PINCTRL_PIN(36, "PD4"), + PINCTRL_PIN(37, "PD5"), + PINCTRL_PIN(38, "PD6"), + PINCTRL_PIN(39, "PD7"), + PINCTRL_PIN(40, "LPC0"), + PINCTRL_PIN(41, "LPC1"), + PINCTRL_PIN(42, "LPC2"), + PINCTRL_PIN(43, "LPC3"), + PINCTRL_PIN(44, "LPC4"), + PINCTRL_PIN(45, "LPC5"), + PINCTRL_PIN(46, "LPC6"), + PINCTRL_PIN(47, "LPC7"), + PINCTRL_PIN(48, "LPC8"), + PINCTRL_PIN(49, "LPC9"), + PINCTRL_PIN(50, "LPC10"), + PINCTRL_PIN(51, "LPC11"), + PINCTRL_PIN(52, "LPC12"), +}; + +static const struct ur_function_desc ur_dp1000_functions[] = { + { "gpio", UR_FUNC_DEF, true }, + { "func0", UR_FUNC0, false }, + { "func1", UR_FUNC1, false }, +}; + +#define UR_DP1000_PORT(_name, _npins, _func, _conf, _modes) \ + { .name = (_name), .npins = (_npins), .func_offset = (_func), \ + .conf_offset = (_conf), .supported_modes = (_modes) } + +static const struct ur_pinctrl_match_data ur_dp1000_match_data = { + .pins = ur_dp1000_pins, + .npins = ARRAY_SIZE(ur_dp1000_pins), + .functions = ur_dp1000_functions, + .num_functions = ARRAY_SIZE(ur_dp1000_functions), + .num_ports = 5, + .ports = { + UR_DP1000_PORT("A", 16, 0x2c0, 0x310, UR_FUNC0 | UR_FUNC1), + UR_DP1000_PORT("B", 8, 0x2c4, 0x318, UR_FUNC0 | UR_FUNC1), + UR_DP1000_PORT("C", 8, 0x2c8, 0x31c, UR_FUNC0 | UR_FUNC1), + UR_DP1000_PORT("D", 8, 0x2cc, 0x320, UR_FUNC0 | UR_FUNC1), + UR_DP1000_PORT("LPC", 13, 0x2d0, 0x324, UR_FUNC0), + }, +}; + +static const struct of_device_id ur_pinctrl_of_match[] = { + { .compatible = "ultrarisc,dp1000-pinctrl", .data = &ur_dp1000_match_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, ur_pinctrl_of_match); + +static struct platform_driver ur_pinctrl_driver = { + .driver = { + .name = "ultrarisc-pinctrl-dp1000", + .of_match_table = ur_pinctrl_of_match, + }, + .probe = ur_pinctrl_probe, +}; + +module_platform_driver(ur_pinctrl_driver); + +MODULE_DESCRIPTION("UltraRISC DP1000 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c new file mode 100644 index 00000000000000..774746943e2831 --- /dev/null +++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c @@ -0,0 +1,746 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + * + * Author: Jia Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../devicetree.h" +#include "../pinconf.h" +#include "../pinctrl-utils.h" +#include "../pinmux.h" + +#include "pinctrl-ultrarisc.h" + +#define UR_CONF_BIT_PER_PIN 4 +#define UR_CONF_PIN_PER_REG (32 / UR_CONF_BIT_PER_PIN) +static const int ur_drive_strengths[] = { 20, 27, 33, 40 }; + +static int ur_pin_num_to_port_pin(const struct ur_pinctrl_match_data *match_data, + struct ur_pin_val *pin_val, u32 pin_num) +{ + for (u32 i = 0; i < match_data->num_ports; i++) { + if (pin_num < match_data->ports[i].npins) { + pin_val->port = i; + pin_val->pin = pin_num; + return 0; + } + pin_num -= match_data->ports[i].npins; + } + + return -EINVAL; +} + +static int ur_pin_to_desc(struct pinctrl_dev *pctldev, struct ur_pin_val *pin_val) +{ + struct ur_pinctrl *ur_pinctrl = pinctrl_dev_get_drvdata(pctldev); + int index = 0; + + for (u32 i = 0; i < pin_val->port; i++) + index += ur_pinctrl->match_data->ports[i].npins; + + return index + pin_val->pin; +} + +static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin) +{ + return port_desc->conf_offset + + (pin / UR_CONF_PIN_PER_REG) * sizeof(u32); +} + +static u32 ur_read_pin_conf(struct ur_pinctrl *pctldata, unsigned int pin) +{ + const struct ur_port_desc *port_desc; + struct ur_pin_val pin_val; + u32 reg_offset; + u32 shift; + u32 conf; + u32 mask; + + if (ur_pin_num_to_port_pin(pctldata->match_data, &pin_val, pin)) + return 0; + + port_desc = &pctldata->match_data->ports[pin_val.port]; + reg_offset = ur_get_pin_conf_offset(port_desc, pin_val.pin); + shift = (pin_val.pin % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN; + mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift; + conf = field_get(mask, readl_relaxed(pctldata->base + reg_offset)); + + return conf; +} + +static int ur_write_pin_conf(struct ur_pinctrl *pctldata, unsigned int pin, u32 conf) +{ + const struct ur_port_desc *port_desc; + struct ur_pin_val pin_val; + unsigned long flags; + void __iomem *reg; + u32 reg_offset; + u32 val; + u32 shift; + u32 mask; + + if (ur_pin_num_to_port_pin(pctldata->match_data, &pin_val, pin)) + return -EINVAL; + + port_desc = &pctldata->match_data->ports[pin_val.port]; + reg_offset = ur_get_pin_conf_offset(port_desc, pin_val.pin); + reg = pctldata->base + reg_offset; + shift = (pin_val.pin % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN; + mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift; + + raw_spin_lock_irqsave(&pctldata->lock, flags); + val = readl_relaxed(reg); + val = (val & ~mask) | field_prep(mask, conf); + writel_relaxed(val, reg); + raw_spin_unlock_irqrestore(&pctldata->lock, flags); + + return 0; +} + +static int ur_set_pin_mux(struct ur_pinctrl *pctldata, struct ur_pin_val *pin_val) +{ + const struct ur_port_desc *port_desc = &pctldata->match_data->ports[pin_val->port]; + void __iomem *reg = pctldata->base + port_desc->func_offset; + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&pctldata->lock, flags); + val = readl_relaxed(reg); + val &= ~((UR_FUNC0 | UR_FUNC1) << pin_val->pin); + val |= pin_val->mode << pin_val->pin; + writel_relaxed(val, reg); + raw_spin_unlock_irqrestore(&pctldata->lock, flags); + + return 0; +} + +static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctldata, unsigned int pin, u32 mode) +{ + struct ur_pin_val pin_val = { .mode = mode }; + const struct ur_port_desc *port_desc; + int ret; + + ret = ur_pin_num_to_port_pin(pctldata->match_data, &pin_val, pin); + if (ret) + return ret; + + port_desc = &pctldata->match_data->ports[pin_val.port]; + if (mode != UR_FUNC_DEF && !(port_desc->supported_modes & mode)) + return -EINVAL; + + return ur_set_pin_mux(pctldata, &pin_val); +} + +static int ur_hw_to_config(unsigned long *config, u32 conf) +{ + enum pin_config_param param = pinconf_to_config_param(*config); + u32 drive = FIELD_GET(UR_DRIVE_MASK, conf); + u32 pull = FIELD_GET(UR_PULL_MASK, conf); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + if (pull != UR_PULL_DIS) + return -EINVAL; + *config = pinconf_to_config_packed(param, 1); + return 0; + case PIN_CONFIG_BIAS_PULL_UP: + if (pull != UR_PULL_UP) + return -EINVAL; + *config = pinconf_to_config_packed(param, 1); + return 0; + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (pull != UR_PULL_DOWN) + return -EINVAL; + *config = pinconf_to_config_packed(param, 1); + return 0; + case PIN_CONFIG_DRIVE_STRENGTH: + if (drive >= ARRAY_SIZE(ur_drive_strengths)) + return -EINVAL; + *config = pinconf_to_config_packed(param, ur_drive_strengths[drive]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ur_config_to_hw(unsigned long config, u32 *conf) +{ + enum pin_config_param param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS); + return 0; + case PIN_CONFIG_BIAS_PULL_UP: + FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP); + return 0; + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN); + return 0; + case PIN_CONFIG_DRIVE_STRENGTH: + for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) { + if (ur_drive_strengths[i] != arg) + continue; + FIELD_MODIFY(UR_DRIVE_MASK, conf, i); + return 0; + } + return -EINVAL; + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_PERSIST_STATE: + return 0; + default: + return -EOPNOTSUPP; + } +} + +struct ur_legacy_prop_data { + struct ur_pin_val *pin_vals; + unsigned int *group_pins; + unsigned int num_pins; +}; + +static int ur_legacy_parse_prop(struct pinctrl_dev *pctldev, + struct device_node *np, + const char *propname, + struct ur_legacy_prop_data *prop) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + int rows; + + rows = pinctrl_count_index_with_args(np, propname); + if (rows < 0) + return dev_err_probe(pctldev->dev, rows, "%pOF: invalid %s count\n", + np, propname); + + prop->pin_vals = devm_kcalloc(pctldev->dev, rows, sizeof(*prop->pin_vals), + GFP_KERNEL); + if (!prop->pin_vals) + return -ENOMEM; + + prop->group_pins = devm_kcalloc(pctldev->dev, rows, sizeof(*prop->group_pins), + GFP_KERNEL); + if (!prop->group_pins) + return -ENOMEM; + + prop->num_pins = rows; + + for (int i = 0; i < rows; i++) { + struct of_phandle_args pin_args; + int ret; + + ret = pinctrl_parse_index_with_args(np, propname, i, &pin_args); + if (ret) + return dev_err_probe(pctldev->dev, ret, + "%pOF: failed to parse %s[%d]\n", + np, propname, i); + + if (pin_args.args_count != 3) + return dev_err_probe(pctldev->dev, -EINVAL, + "%pOF: invalid %s[%d] args_count=%d\n", + np, propname, i, pin_args.args_count); + + prop->pin_vals[i].port = pin_args.args[0]; + prop->pin_vals[i].pin = pin_args.args[1]; + prop->pin_vals[i].mode = pin_args.args[2]; + + if (prop->pin_vals[i].port >= pctldata->match_data->num_ports) + return dev_err_probe(pctldev->dev, -EINVAL, + "%pOF: invalid %s[%d] port=%u\n", + np, propname, i, prop->pin_vals[i].port); + + if (prop->pin_vals[i].pin >= + pctldata->match_data->ports[prop->pin_vals[i].port].npins) + return dev_err_probe(pctldev->dev, -EINVAL, + "%pOF: invalid %s[%d] pin=%u\n", + np, propname, i, prop->pin_vals[i].pin); + + prop->group_pins[i] = ur_pin_to_desc(pctldev, &prop->pin_vals[i]); + } + + return 0; +} + +static const char *ur_legacy_get_function_name(const struct ur_pinctrl_match_data *match_data, + u32 mode) +{ + for (u32 i = 0; i < match_data->num_functions; i++) { + if (match_data->functions[i].mode == mode) + return match_data->functions[i].name; + } + + return NULL; +} + +static int ur_legacy_conf_to_configs(struct pinctrl_dev *pctldev, u32 conf, + unsigned long **configs, + unsigned int *num_configs) +{ + u32 drive = FIELD_GET(UR_DRIVE_MASK, conf); + u32 pull = FIELD_GET(UR_PULL_MASK, conf); + unsigned long config; + int ret; + + switch (pull) { + case UR_PULL_DIS: + config = pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE, 1); + break; + case UR_PULL_UP: + config = pinconf_to_config_packed(PIN_CONFIG_BIAS_PULL_UP, 1); + break; + case UR_PULL_DOWN: + config = pinconf_to_config_packed(PIN_CONFIG_BIAS_PULL_DOWN, 1); + break; + default: + return -EINVAL; + } + + ret = pinctrl_utils_add_config(pctldev, configs, num_configs, config); + if (ret) + return ret; + + if (drive >= ARRAY_SIZE(ur_drive_strengths)) + return -EINVAL; + + config = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, + ur_drive_strengths[drive]); + + return pinctrl_utils_add_config(pctldev, configs, num_configs, config); +} + +static int ur_legacy_add_mux_maps(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps, + const struct ur_legacy_prop_data *prop) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + + for (u32 i = 0; i < prop->num_pins; i++) { + const char *function; + const char *group; + int ret; + + function = ur_legacy_get_function_name(pctldata->match_data, + prop->pin_vals[i].mode); + if (!function) + return -EINVAL; + + group = pctldata->match_data->pins[prop->group_pins[i]].name; + if (!group) + return -EINVAL; + + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, + num_maps, group, function); + if (ret) + return ret; + } + + return 0; +} + +static int ur_legacy_add_pinconf_maps(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps, + const struct ur_legacy_prop_data *prop) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + + for (u32 i = 0; i < prop->num_pins; i++) { + unsigned long *configs = NULL; + unsigned int num_configs = 0; + const char *group; + int ret; + + ret = ur_legacy_conf_to_configs(pctldev, prop->pin_vals[i].conf, + &configs, &num_configs); + if (ret) + goto err; + + group = pctldata->match_data->pins[prop->group_pins[i]].name; + if (!group) { + ret = -EINVAL; + goto err; + } + + ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, + num_maps, group, configs, + num_configs, + PIN_MAP_TYPE_CONFIGS_PIN); +err: + kfree(configs); + if (ret) + return ret; + } + + return 0; +} + +static int ur_legacy_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct ur_legacy_prop_data conf_prop = {}; + struct ur_legacy_prop_data mux_prop = {}; + struct pinctrl_map *new_map = NULL; + unsigned int reserved_maps = 0; + unsigned int total_maps = 0; + bool conf_present = false; + bool mux_present = false; + unsigned int map_num = 0; + int ret; + + if (of_property_present(np, "pinctrl-pins")) + mux_present = true; + if (of_property_present(np, "pinconf-pins")) + conf_present = true; + if (!mux_present && !conf_present) + return -EINVAL; + + if (mux_present) { + ret = ur_legacy_parse_prop(pctldev, np, "pinctrl-pins", &mux_prop); + if (ret) + goto err; + total_maps += mux_prop.num_pins; + } + + if (conf_present) { + ret = ur_legacy_parse_prop(pctldev, np, "pinconf-pins", &conf_prop); + if (ret) + goto err; + total_maps += conf_prop.num_pins; + } + + ret = pinctrl_utils_reserve_map(pctldev, &new_map, &reserved_maps, + &map_num, total_maps); + if (ret) + goto err; + + if (mux_present) { + ret = ur_legacy_add_mux_maps(pctldev, &new_map, &reserved_maps, + &map_num, &mux_prop); + if (ret) + goto err; + } + + if (conf_present) { + ret = ur_legacy_add_pinconf_maps(pctldev, &new_map, &reserved_maps, + &map_num, &conf_prop); + if (ret) + goto err; + } + + *map = new_map; + *num_maps = map_num; + + return 0; + +err: + pinctrl_utils_free_map(pctldev, new_map, map_num); + return ret; +} + +static int ur_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, + PIN_MAP_TYPE_INVALID); +} + +static int ur_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + bool legacy = of_property_present(np, "pinctrl-pins") || + of_property_present(np, "pinconf-pins"); + bool generic = of_property_present(np, "pins"); + + if (legacy && generic) { + dev_err(pctldev->dev, + "%pOF: mixed legacy and generic pinctrl properties are not supported\n", + np); + return -EINVAL; + } + + if (generic) + return ur_generic_dt_node_to_map(pctldev, np, map, num_maps); + + if (legacy) + return ur_legacy_dt_node_to_map(pctldev, np, map, num_maps); + + return -EINVAL; +} + +static void ur_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned int num_maps) +{ + pinctrl_utils_free_map(pctldev, map, num_maps); +} + +static void ur_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static const struct pinctrl_ops ur_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = ur_dt_node_to_map, + .dt_free_map = ur_dt_free_map, + .pin_dbg_show = ur_pin_dbg_show, +}; + +static int ur_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + + (void)range; + + return ur_set_pin_mux_by_num(pctldata, offset, UR_FUNC_DEF); +} + +static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, + unsigned int group_selector) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + const struct ur_function_desc *desc; + const struct function_desc *func; + const unsigned int *pins; + unsigned int npins; + int ret; + + func = pinmux_generic_get_function(pctldev, func_selector); + if (!func || !func->data) + return -EINVAL; + + desc = func->data; + ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins); + if (ret) + return ret; + + for (u32 i = 0; i < npins; i++) { + ret = ur_set_pin_mux_by_num(pctldata, pins[i], desc->mode); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinmux_ops ur_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .function_is_gpio = pinmux_generic_function_is_gpio, + .set_mux = ur_set_mux, + .gpio_request_enable = ur_gpio_request_enable, + .strict = true, +}; + +static int ur_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *config) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + + return ur_hw_to_config(config, ur_read_pin_conf(pctldata, pin)); +} + +static int ur_pin_config_set(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs) +{ + struct ur_pinctrl *pctldata = pinctrl_dev_get_drvdata(pctldev); + u32 conf = ur_read_pin_conf(pctldata, pin); + int ret; + + for (u32 i = 0; i < num_configs; i++) { + ret = ur_config_to_hw(configs[i], &conf); + if (ret) + return ret; + } + + return ur_write_pin_conf(pctldata, pin, conf); +} + +static int ur_pin_config_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *config) +{ + const unsigned int *pins; + unsigned int npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins); + if (ret || !npins) + return ret ?: -EINVAL; + + return ur_pin_config_get(pctldev, pins[0], config); +} + +static int ur_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + const unsigned int *pins; + unsigned int npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins); + if (ret) + return ret; + + for (u32 i = 0; i < npins; i++) { + ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops ur_pinconf_ops = { + .pin_config_get = ur_pin_config_get, + .pin_config_set = ur_pin_config_set, + .pin_config_group_get = ur_pin_config_group_get, + .pin_config_group_set = ur_pin_config_group_set, +#ifdef CONFIG_GENERIC_PINCONF + .is_generic = true, +#endif +}; + +static int ur_add_pin_groups(struct ur_pinctrl *pctldata) +{ + for (u32 i = 0; i < pctldata->match_data->npins; i++) { + int ret; + + pctldata->group_names[i] = pctldata->match_data->pins[i].name; + pctldata->group_pins[i] = pctldata->match_data->pins[i].number; + + ret = pinctrl_generic_add_group(pctldata->pctl_dev, pctldata->group_names[i], + &pctldata->group_pins[i], 1, NULL); + if (ret < 0) + return dev_err_probe(pctldata->dev, ret, + "failed to add pin group %s\n", + pctldata->group_names[i]); + } + + return 0; +} + +static int ur_add_functions(struct ur_pinctrl *pctldata) +{ + for (u32 i = 0; i < pctldata->match_data->num_functions; i++) { + const struct ur_function_desc *desc = &pctldata->match_data->functions[i]; + struct pinfunction func = desc->gpio ? + PINCTRL_GPIO_PINFUNCTION(desc->name, pctldata->group_names, + pctldata->match_data->npins) : + PINCTRL_PINFUNCTION(desc->name, pctldata->group_names, + pctldata->match_data->npins); + int ret; + + ret = pinmux_generic_add_pinfunction(pctldata->pctl_dev, &func, (void *)desc); + if (ret < 0) + return dev_err_probe(pctldata->dev, ret, + "failed to add function %s\n", + desc->name); + } + + return 0; +} + +int ur_pinctrl_probe(struct platform_device *pdev) +{ + const struct ur_pinctrl_match_data *match_data; + struct ur_pinctrl *pctldata; + struct pinctrl_desc *desc; + int ret; + + match_data = of_device_get_match_data(&pdev->dev); + if (!match_data) + return -ENODEV; + + desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + pctldata = devm_kzalloc(&pdev->dev, sizeof(*pctldata), GFP_KERNEL); + if (!pctldata) + return -ENOMEM; + + pctldata->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pctldata->base)) + return PTR_ERR(pctldata->base); + pctldata->dev = &pdev->dev; + pctldata->match_data = match_data; + pctldata->group_names = devm_kcalloc(&pdev->dev, match_data->npins, + sizeof(*pctldata->group_names), GFP_KERNEL); + if (!pctldata->group_names) + return -ENOMEM; + + pctldata->group_pins = devm_kcalloc(&pdev->dev, match_data->npins, + sizeof(*pctldata->group_pins), GFP_KERNEL); + if (!pctldata->group_pins) + return -ENOMEM; + + raw_spin_lock_init(&pctldata->lock); + + desc->name = dev_name(&pdev->dev); + desc->owner = THIS_MODULE; + desc->pins = match_data->pins; + desc->npins = match_data->npins; + desc->pctlops = &ur_pinctrl_ops; + desc->pmxops = &ur_pinmux_ops; + desc->confops = &ur_pinconf_ops; + + ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctldata, &pctldata->pctl_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n"); + + ret = ur_add_pin_groups(pctldata); + if (ret) + return ret; + + ret = ur_add_functions(pctldata); + if (ret) + return ret; + + platform_set_drvdata(pdev, pctldata); + + return pinctrl_enable(pctldata->pctl_dev); +} +EXPORT_SYMBOL_GPL(ur_pinctrl_probe); + +MODULE_DESCRIPTION("UltraRISC pinctrl core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h new file mode 100644 index 00000000000000..25291f18c95066 --- /dev/null +++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + * + * Author: Jia Wang + */ + +#ifndef __PINCTRL_ULTRARISC_H__ +#define __PINCTRL_ULTRARISC_H__ + +#include +#include +#include + +struct platform_device; + +struct ur_pin_val { + u32 port; + u32 pin; + union { + u32 mode; + u32 conf; + }; +#define UR_FUNC_DEF 0 +#define UR_FUNC0 1 +#define UR_FUNC1 0x10000 + +#define UR_BIAS_MASK 0x0000000F +#define UR_PULL_MASK 0x0C +#define UR_PULL_DIS 0 +#define UR_PULL_UP 1 +#define UR_PULL_DOWN 2 +#define UR_DRIVE_MASK 0x03 +}; + +struct ur_port_desc { + const char *name; + u32 npins; + u32 func_offset; + u32 conf_offset; + u32 supported_modes; +}; + +struct ur_function_desc { + const char *name; + u32 mode; + bool gpio; +}; + +struct ur_pinctrl_match_data { + const struct pinctrl_pin_desc *pins; + u32 npins; + const struct ur_function_desc *functions; + u32 num_functions; + u32 num_ports; + struct ur_port_desc ports[]; +}; + +struct ur_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl_dev; + void __iomem *base; + const struct ur_pinctrl_match_data *match_data; + raw_spinlock_t lock; + const char **group_names; + unsigned int *group_pins; +}; + +int ur_pinctrl_probe(struct platform_device *pdev); + +#endif diff --git a/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h new file mode 100644 index 00000000000000..bef28115898d46 --- /dev/null +++ b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * UltraRISC DP1000 pinctrl header. + * + * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. + */ + +#ifndef _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_PINCTRL_H +#define _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_PINCTRL_H + +/** + * UltraRISC DP1000 IO pad configuration + * port: A, B, C, D, LPC + * Pin in the port + * pin: + * PA: 0 - 15 + * PB-PD: 0 - 7 + * LPC: 0 - 12 + * func: + * UR_DP1000_FUNC_DEF: default + * UR_DP1000_FUNC0: func0 + * UR_DP1000_FUNC1: func1 + */ +#define UR_DP1000_IOMUX_A 0x0 +#define UR_DP1000_IOMUX_B 0x1 +#define UR_DP1000_IOMUX_C 0x2 +#define UR_DP1000_IOMUX_D 0x3 +#define UR_DP1000_IOMUX_LPC 0x4 + +#define UR_DP1000_FUNC_DEF 0 +#define UR_DP1000_FUNC0 1 +#define UR_DP1000_FUNC1 0x10000 + +/** + * Configure pull up/down resistor of the IO pin + * UR_DP1000_PULL_DIS: disable pull-up and pull-down + * UR_DP1000_PULL_UP: enable pull-up + * UR_DP1000_PULL_DOWN: enable pull-down + */ +#define UR_DP1000_PULL_DIS 0 +#define UR_DP1000_PULL_UP 1 +#define UR_DP1000_PULL_DOWN 2 +/** + * Configure drive strength of the IO pin + * UR_DP1000_DRIVE_DEF: default value, reset value is 2 + * UR_DP1000_DRIVE_0: 20mA + * UR_DP1000_DRIVE_1: 27mA + * UR_DP1000_DRIVE_2: 33mA + * UR_DP1000_DRIVE_3: 40mA + */ +#define UR_DP1000_DRIVE_DEF 2 +#define UR_DP1000_DRIVE_0 0 +#define UR_DP1000_DRIVE_1 1 +#define UR_DP1000_DRIVE_2 2 +#define UR_DP1000_DRIVE_3 3 + +/** + * Combine the pull-up/down resistor and drive strength + * pull: UR_DP1000_PULL_DIS, UR_DP1000_PULL_UP, UR_DP1000_PULL_DOWN + * drive: UR_DP1000_DRIVE_DEF, UR_DP1000_DRIVE_0, UR_DP1000_DRIVE_1, + * UR_DP1000_DRIVE_2, UR_DP1000_DRIVE_3 + */ +#define UR_DP1000_BIAS(pull, drive) (((pull) << 2) | (drive)) + +#endif /* _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_PINCTRL_H */