diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led index 2e24ac3bd7efa..0313b82644f24 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -72,6 +72,12 @@ Description: /sys/class/leds/ once a given trigger is selected. For their documentation see `sysfs-class-led-trigger-*`. + Writing "none" removes the trigger for this LED. + + Writing "default" sets the trigger to the LED's default trigger + (which would often be configured in the device tree for the + hardware). + What: /sys/class/leds//inverted Date: January 2011 KernelVersion: 2.6.38 diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev index f6d9d72ce77b7..ed46b37ab8a28 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -88,6 +88,8 @@ Description: speed of 10MBps of the named network device. Setting this value also immediately changes the LED state. + Present only if the named network device supports 10Mbps link speed. + What: /sys/class/leds//link_100 Date: Jun 2023 KernelVersion: 6.5 @@ -101,6 +103,8 @@ Description: speed of 100Mbps of the named network device. Setting this value also immediately changes the LED state. + Present only if the named network device supports 100Mbps link speed. + What: /sys/class/leds//link_1000 Date: Jun 2023 KernelVersion: 6.5 @@ -114,6 +118,53 @@ Description: speed of 1000Mbps of the named network device. Setting this value also immediately changes the LED state. + Present only if the named network device supports 1000Mbps link speed. + +What: /sys/class/leds//link_2500 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 2500Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 2500Mbps of the named network device. + Setting this value also immediately changes the LED state. + + Present only if the named network device supports 2500Mbps link speed. + +What: /sys/class/leds//link_5000 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 5000Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 5000Mbps of the named network device. + Setting this value also immediately changes the LED state. + + Present only if the named network device supports 5000Mbps link speed. + +What: /sys/class/leds//link_10000 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 10000Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 10000Mbps of the named network device. + Setting this value also immediately changes the LED state. + + Present only if the named network device supports 10000Mbps link speed. + What: /sys/class/leds//half_duplex Date: Jun 2023 KernelVersion: 6.5 diff --git a/Documentation/devicetree/bindings/hwmon/ultrarisc,dp1000-pvt.yaml b/Documentation/devicetree/bindings/hwmon/ultrarisc,dp1000-pvt.yaml new file mode 100644 index 0000000000000..41256a3e7cb3d --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ultrarisc,dp1000-pvt.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/ultrarisc,dp1000-pvt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: UltraRISC DP1000 Core PVT Sensor + +maintainers: + - Jia Wang + +description: | + UltraRISC DP1000 SoC provides a voltage and temperature (PVT) sensor to + monitor the internal SoC environment including chip temperature and supply voltage. + +properties: + compatible: + const: ultrarisc,dp1000-pvt + + reg: + maxItems: 1 + description: Register space of the PVT controller + + interrupts: + maxItems: 1 + description: Optional interrupt number for the PVT controller. This property is optional and can be omitted if not used. + + clock-frequency: + description: Clock frequency of the PVT controller in Hz + + channels: + description: Total number of PVT channels supported + +patternProperties: + "^channel@[0-9a-f]+$": + type: object + description: Child node describing a PVT channel + properties: + reg: + description: Channel index + minimum: 0 + maximum: 63 + + label: + description: Name for this channel, typically indicating its purpose + + trim: + description: Trim value for calibration + default: 7 + minimum: 0 + maximum: 15 + + required: + - reg + - label + +required: + - compatible + - reg + - clock-frequency + - channels + +additionalProperties: false + +examples: + - | + core_pvt: pvt@20008000 { + compatible = "ultrarisc,dp1000-pvt"; + reg = <0x20008000 0x1000>; + clock-frequency = <4000000>; + channels = <13>; + + channel@0 { + reg = <0>; + label = "Core temp0"; + trim = <7>; + }; + + channel@1 { + reg = <1>; + label = "Core temp1"; + trim = <7>; + }; + + channel@2 { + reg = <2>; + label = "Core temp2"; + trim = <7>; + }; + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index dc1f28e552660..0e97f0c3e4888 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -67,6 +67,9 @@ properties: - allwinner,sun20i-d1-plic - thead,th1520-plic - const: thead,c900-plic + - items: + - const: ultrarisc,dp1000-plic + - const: ultrarisc,cp100-plic - items: - const: sifive,plic-1.0.0 - const: riscv,plic0 diff --git a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml index 3b51686d0d1d9..1ad5239cd108d 100644 --- a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml @@ -10,7 +10,7 @@ maintainers: description: | UltraRISC RISC-V SoC DP1000 pin controller. - contains the pinmux definitions. + contains the pinmux definitions. properties: compatible: diff --git a/arch/riscv/boot/dts/ultrarisc/Makefile b/arch/riscv/boot/dts/ultrarisc/Makefile index df8efe1a3ed72..1fb9be766c97f 100644 --- a/arch/riscv/boot/dts/ultrarisc/Makefile +++ b/arch/riscv/boot/dts/ultrarisc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-evb-v1.dtb -dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-mo-v1.dtb +dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-m0-v1.dtb dtb-$(CONFIG_ARCH_ULTRARISC) += dp1000-titan-v1.dtb diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-evb-pinctrl.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000-evb-pinctrl.dtsi index 85b013f66bbdb..ae78ae395314d 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-evb-pinctrl.dtsi +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-evb-pinctrl.dtsi @@ -3,7 +3,7 @@ * Copyright(C) 2025 UltraRISC Technology (Shanghai) Co., Ltd. */ -#include +#include #include "dp1000.dtsi" &pmx0 { diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-evb-v1.dts b/arch/riscv/boot/dts/ultrarisc/dp1000-evb-v1.dts index 46fe457b5f523..f6e17183cc148 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-evb-v1.dts +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-evb-v1.dts @@ -5,11 +5,14 @@ #include "dp1000-evb-pinctrl.dtsi" #include +#include / { + model = "UltraRISC EVB v1"; + compatible = "ultrarisc,evb-v1", "ultrarisc,dp1000"; + chosen { - bootargs = "earlycon=sbi console=ttyS1,115200"; - stdout-path = &uart1; + stdout-path = "serial1:115200n8"; }; }; @@ -21,6 +24,16 @@ &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins>; + + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; }; &i2c3 { @@ -31,14 +44,6 @@ &spi0 { pinctrl-names = "default"; pinctrl-0 = <&spi0_pins>; - - mmc0: mmc@0 { - compatible = "mmc-spi-slot"; - spi-max-frequency = <15625000>; - reg = <0x00>; - voltage-ranges = <3300 3300>; - disable-wp; - }; }; &spi1 { @@ -62,3 +67,17 @@ pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; }; + +ðernet { + phy-handle = <&phy0>; + mdio { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "snps,dwmac-mdio"; + phy0: phy@0{ + phandle = <0x04>; + reg = <0x00>; + status = "okay"; + }; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-mo-pinctrl.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000-m0-pinctrl.dtsi similarity index 98% rename from arch/riscv/boot/dts/ultrarisc/dp1000-mo-pinctrl.dtsi rename to arch/riscv/boot/dts/ultrarisc/dp1000-m0-pinctrl.dtsi index 85b013f66bbdb..ae78ae395314d 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-mo-pinctrl.dtsi +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-m0-pinctrl.dtsi @@ -3,7 +3,7 @@ * Copyright(C) 2025 UltraRISC Technology (Shanghai) Co., Ltd. */ -#include +#include #include "dp1000.dtsi" &pmx0 { diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-mo-v1.dts b/arch/riscv/boot/dts/ultrarisc/dp1000-m0-v1.dts similarity index 54% rename from arch/riscv/boot/dts/ultrarisc/dp1000-mo-v1.dts rename to arch/riscv/boot/dts/ultrarisc/dp1000-m0-v1.dts index dc057cbaf59be..c17d848776798 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-mo-v1.dts +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-m0-v1.dts @@ -3,13 +3,32 @@ * Copyright(C) 2025 UltraRISC Technology (Shanghai) Co., Ltd. */ -#include "dp1000-mo-pinctrl.dtsi" +#include "dp1000-m0-pinctrl.dtsi" #include +#include / { + model = "Rongda M0 Board v1"; + compatible = "rongda,m0-v1", "ultrarisc,dp1000"; + chosen { - bootargs = "earlycon=sbi console=ttyS0,115200"; - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; + }; + + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&portb 0 GPIO_ACTIVE_HIGH>; + active-delay-ms = <100>; + line-name = "power-off"; + status = "okay"; + }; + + gpio-restart { + compatible = "gpio-restart"; + gpios = <&portb 1 GPIO_ACTIVE_HIGH>; + active-delay-ms = <100>; + line-name = "reset-system"; + status = "okay"; }; }; @@ -64,3 +83,17 @@ pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; }; + +ðernet { + phy-handle = <&phy0>; + mdio { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "snps,dwmac-mdio"; + phy0: phy@0{ + phandle = <0x04>; + reg = <0x00>; + status = "okay"; + }; + }; +}; diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-titan-pinctrl.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000-titan-pinctrl.dtsi index 35429e5398325..7ea782f459ab5 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-titan-pinctrl.dtsi +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-titan-pinctrl.dtsi @@ -3,7 +3,7 @@ * Copyright(C) 2025 UltraRISC Technology (Shanghai) Co., Ltd. */ -#include +#include #include "dp1000.dtsi" &pmx0 { @@ -129,7 +129,6 @@ UR_DP1000_IOMUX_A 1 UR_FUNC0 UR_DP1000_IOMUX_A 2 UR_FUNC0 UR_DP1000_IOMUX_A 3 UR_FUNC0 - UR_DP1000_IOMUX_A 4 UR_FUNC0 >; pinconf-pins = < @@ -137,15 +136,12 @@ UR_DP1000_IOMUX_A 1 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) UR_DP1000_IOMUX_A 2 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) UR_DP1000_IOMUX_A 3 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) - UR_DP1000_IOMUX_A 4 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) >; }; gpios_pin: gpios_pin { pinctrl-pins = < UR_DP1000_IOMUX_A 10 UR_FUNC_DEF - UR_DP1000_IOMUX_A 11 UR_FUNC_DEF - UR_DP1000_IOMUX_A 14 UR_FUNC_DEF UR_DP1000_IOMUX_A 15 UR_FUNC_DEF UR_DP1000_IOMUX_B 0 UR_FUNC_DEF @@ -158,8 +154,6 @@ pinconf-pins = < UR_DP1000_IOMUX_A 10 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) - UR_DP1000_IOMUX_A 11 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) - UR_DP1000_IOMUX_A 14 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) UR_DP1000_IOMUX_A 15 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) UR_DP1000_IOMUX_B 0 UR_DP1000_BIAS(UR_PULL_UP, UR_DRIVE_DEF) diff --git a/arch/riscv/boot/dts/ultrarisc/dp1000-titan-v1.dts b/arch/riscv/boot/dts/ultrarisc/dp1000-titan-v1.dts index 2cbdfa2ad813d..3b2d04cfb4475 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000-titan-v1.dts +++ b/arch/riscv/boot/dts/ultrarisc/dp1000-titan-v1.dts @@ -8,11 +8,14 @@ #include #include #include +#include / { + model = "MilkV Titan V1.2"; + compatible = "milkv,titan-v1.2", "ultrarisc,dp1000"; + chosen { - bootargs = "earlycon=sbi console=ttyS0,115200"; - stdout-path = &uart0; + stdout-path = "serial0:115200n8"; }; gpio-poweroff { @@ -34,7 +37,7 @@ gpio-keys { compatible = "gpio-keys"; - key-wakeup { + key-wakeup@0 { label = "Wake-Up"; gpios = <&porta 14 GPIO_ACTIVE_LOW>; linux,code = ; @@ -43,6 +46,26 @@ wakeup-source; wakeup-event-action = ; }; + + key-wakeup@1 { + label = "Power"; + gpios = <&porta 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 = <&porta 4 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <10>; + wakeup-source; + wakeup-event-action = ; + }; }; }; @@ -137,3 +160,39 @@ line-name = "gpio-mux-debug"; }; }; + +ðernet { + phy-handle = <&phy0>; + mdio { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "snps,dwmac-mdio"; + phy0: phy@0{ + reg = <0x00>; + status = "okay"; + + 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.dtsi b/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi index 5fbd51bfaffc6..a7dbdfddb6243 100644 --- a/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi +++ b/arch/riscv/boot/dts/ultrarisc/dp1000.dtsi @@ -22,14 +22,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache0: l2-cache0 { + /* 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 { device_type = "cpu"; @@ -37,14 +74,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache1: l2-cache1 { + /* 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 { device_type = "cpu"; @@ -52,14 +126,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache2: l2-cache2 { + /* 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 { device_type = "cpu"; @@ -67,14 +178,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache3: l2-cache3 { + /* 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 { device_type = "cpu"; @@ -82,14 +230,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache4: l2-cache4 { + /* 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 { device_type = "cpu"; @@ -97,14 +282,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache5: l2-cache5 { + /* 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 { device_type = "cpu"; @@ -112,16 +334,51 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache6: l2-cache6 { + /* 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 { device_type = "cpu"; @@ -129,14 +386,111 @@ status = "okay"; compatible = "riscv"; riscv,isa = "rv64imafdcbh"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i","m","a","f","d","c","h","zba", + "zbb","zbc","zbs","zicntr","zicsr", + "zifencei","zihpm","ziccif","ziccrse", + "ziccamoa","za64rs","zic64b","zicbom", + "zicbop","zicboz","zkt","zama16b", + "svade","ssccptr","sstvecd","sscounterenw", + "shcounterenw","shtvala","shvstvecd", + "shvsatpa","ssstrict","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 { #address-cells = <0x01>; interrupt-controller; compatible = "riscv,cpu-intc"; #interrupt-cells = <0x01>; }; + l2_cache7: l2-cache7 { + /* 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>; + }; + + 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: cluster1 { + core0 { + cpu = <&cpu4>; + }; + core1 { + cpu = <&cpu5>; + }; + core2 { + cpu = <&cpu6>; + }; + core3 { + cpu = <&cpu7>; + }; + 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>; + }; + }; }; }; @@ -151,6 +505,20 @@ compatible = "simple-bus"; ranges; + 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; + }; + clocks { compatible = "simple-bus"; u-boot,dm-pre-reloc; @@ -170,37 +538,105 @@ clint: clint@8000000 { compatible = "riscv,clint0"; 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>; + <&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>; reg = <0x00 0x8000000 0x00 0x100000>; }; plic: plic@9000000 { #interrupt-cells = <1>; #address-cells = <0>; - phandle = <0x01>; - compatible = "ultrarisc,dp1000-plic"; + compatible = "ultrarisc,cp100-plic", "ultrarisc,dp1000-plic"; 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>; + <&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>; reg = <0x00 0x9000000 0x00 0x4000000>; riscv,max-priority = <0x07>; riscv,ndev = <160>; }; + core_pvt: pvt@110D0000 { + compatible = "ultrarisc,dp1000-pvt"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x00 0x110D0000 0x00 0x0000D000>; + clock-frequency = <250000000>; + channels = <13>; + #thermal-sensor-cells = <1>; + + pvt_channel0: channel@0 { + label = "Core temp0"; + reg = <0>; + }; + + pvt_channel1: channel@1 { + label = "Core temp1"; + reg = <1>; + }; + + pvt_channel2: channel@2 { + label = "Core temp2"; + reg = <2>; + }; + + pvt_channel3: channel@3 { + label = "Core temp3"; + reg = <3>; + }; + + pvt_channel4: channel@4 { + label = "Core temp4"; + reg = <4>; + }; + + pvt_channel5: channel@5 { + label = "Core temp5"; + reg = <5>; + }; + pvt_channel6: channel@6 { + label = "Core temp6"; + reg = <6>; + }; + pvt_channel7: channel@7 { + label = "Core temp7"; + reg = <7>; + }; + pvt_channel8: channel@8 { + label = "Core temp8"; + reg = <8>; + }; + + pvt_channel9: channel@9 { + label = "Core temp9"; + reg = <9>; + }; + pvt_channel10: channel@10 { + label = "Core temp10"; + reg = <10>; + }; + pvt_channel11: channel@11 { + label = "Cluster0 voltage"; + reg = <11>; + }; + pvt_channel12: channel@12 { + label = "Cluster1 voltage"; + reg = <12>; + }; + }; + uart0: serial@20300000 { - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <17>; clock-frequency = <62500000>; current-speed = <115200>; @@ -211,7 +647,7 @@ }; uart1: serial@20310000 { - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <18>; clock-frequency = <62500000>; current-speed = <115200>; @@ -222,7 +658,7 @@ }; uart2: serial@20400000 { - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <25>; clock-frequency = <62500000>; current-speed = <115200>; @@ -233,7 +669,7 @@ }; uart3: serial@20410000 { - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <26>; clock-frequency = <62500000>; current-speed = <115200>; @@ -249,7 +685,7 @@ #address-cells = <0x01>; #size-cells = <0x00>; reg = <0x0 0x20320000 0x0 0x1000>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <19>; clocks = <&device_clk>; clock-names = "device_clk"; @@ -263,7 +699,7 @@ #address-cells = <0x01>; #size-cells = <0x00>; reg = <0x0 0x20420000 0x0 0x1000>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <27>; clocks = <&device_clk>; clock-names = "device_clk"; @@ -279,7 +715,7 @@ reg = <0x0 0x20330000 0x0 0x100>; clock-frequency = <400000>; clocks = <&device_clk>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <20>; }; @@ -291,7 +727,7 @@ reg = <0x0 0x20340000 0x0 0x100>; clock-frequency = <400000>; clocks = <&device_clk>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <21>; }; @@ -303,7 +739,7 @@ reg = <0x0 0x20430000 0x0 0x100>; clock-frequency = <400000>; clocks = <&device_clk>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <28>; }; @@ -315,21 +751,10 @@ reg = <0x0 0x20440000 0x0 0x100>; clock-frequency = <400000>; clocks = <&device_clk>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <29>; }; - wdt0: watchdog@20210000 { - compatible = "snps,dw-wdt"; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0 0x20210000 0x0 0x100>; - interrupt-parent = <0x01>; - interrupts = <33>; - clocks = <&device_clk>; - }; - pmx0: pinmux@11081000 { compatible = "ultrarisc,dp1000-pinctrl"; reg = <0x0 0x11081000 0x0 0x1000>; @@ -358,7 +783,7 @@ snps,nr-gpios = <16>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <34>; gpio-ranges = <&pmx0 0 0 16>; }; @@ -391,11 +816,11 @@ }; }; - ethernet1@38000000 { + ethernet: ethernet1@38000000 { clocks = <&csr_clk>; clock-names = "stmmaceth"; - compatible = "ultrarisc,dp1000-gmac", "snps,dwmac-5.10a"; - interrupt-parent = <0x01>; + compatible = "snps,dwmac", "snps,dwmac-5.10a"; + interrupt-parent = <&plic>; interrupts = <84>; interrupt-names = "macirq"; reg = <0x00 0x38000000 0x00 0x1000000>; @@ -404,17 +829,6 @@ max-speed = <1000>; snps,txpbl = <8>; snps,rxpbl = <8>; - phy-handle = <&phy0>; - mdio { - #address-cells = <0x01>; - #size-cells = <0x00>; - compatible = "snps,dwmac-mdio"; - phy0: phy@0{ - phandle = <0x04>; - reg = <0x00>; - status = "okay"; - }; - }; }; dmac: dma-controller@39000000 { @@ -424,7 +838,7 @@ reg = <0x0 0x39000000 0x0 0x400>; clocks = <&device_clk>, <&device_clk>; clock-names = "core-clk", "cfgr-clk"; - interrupt-parent = <0x01>; + interrupt-parent = <&plic>; interrupts = <152>; #dma-cells = <1>; dma-channels = <8>; @@ -436,7 +850,7 @@ }; pcie_x16: pcie@21000000 { - compatible = "ultrarisc,dw-pcie"; + compatible = "ultrarisc,dp1000-pcie", "ultrarisc,dw-pcie"; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; @@ -447,22 +861,27 @@ dma-coherent; bus-range = <0x0 0xff>; num-lanes = <16>; - ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, /* io */ - <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, /* mem32 */ - <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; /* mem64 prefetchable */ + /* ranges: + * io + * mem32 + * mem64 prefetchable + */ + ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, + <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; max-link-speed = <4>; interrupt-parent = <&plic>; - interrupts = <43>, <44>, <45>, <46>, <47>, <48>; - interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + 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>; + <0x0 0x0 0x0 0x2 &plic 45>, + <0x0 0x0 0x0 0x3 &plic 46>, + <0x0 0x0 0x0 0x4 &plic 47>; }; pcie_x4a: pcie@23000000 { - compatible = "ultrarisc,dw-pcie"; + compatible = "ultrarisc,dp1000-pcie", "ultrarisc,dw-pcie"; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; @@ -473,22 +892,27 @@ dma-coherent; bus-range = <0x0 0xff>; num-lanes = <4>; - ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, /* io */ - <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, /* mem32 */ - <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; /* mem64 prefetchable */ + /* ranges: + * io + * mem32 + * mem64 prefetchable + */ + ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, + <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; max-link-speed = <4>; interrupt-parent = <&plic>; - interrupts = <63>, <64>, <65>, <66>, <67>, <68>; - interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + 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>; + <0x0 0x0 0x0 0x2 &plic 65>, + <0x0 0x0 0x0 0x3 &plic 66>, + <0x0 0x0 0x0 0x4 &plic 67>; }; pcie_x4b: pcie@24000000 { - compatible = "ultrarisc,dw-pcie"; + compatible = "ultrarisc,dp1000-pcie", "ultrarisc,dw-pcie"; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; @@ -499,18 +923,23 @@ dma-coherent; bus-range = <0x0 0xff>; num-lanes = <4>; - ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, /* io */ - <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, /* mem32 */ - <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; /* mem64 prefetchable */ + /* ranges: + * io + * mem32 + * mem64 prefetchable + */ + ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, + <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; max-link-speed = <4>; interrupt-parent = <&plic>; - interrupts = <73>, <74>, <75>, <76>, <77>, <78>; - interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + 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>; + <0x0 0x0 0x0 0x2 &plic 75>, + <0x0 0x0 0x0 0x3 &plic 76>, + <0x0 0x0 0x0 0x4 &plic 77>; }; }; }; diff --git a/arch/riscv/configs/deepin_riscv64_desktop_defconfig b/arch/riscv/configs/deepin_riscv64_desktop_defconfig index 7a8fb9876602b..724fa376d46dc 100644 --- a/arch/riscv/configs/deepin_riscv64_desktop_defconfig +++ b/arch/riscv/configs/deepin_riscv64_desktop_defconfig @@ -1321,6 +1321,7 @@ CONFIG_SENSORS_ADT7470=m CONFIG_SENSORS_ADT7475=m CONFIG_SENSORS_ASC7621=m CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_COREPVT_ULTRARISC=m CONFIG_SENSORS_DRIVETEMP=m CONFIG_SENSORS_DS620=m CONFIG_SENSORS_I5K_AMB=m @@ -1630,7 +1631,9 @@ CONFIG_DRM_AMDGPU=m CONFIG_DRM_AMDGPU_SI=y CONFIG_DRM_AMDGPU_CIK=y CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AMD_ACP=y CONFIG_DRM_AMD_DC_SI=y +CONFIG_DRM_AMD_SECURE_DISPLAY=y CONFIG_DRM_NOUVEAU=m CONFIG_DRM_VGEM=m CONFIG_DRM_UDL=m @@ -2053,8 +2056,10 @@ CONFIG_INFINIBAND_ISER=m CONFIG_INFINIBAND_ISERT=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1307_CENTURY=y CONFIG_RTC_DRV_PCF85063=m CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_SD3078=m CONFIG_RTC_DRV_DA9063=m CONFIG_RTC_DRV_SUN6I=y CONFIG_RTC_DRV_POLARFIRE_SOC=m diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 236538ffd20c5..d386524d39b54 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -458,6 +458,15 @@ config SENSORS_BT1_PVT This driver can also be built as a module. If so, the module will be called bt1-pvt. +config SENSORS_COREPVT_ULTRARISC + tristate "UltraRISC Core Voltage, Temperature sensor driver" + help + If you say yes here you get support for UltraRISC Core PVT sensor + embedded into the SoC. + + This driver can also be built as a module. If so, the module will be + called corepvt-ultrarisc. + config SENSORS_BT1_PVT_ALARMS bool "Enable Baikal-T1 PVT sensor alarms" depends on SENSORS_BT1_PVT diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index ea2c509cb3436..82750fe6a4416 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o obj-$(CONFIG_SENSORS_BT1_PVT) += bt1-pvt.o +obj-$(CONFIG_SENSORS_COREPVT_ULTRARISC) += corepvt-ultrarisc.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_CORSAIR_CPRO) += corsair-cpro.o obj-$(CONFIG_SENSORS_CORSAIR_PSU) += corsair-psu.o diff --git a/drivers/hwmon/corepvt-ultrarisc.c b/drivers/hwmon/corepvt-ultrarisc.c new file mode 100644 index 0000000000000..3674eedefbda1 --- /dev/null +++ b/drivers/hwmon/corepvt-ultrarisc.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for UltraRISC Core PVT + * + * Copyright(C) 2025 UltraRISC Technology (Shanghai) Co., Ltd. + * + * Author: wangjia + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define COREPVT_CHL_OFFSET 0x1000 +#define COREPVT_REG_CIR 0x0 +#define COREPVT_REG_PSCR 0x04 +#define COREPVT_REG_CFDR 0x08 +#define COREPVT_REG_DOR 0x0C +#define COREPVT_REG_ICR 0x10 +#define COREPVT_REG_IER 0x14 +#define COREPVT_REG_IMSR 0x18 +#define COREPVT_REG_IRSR 0x1C + +#define PVT_MAX_CHANNEL 64 +#define PVT_TRIM_DEFAULT 0x7 + +struct corepvt_channel_config { + const char *label; + u32 trim; +}; + +struct corepvt_cal_data { + u32 val_offset; + u32 val_lsb; +}; + +struct corepvt_data { + const struct hwmon_chip_info *chip_info; + u64 temp_chl_mask; + u64 vol_chl_mask; +}; + +struct corepvt_hwmon { + struct device *dev; + struct device *hwmon; + + void __iomem *regs; + int irq; + int clk_freq; + int channels; + const struct hwmon_chip_info *chip_info; + struct corepvt_channel_config config[PVT_MAX_CHANNEL]; + const struct corepvt_data *pvt_data; + raw_spinlock_t lock; +}; + +#define COREPVT_VOLTAGE_DATA_BASE 2065100 /* 2065.1 */ +#define COREPVT_VOLTAGE_LSB 1682 /* 1.682 mV */ +#define COREPVT_TEMP_DATA_BASE 27049000 /* 2704.9 */ +#define COREPVT_TEMP_LSB 22632 /* 2.2632 Celsius */ + +static int corepvt_read_vol(struct corepvt_hwmon *pvt, + int channel, long *val) +{ + void __iomem *chl_base; + unsigned long flag; + u32 dout; + u32 chl_offset = 0; + + // Assume that the voltage channel is continuous + chl_offset = __ffs64(pvt->pvt_data->vol_chl_mask); + chl_base = pvt->regs + COREPVT_CHL_OFFSET * (channel + chl_offset); + + raw_spin_lock_irqsave(&pvt->lock, flag); + dout = readl_relaxed(chl_base + COREPVT_REG_DOR); + raw_spin_unlock_irqrestore(&pvt->lock, flag); + + *val = ((long)dout * 1000 - COREPVT_VOLTAGE_DATA_BASE) / COREPVT_VOLTAGE_LSB; + + return 0; +} + +static int corepvt_read_temp(struct corepvt_hwmon *pvt, + int channel, long *val) +{ + void __iomem *chl_base; + unsigned long flag; + u32 dout; + u32 chl_offset = 0; + + // Assume that the temperature channel is continuous + chl_offset = __ffs64(pvt->pvt_data->temp_chl_mask); + chl_base = pvt->regs + COREPVT_CHL_OFFSET * (channel + chl_offset); + + raw_spin_lock_irqsave(&pvt->lock, flag); + dout = readl_relaxed(chl_base + COREPVT_REG_DOR); + raw_spin_unlock_irqrestore(&pvt->lock, flag); + + *val = ((long)dout * 10000 - COREPVT_TEMP_DATA_BASE) * 1000 / COREPVT_TEMP_LSB; + + return 0; +} + +static umode_t corepvt_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct corepvt_hwmon *pvt = drvdata; + + if (channel >= pvt->channels) + return 0; + + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_input: + case hwmon_in_label: + return 0444; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_type: + case hwmon_temp_label: + return 0444; + } + break; + default: + return 0; + } + + return 0; +} + +static int corepvt_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct corepvt_hwmon *pvt = dev_get_drvdata(dev); + + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_input: + return corepvt_read_vol(pvt, channel, val); + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_type: + *val = 1; + return 0; + case hwmon_temp_input: + return corepvt_read_temp(pvt, channel, val); + } + break; + default: + return -EOPNOTSUPP; + } + + return -ENODATA; +} + +static int corepvt_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct corepvt_hwmon *pvt = dev_get_drvdata(dev); + u32 chl_offset = 0; + + switch (type) { + case hwmon_in: + chl_offset = __ffs64(pvt->pvt_data->vol_chl_mask); + break; + case hwmon_temp: + chl_offset = __ffs64(pvt->pvt_data->temp_chl_mask); + break; + default: + return -ENODATA; + break; + } + + *str = pvt->config[channel + chl_offset].label; + + return 0; +} + +/* + * corepvt init process: + * 1. config SETUP time, should be 10us, set PSCR register + * 2. config CLKIN, should be 4MHz, set CFDR register + * 3. (TODO)config interrupt, set ICR/IER/IMSR/IRSR + * 4. config TRIM and enable PVT, set CIR + */ +static int corepvt_init(struct corepvt_hwmon *pvt) +{ + void __iomem *chl_base; + unsigned long flag; + /* + * SETUP time 10us = 100KHz + * PSCR = CLK_FREQ / 100KHz + */ + u32 pscr_val = pvt->clk_freq / 100000; + /* + * CFDR = CLK_FREQ / 4MHz / 2 + */ + u32 cfdr_val = pvt->clk_freq / 8000000; + /* + * CIR: + * bit[0]: PU_VTDC, set 1 to enable pvt + * bit[5:2]: TRIM + */ + u32 cir_val; + + raw_spin_lock_irqsave(&pvt->lock, flag); + for (int i = 0; i < pvt->channels; i++) { + chl_base = pvt->regs + COREPVT_CHL_OFFSET * i; + cir_val = (pvt->config[i].trim << 2) | 0x01; + writel_relaxed(pscr_val, chl_base + COREPVT_REG_PSCR); + writel_relaxed(cfdr_val, chl_base + COREPVT_REG_CFDR); + writel_relaxed(cir_val, chl_base + COREPVT_REG_CIR); + } + raw_spin_unlock_irqrestore(&pvt->lock, flag); + + return 0; +} + +static const struct hwmon_ops corepvt_hwmon_ops = { + .is_visible = corepvt_is_visible, + .read = corepvt_read, + .read_string = corepvt_read_string, +}; + +static int corepvt_probe_channel_from_dt(struct platform_device *pdev, struct corepvt_hwmon *pvt) +{ + struct device_node *child; + int ret; + u32 channel; + const char *label; + u32 trim; + + for_each_child_of_node(pdev->dev.of_node, child) { + if (!of_node_name_eq(child, "channel")) + continue; + + ret = of_property_read_u32(child, "reg", &channel); + if (ret) + goto node_put; + + ret = of_property_read_string(child, "label", &label); + if (ret) + goto node_put; + + if (of_property_present(child, "trim")) + of_property_read_u32(child, "trim", &trim); + else + trim = PVT_TRIM_DEFAULT; + + pvt->config[channel].label = label; + pvt->config[channel].trim = trim; + } + + return 0; + +node_put: + of_node_put(child); + return ret; +} + +static int corepvt_probe(struct platform_device *pdev) +{ + struct corepvt_hwmon *pvt; + const struct corepvt_data *pvt_data; + int ret; + + pvt = devm_kzalloc(&pdev->dev, sizeof(*pvt), GFP_KERNEL); + if (!pvt) + return -ENOMEM; + + pvt->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pvt->regs)) { + dev_err(&pdev->dev, "get ioremap resource failed\n"); + ret = -EINVAL; + goto free_pvt; + } + + if (device_property_present(&pdev->dev, "interrupts")) + pvt->irq = platform_get_irq(pdev, 0); + + ret = device_property_read_u32(&pdev->dev, "clock-frequency", &pvt->clk_freq); + if (ret) { + dev_err(&pdev->dev, "get clock-frequency failed\n"); + goto free_pvt; + } + + ret = device_property_read_u32(&pdev->dev, "channels", &pvt->channels); + if (ret) { + dev_err(&pdev->dev, "get channels failed\n"); + goto free_pvt; + } + + pvt_data = device_get_match_data(&pdev->dev); + if (!pvt_data) { + dev_err(&pdev->dev, "No chip info found\n"); + ret = -ENODATA; + goto free_pvt; + } + + pvt->dev = &pdev->dev; + pvt->chip_info = pvt_data->chip_info; + pvt->pvt_data = pvt_data; + + if (pdev->dev.of_node) { + ret = corepvt_probe_channel_from_dt(pdev, pvt); + if (ret) + dev_warn(&pdev->dev, "WARN: probe channel failed\n"); + } + + pvt->hwmon = devm_hwmon_device_register_with_info(&pdev->dev, "corepvt_ultrarisc", + pvt, pvt->chip_info, + NULL); + if (IS_ERR(pvt->hwmon)) { + dev_err(&pdev->dev, "register hwmon failed(%ld)\n", PTR_ERR(pvt->hwmon)); + ret = -EINVAL; + goto free_pvt; + } + + pvt->dev = &pdev->dev; + raw_spin_lock_init(&pvt->lock); + + // Config and enable corepvt + corepvt_init(pvt); + + return 0; + +free_pvt: + devm_kfree(&pdev->dev, pvt); + return ret; +} + +static const struct hwmon_channel_info * const ur_dp1000_channel_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + NULL +}; + +static const struct hwmon_chip_info ur_dp1000_chip_info = { + .ops = &corepvt_hwmon_ops, + .info = ur_dp1000_channel_info, +}; + +static struct corepvt_data ur_dp1000_pvt_data = { + .chip_info = &ur_dp1000_chip_info, + .temp_chl_mask = GENMASK_ULL(10, 0), + .vol_chl_mask = GENMASK_ULL(12, 11) +}; + +static const struct of_device_id corepvt_of_match[] = { + { .compatible = "ultrarisc,dp1000-pvt", .data = &ur_dp1000_pvt_data }, + { } +}; +MODULE_DEVICE_TABLE(of, corepvt_of_match); + +static struct platform_driver corepvt_driver = { + .probe = corepvt_probe, + .driver = { + .name = "corepvt-ultrarisc", + .of_match_table = corepvt_of_match + } +}; +module_platform_driver(corepvt_driver); + +MODULE_AUTHOR("Jia Wang "); +MODULE_DESCRIPTION("corepvt-ultrarisc driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index c728db164f83f..12d570e49c28f 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -48,7 +48,7 @@ #define CONTEXT_ENABLE_BASE 0x2000 #define CONTEXT_ENABLE_SIZE 0x80 -#define PENDING_BASE 0x1000 +#define PENDING_BASE 0x1000 /* * Each hart context has a set of control registers associated with it. Right @@ -64,7 +64,7 @@ #define PLIC_ENABLE_THRESHOLD 0 #define PLIC_QUIRK_EDGE_INTERRUPT 0 -#define PLIC_QUIRK_CLAIM_REGISTER 1 +#define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1 struct plic_priv { struct fwnode_handle *fwnode; @@ -94,15 +94,22 @@ static DEFINE_PER_CPU(struct plic_handler, plic_handlers); static int plic_irq_set_type(struct irq_data *d, unsigned int type); -static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) +static void __plic_toggle(struct plic_handler *handler, int hwirq, int enable) { - u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32); + u32 __iomem *base = handler->enable_base; u32 hwirq_mask = 1 << (hwirq % 32); + int group = hwirq / 32; + u32 value; + + value = readl(base + group); if (enable) - writel(readl(reg) | hwirq_mask, reg); + value |= hwirq_mask; else - writel(readl(reg) & ~hwirq_mask, reg); + value &= ~hwirq_mask; + + handler->enable_save[group] = value; + writel(value, base + group); } static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) @@ -110,7 +117,7 @@ static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) unsigned long flags; raw_spin_lock_irqsave(&handler->enable_lock, flags); - __plic_toggle(handler->enable_base, hwirq, enable); + __plic_toggle(handler, hwirq, enable); raw_spin_unlock_irqrestore(&handler->enable_lock, flags); } @@ -250,33 +257,16 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type) static int plic_irq_suspend(void) { - unsigned int i, cpu; - unsigned long flags; - u32 __iomem *reg; struct plic_priv *priv; priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; /* irq ID 0 is reserved */ - for (i = 1; i < priv->nr_irqs; i++) { + for (unsigned int i = 1; i < priv->nr_irqs; i++) { __assign_bit(i, priv->prio_save, readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); } - for_each_cpu(cpu, cpu_present_mask) { - struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - - if (!handler->present) - continue; - - raw_spin_lock_irqsave(&handler->enable_lock, flags); - for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { - reg = handler->enable_base + i * sizeof(u32); - handler->enable_save[i] = readl(reg); - } - raw_spin_unlock_irqrestore(&handler->enable_lock, flags); - } - return 0; } @@ -296,7 +286,7 @@ static void plic_irq_resume(void) priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID); } - for_each_cpu(cpu, cpu_present_mask) { + for_each_present_cpu(cpu) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); if (!handler->present) @@ -368,101 +358,118 @@ static const struct irq_domain_ops plic_irqdomain_ops = { .free = irq_domain_free_irqs_top, }; -static bool plic_check_enable_first_pending(u32 ie[]) +/* + * Handling an interrupt is a two-step process: first you claim the interrupt + * by reading the claim register, then you complete the interrupt by writing + * that source ID back to the same claim register. This automatically enables + * and disables the interrupt, so there's nothing else to do. + */ +static void plic_handle_irq(struct irq_desc *desc) { struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - void __iomem *enable = handler->enable_base; - void __iomem *pending = handler->priv->regs + PENDING_BASE; - int nr_irqs = handler->priv->nr_irqs; - int nr_irq_groups = (nr_irqs + 31) / 32; - bool is_pending = false; - int i, j; - - raw_spin_lock(&handler->enable_lock); - - // Read current interrupt enables - for (i = 0; i < nr_irq_groups; i++) - ie[i] = readl(enable + i * sizeof(u32)); + struct irq_chip *chip = irq_desc_get_chip(desc); + void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; + irq_hw_number_t hwirq; - // Check for pending interrupts and enable only the first one found - for (i = 0; i < nr_irq_groups; i++) { - u32 pending_irqs = readl(pending + i * sizeof(u32)) & ie[i]; + WARN_ON_ONCE(!handler->present); - if (pending_irqs) { - int nbit = __ffs(pending_irqs); + chained_irq_enter(chip, desc); - for (j = 0; j < nr_irq_groups; j++) - writel((i == j)?(1 << nbit):0, enable + j * sizeof(u32)); - is_pending = true; - break; + while ((hwirq = readl(claim))) { + int err = generic_handle_domain_irq(handler->priv->irqdomain, + hwirq); + if (unlikely(err)) { + pr_warn_ratelimited("%pfwP: can't find mapping for hwirq %lu\n", + handler->priv->fwnode, hwirq); } } - raw_spin_unlock(&handler->enable_lock); - - return is_pending; + chained_irq_exit(chip, desc); } -static void plic_restore_enable_state(u32 ie[]) +static u32 cp100_isolate_pending_irq(int nr_irq_groups, struct plic_handler *handler) { - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - void __iomem *enable = handler->enable_base; - int nr_irqs = handler->priv->nr_irqs; - int nr_irq_groups = (nr_irqs + 31) / 32; - int i; + u32 __iomem *pending = handler->priv->regs + PENDING_BASE; + u32 __iomem *enable = handler->enable_base; + u32 pending_irqs = 0; + int i, j; - raw_spin_lock(&handler->enable_lock); + /* Look for first pending interrupt */ + for (i = 0; i < nr_irq_groups; i++) { + /* Any pending interrupts would be annihilated, so skip checking them */ + if (!handler->enable_save[i]) + continue; - for (i = 0; i < nr_irq_groups; i++) - writel(ie[i], enable + i * sizeof(u32)); + pending_irqs = handler->enable_save[i] & readl_relaxed(pending + i); + if (pending_irqs) + break; + } - raw_spin_unlock(&handler->enable_lock); + if (!pending_irqs) + return 0; + + /* Isolate lowest set bit */ + pending_irqs &= -pending_irqs; + + /* Disable all interrupts but the first pending one */ + for (j = 0; j < nr_irq_groups; j++) { + u32 new_mask = j == i ? pending_irqs : 0; + + if (new_mask != handler->enable_save[j]) + writel_relaxed(new_mask, enable + j); + } + return pending_irqs; } -static irq_hw_number_t plic_get_hwirq(void) +static irq_hw_number_t cp100_get_hwirq(struct plic_handler *handler, void __iomem *claim) { - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - struct plic_priv *priv = handler->priv; - void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; - irq_hw_number_t hwirq; - u32 ie[32] = {0}; + int nr_irq_groups = DIV_ROUND_UP(handler->priv->nr_irqs, 32); + u32 __iomem *enable = handler->enable_base; + irq_hw_number_t hwirq = 0; + u32 iso_mask; + int i; + + guard(raw_spinlock)(&handler->enable_lock); + + /* Existing enable state is already cached in enable_save */ + iso_mask = cp100_isolate_pending_irq(nr_irq_groups, handler); + if (!iso_mask) + return 0; /* - * Due to the implementation of the claim register in the UltraRISC DP1000 - * platform PLIC not conforming to the specification, this is a hardware - * bug. Therefore, when an interrupt is pending, we need to disable the other - * interrupts before reading the claim register. After processing the interrupt, - * we should then restore the enable register. + * Interrupts delievered to hardware still become pending, but only + * interrupts that are both pending and enabled can be claimed. + * Clearing the enable bit for all interrupts but the first pending + * one avoids a hardware bug that occurs during read from the claim + * register with more than one eligible interrupt. */ - if (test_bit(PLIC_QUIRK_CLAIM_REGISTER, &priv->plic_quirks)) { - hwirq = plic_check_enable_first_pending(ie)?readl(claim):0; - plic_restore_enable_state(ie); - } else { - hwirq = readl(claim); - } + hwirq = readl(claim); + + /* Restore previous state */ + for (i = 0; i < nr_irq_groups; i++) { + u32 written = i == hwirq / 32 ? iso_mask : 0; + u32 stored = handler->enable_save[i]; + if (stored != written) + writel_relaxed(stored, enable + i); + } return hwirq; } -/* - * Handling an interrupt is a two-step process: first you claim the interrupt - * by reading the claim register, then you complete the interrupt by writing - * that source ID back to the same claim register. This automatically enables - * and disables the interrupt, so there's nothing else to do. - */ -static void plic_handle_irq(struct irq_desc *desc) +static void plic_handle_irq_cp100(struct irq_desc *desc) { struct plic_handler *handler = this_cpu_ptr(&plic_handlers); struct irq_chip *chip = irq_desc_get_chip(desc); + void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; irq_hw_number_t hwirq; WARN_ON_ONCE(!handler->present); chained_irq_enter(chip, desc); - while ((hwirq = plic_get_hwirq())) { - int err = generic_handle_domain_irq(handler->priv->irqdomain, - hwirq); + while ((hwirq = cp100_get_hwirq(handler, claim))) { + int err = generic_handle_domain_irq(handler->priv->irqdomain, hwirq); + if (unlikely(err)) { pr_warn_ratelimited("%pfwP: can't find mapping for hwirq %lu\n", handler->priv->fwnode, hwirq); @@ -508,8 +515,8 @@ static const struct of_device_id plic_match[] = { .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, { .compatible = "thead,c900-plic", .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, - { .compatible = "ultrarisc,dp1000-plic", - .data = (const void *)BIT(PLIC_QUIRK_CLAIM_REGISTER) }, + { .compatible = "ultrarisc,cp100-plic", + .data = (const void *)BIT(PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM) }, {} }; @@ -626,12 +633,11 @@ static int plic_probe(struct fwnode_handle *fwnode) if (parent_hwirq != RV_IRQ_EXT) { /* Disable S-mode enable bits if running in M-mode. */ if (IS_ENABLED(CONFIG_RISCV_M_MODE)) { - void __iomem *enable_base = priv->regs + - CONTEXT_ENABLE_BASE + - i * CONTEXT_ENABLE_SIZE; + u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE + + i * CONTEXT_ENABLE_SIZE; - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) - __plic_toggle(enable_base, hwirq, 0); + for (int j = 0; j <= nr_irqs / 32; j++) + writel(0, enable_base + j); } continue; } @@ -702,12 +708,17 @@ static int plic_probe(struct fwnode_handle *fwnode) } if (global_setup) { + void (*handler_fn)(struct irq_desc *) = plic_handle_irq; + + if (test_bit(PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM, &handler->priv->plic_quirks)) + handler_fn = plic_handle_irq_cp100; + /* Find parent domain and register chained handler */ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); if (domain) plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT); if (plic_parent_irq) - irq_set_chained_handler(plic_parent_irq, plic_handle_irq); + irq_set_chained_handler(plic_parent_irq, handler_fn); cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, "irqchip/sifive/plic:starting", diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index e7d75716632b8..ad1da4f3eafba 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -559,6 +559,12 @@ int led_classdev_register_ext(struct device *parent, led_init_core(led_cdev); #ifdef CONFIG_LEDS_TRIGGERS + /* + * If no default trigger was given and hw_control_trigger is set, + * make it the default trigger. + */ + if (!led_cdev->default_trigger && led_cdev->hw_control_trigger) + led_cdev->default_trigger = led_cdev->hw_control_trigger; led_trigger_set_default(led_cdev); #endif diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 136cb7f7469b6..8bf0dbefad8a8 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -117,15 +117,22 @@ static void led_timer_function(struct timer_list *t) static void set_brightness_delayed_set_brightness(struct led_classdev *led_cdev, unsigned int value) { - int ret = 0; + int ret; ret = __led_set_brightness(led_cdev, value); - if (ret == -ENOTSUPP) + if (ret == -ENOTSUPP) { ret = __led_set_brightness_blocking(led_cdev, value); - if (ret < 0 && - /* LED HW might have been unplugged, therefore don't warn */ - !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) && - (led_cdev->flags & LED_HW_PLUGGABLE))) + if (ret == -ENOTSUPP) + /* No back-end support to set a fixed brightness value */ + return; + } + + /* LED HW might have been unplugged, therefore don't warn */ + if (ret == -ENODEV && led_cdev->flags & LED_UNREGISTERING && + led_cdev->flags & LED_HW_PLUGGABLE) + return; + + if (ret < 0) dev_err(led_cdev->dev, "Setting an LED's brightness failed (%d)\n", ret); } diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 72fd2fe8f6fe8..30b0f80393931 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -23,7 +23,7 @@ * Nests outside led_cdev->trigger_lock */ static DECLARE_RWSEM(triggers_list_lock); -LIST_HEAD(trigger_list); +static LIST_HEAD(trigger_list); /* Used by LED Class */ @@ -54,6 +54,11 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, goto unlock; } + if (sysfs_streq(buf, "default")) { + led_trigger_set_default(led_cdev); + goto unlock; + } + down_read(&triggers_list_lock); list_for_each_entry(trig, &trigger_list, next_trig) { if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) { @@ -98,6 +103,9 @@ static int led_trigger_format(char *buf, size_t size, int len = led_trigger_snprintf(buf, size, "%s", led_cdev->trigger ? "none" : "[none]"); + if (led_cdev->default_trigger) + len += led_trigger_snprintf(buf + len, size - len, " default"); + list_for_each_entry(trig, &trigger_list, next_trig) { bool hit; @@ -260,25 +268,48 @@ void led_trigger_remove(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_trigger_remove); +static bool led_match_default_trigger(struct led_classdev *led_cdev, + struct led_trigger *trig) +{ + if (!strcmp(led_cdev->default_trigger, trig->name) && + trigger_relevant(led_cdev, trig)) { + led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; + led_trigger_set(led_cdev, trig); + return true; + } + + return false; +} + void led_trigger_set_default(struct led_classdev *led_cdev) { struct led_trigger *trig; + bool found = false; if (!led_cdev->default_trigger) return; + if (!strcmp(led_cdev->default_trigger, "none")) { + led_trigger_remove(led_cdev); + return; + } + down_read(&triggers_list_lock); down_write(&led_cdev->trigger_lock); list_for_each_entry(trig, &trigger_list, next_trig) { - if (!strcmp(led_cdev->default_trigger, trig->name) && - trigger_relevant(led_cdev, trig)) { - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; - led_trigger_set(led_cdev, trig); + found = led_match_default_trigger(led_cdev, trig); + if (found) break; - } } up_write(&led_cdev->trigger_lock); up_read(&triggers_list_lock); + + /* + * If default trigger wasn't found, maybe trigger module isn't loaded yet. + * Once loaded it will re-probe with all led_cdev's. + */ + if (!found) + request_module_nowait("ledtrig:%s", led_cdev->default_trigger); } EXPORT_SYMBOL_GPL(led_trigger_set_default); @@ -310,12 +341,8 @@ int led_trigger_register(struct led_trigger *trig) down_read(&leds_list_lock); list_for_each_entry(led_cdev, &leds_list, node) { down_write(&led_cdev->trigger_lock); - if (!led_cdev->trigger && led_cdev->default_trigger && - !strcmp(led_cdev->default_trigger, trig->name) && - trigger_relevant(led_cdev, trig)) { - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; - led_trigger_set(led_cdev, trig); - } + if (!led_cdev->trigger && led_cdev->default_trigger) + led_match_default_trigger(led_cdev, trig); up_write(&led_cdev->trigger_lock); } up_read(&leds_list_lock); diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index 345062ccabdaa..1138e2ab82e55 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -30,7 +30,6 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, extern struct rw_semaphore leds_list_lock; extern struct list_head leds_list; -extern struct list_head trigger_list; extern const char * const led_colors[LED_COLOR_ID_MAX]; #endif /* __LEDS_H_INCLUDED */ diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 79719fc8a08fb..55739c1597413 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include "../leds.h" @@ -55,12 +57,15 @@ struct led_netdev_data { unsigned long mode; int link_speed; + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported_link_modes); u8 duplex; bool carrier_link_up; bool hw_control; }; +static const struct attribute_group netdev_trig_link_speed_attrs_group; + static void set_baseline_state(struct led_netdev_data *trigger_data) { int current_brightness; @@ -99,6 +104,18 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) trigger_data->link_speed == SPEED_1000) blink_on = true; + if (test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) && + trigger_data->link_speed == SPEED_2500) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) && + trigger_data->link_speed == SPEED_5000) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) && + trigger_data->link_speed == SPEED_10000) + blink_on = true; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) && trigger_data->duplex == DUPLEX_HALF) blink_on = true; @@ -196,13 +213,20 @@ static void get_device_state(struct led_netdev_data *trigger_data) struct ethtool_link_ksettings cmd; trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); - if (!trigger_data->carrier_link_up) + + if (__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) return; - if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) { + if (trigger_data->carrier_link_up) { trigger_data->link_speed = cmd.base.speed; trigger_data->duplex = cmd.base.duplex; } + + /* + * Have a local copy of the link speed supported to avoid rtnl lock every time + * modes are refreshed on any change event + */ + linkmode_copy(trigger_data->supported_link_modes, cmd.link_modes.supported); } static ssize_t device_name_show(struct device *dev, @@ -255,7 +279,10 @@ static int set_device_name(struct led_netdev_data *trigger_data, trigger_data->last_activity = 0; - set_baseline_state(trigger_data); + /* Skip if we're called from netdev_trig_activate() and hw_control is true */ + if (!trigger_data->hw_control || led_get_trigger_data(trigger_data->led_cdev)) + set_baseline_state(trigger_data); + mutex_unlock(&trigger_data->lock); rtnl_unlock(); @@ -273,6 +300,10 @@ static ssize_t device_name_store(struct device *dev, if (ret < 0) return ret; + + /* Refresh link_speed visibility */ + sysfs_update_group(&dev->kobj, &netdev_trig_link_speed_attrs_group); + return size; } @@ -289,6 +320,9 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf, case TRIGGER_NETDEV_LINK_10: case TRIGGER_NETDEV_LINK_100: case TRIGGER_NETDEV_LINK_1000: + case TRIGGER_NETDEV_LINK_2500: + case TRIGGER_NETDEV_LINK_5000: + case TRIGGER_NETDEV_LINK_10000: case TRIGGER_NETDEV_HALF_DUPLEX: case TRIGGER_NETDEV_FULL_DUPLEX: case TRIGGER_NETDEV_TX: @@ -319,6 +353,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, case TRIGGER_NETDEV_LINK_10: case TRIGGER_NETDEV_LINK_100: case TRIGGER_NETDEV_LINK_1000: + case TRIGGER_NETDEV_LINK_2500: + case TRIGGER_NETDEV_LINK_5000: + case TRIGGER_NETDEV_LINK_10000: case TRIGGER_NETDEV_HALF_DUPLEX: case TRIGGER_NETDEV_FULL_DUPLEX: case TRIGGER_NETDEV_TX: @@ -337,7 +374,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, if (test_bit(TRIGGER_NETDEV_LINK, &mode) && (test_bit(TRIGGER_NETDEV_LINK_10, &mode) || test_bit(TRIGGER_NETDEV_LINK_100, &mode) || - test_bit(TRIGGER_NETDEV_LINK_1000, &mode))) + test_bit(TRIGGER_NETDEV_LINK_1000, &mode) || + test_bit(TRIGGER_NETDEV_LINK_2500, &mode) || + test_bit(TRIGGER_NETDEV_LINK_5000, &mode) || + test_bit(TRIGGER_NETDEV_LINK_10000, &mode))) return -EINVAL; cancel_delayed_work_sync(&trigger_data->work); @@ -367,6 +407,9 @@ DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK); DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10); DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100); DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000); +DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500); +DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000); +DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000); DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX); DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX); DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX); @@ -419,12 +462,63 @@ static ssize_t offloaded_show(struct device *dev, static DEVICE_ATTR_RO(offloaded); -static struct attribute *netdev_trig_attrs[] = { - &dev_attr_device_name.attr, - &dev_attr_link.attr, +#define CHECK_LINK_MODE_ATTR(link_speed) \ + do { \ + if (attr == &dev_attr_link_##link_speed.attr && \ + link_ksettings.base.speed == SPEED_##link_speed) \ + return attr->mode; \ + } while (0) + +static umode_t netdev_trig_link_speed_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct led_netdev_data *trigger_data; + unsigned long *supported_link_modes; + u32 mode; + + trigger_data = led_trigger_get_drvdata(dev); + supported_link_modes = trigger_data->supported_link_modes; + + /* + * Search in the supported link mode mask a matching supported mode. + * Stop at the first matching entry as we care only to check if a particular + * speed is supported and not the kind. + */ + for_each_set_bit(mode, supported_link_modes, __ETHTOOL_LINK_MODE_MASK_NBITS) { + struct ethtool_link_ksettings link_ksettings; + + ethtool_params_from_link_mode(&link_ksettings, mode); + + CHECK_LINK_MODE_ATTR(10); + CHECK_LINK_MODE_ATTR(100); + CHECK_LINK_MODE_ATTR(1000); + CHECK_LINK_MODE_ATTR(2500); + CHECK_LINK_MODE_ATTR(5000); + CHECK_LINK_MODE_ATTR(10000); + } + + return 0; +} + +static struct attribute *netdev_trig_link_speed_attrs[] = { &dev_attr_link_10.attr, &dev_attr_link_100.attr, &dev_attr_link_1000.attr, + &dev_attr_link_2500.attr, + &dev_attr_link_5000.attr, + &dev_attr_link_10000.attr, + NULL +}; + +static const struct attribute_group netdev_trig_link_speed_attrs_group = { + .attrs = netdev_trig_link_speed_attrs, + .is_visible = netdev_trig_link_speed_visible, +}; + +static struct attribute *netdev_trig_attrs[] = { + &dev_attr_device_name.attr, + &dev_attr_link.attr, &dev_attr_full_duplex.attr, &dev_attr_half_duplex.attr, &dev_attr_rx.attr, @@ -433,7 +527,16 @@ static struct attribute *netdev_trig_attrs[] = { &dev_attr_offloaded.attr, NULL }; -ATTRIBUTE_GROUPS(netdev_trig); + +static const struct attribute_group netdev_trig_attrs_group = { + .attrs = netdev_trig_attrs, +}; + +static const struct attribute_group *netdev_trig_groups[] = { + &netdev_trig_attrs_group, + &netdev_trig_link_speed_attrs_group, + NULL, +}; static int netdev_trig_notify(struct notifier_block *nb, unsigned long evt, void *dv) @@ -442,6 +545,7 @@ static int netdev_trig_notify(struct notifier_block *nb, netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv); struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); + struct led_classdev *led_cdev = trigger_data->led_cdev; if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER @@ -474,8 +578,14 @@ static int netdev_trig_notify(struct notifier_block *nb, trigger_data->net_dev = NULL; break; case NETDEV_UP: + trigger_data->hw_control = can_hw_control(trigger_data); + fallthrough; case NETDEV_CHANGE: get_device_state(trigger_data); + /* Refresh link_speed visibility */ + if (evt == NETDEV_CHANGE) + sysfs_update_group(&led_cdev->dev->kobj, + &netdev_trig_link_speed_attrs_group); break; } @@ -522,6 +632,9 @@ static void netdev_trig_work(struct work_struct *work) test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode); interval = jiffies_to_msecs( @@ -572,8 +685,8 @@ static int netdev_trig_activate(struct led_classdev *led_cdev) if (dev) { const char *name = dev_name(dev); - set_device_name(trigger_data, name, strlen(name)); trigger_data->hw_control = true; + set_device_name(trigger_data, name, strlen(name)); rc = led_cdev->hw_control_get(led_cdev, &mode); if (!rc) @@ -618,3 +731,4 @@ MODULE_AUTHOR("Ben Whitten "); MODULE_AUTHOR("Oliver Jowett "); MODULE_DESCRIPTION("Netdev LED trigger"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("ledtrig:netdev"); diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c index 5a6b21bfeb9af..1d49c10780910 100644 --- a/drivers/leds/trigger/ledtrig-panic.c +++ b/drivers/leds/trigger/ledtrig-panic.c @@ -21,24 +21,15 @@ static struct led_trigger *trigger; */ static void led_trigger_set_panic(struct led_classdev *led_cdev) { - struct led_trigger *trig; + if (led_cdev->trigger) + list_del(&led_cdev->trig_list); + list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); - list_for_each_entry(trig, &trigger_list, next_trig) { - if (strcmp("panic", trig->name)) - continue; - if (led_cdev->trigger) - list_del(&led_cdev->trig_list); - list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); + /* Avoid the delayed blink path */ + led_cdev->blink_delay_on = 0; + led_cdev->blink_delay_off = 0; - /* Avoid the delayed blink path */ - led_cdev->blink_delay_on = 0; - led_cdev->blink_delay_off = 0; - - led_cdev->trigger = trig; - if (trig->activate) - trig->activate(led_cdev); - break; - } + led_cdev->trigger = trigger; } static int led_trigger_panic_notifier(struct notifier_block *nb, diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 2604d9663a5b2..99487f91c1509 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -32,6 +32,15 @@ #define RTL8211F_PHYCR2 0x19 #define RTL8211F_INSR 0x1d +#define RTL8211F_LEDCR 0x10 +#define RTL8211F_LEDCR_MODE BIT(15) +#define RTL8211F_LEDCR_ACT_TXRX BIT(4) +#define RTL8211F_LEDCR_LINK_1000 BIT(3) +#define RTL8211F_LEDCR_LINK_100 BIT(1) +#define RTL8211F_LEDCR_LINK_10 BIT(0) +#define RTL8211F_LEDCR_MASK GENMASK(4, 0) +#define RTL8211F_LEDCR_SHIFT 5 + #define RTL8211F_TX_DELAY BIT(8) #define RTL8211F_RX_DELAY BIT(3) @@ -73,6 +82,8 @@ #define RTL_GENERIC_PHYID 0x001cc800 #define RTL_8211FVD_PHYID 0x001cc878 +#define RTL8211F_LED_COUNT 3 + MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); @@ -462,6 +473,102 @@ static int rtl821x_resume(struct phy_device *phydev) return 0; } +static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX); + + /* The RTL8211F PHY supports these LED settings on up to three LEDs: + * - Link: Configurable subset of 10/100/1000 link rates + * - Active: Blink on activity, RX or TX is not differentiated + * The Active option has two modes, A and B: + * - A: Link and Active indication at configurable, but matching, + * subset of 10/100/1000 link rates + * - B: Link indication at configurable subset of 10/100/1000 link + * rates and Active indication always at all three 10+100+1000 + * link rates. + * This code currently uses mode B only. + */ + + if (index >= RTL8211F_LED_COUNT) + return -EINVAL; + + /* Filter out any other unsupported triggers. */ + if (rules & ~mask) + return -EOPNOTSUPP; + + /* RX and TX are not differentiated, either both are set or not set. */ + if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) + return -EOPNOTSUPP; + + return 0; +} + +static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int val; + + if (index >= RTL8211F_LED_COUNT) + return -EINVAL; + + val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); + if (val < 0) + return val; + + val >>= RTL8211F_LEDCR_SHIFT * index; + val &= RTL8211F_LEDCR_MASK; + + if (val & RTL8211F_LEDCR_LINK_10) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + + if (val & RTL8211F_LEDCR_LINK_100) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + + if (val & RTL8211F_LEDCR_LINK_1000) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + + if (val & RTL8211F_LEDCR_ACT_TXRX) { + set_bit(TRIGGER_NETDEV_RX, rules); + set_bit(TRIGGER_NETDEV_TX, rules); + } + + return 0; +} + +static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); + u16 reg = 0; + + if (index >= RTL8211F_LED_COUNT) + return -EINVAL; + + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + reg |= RTL8211F_LEDCR_LINK_10; + + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + reg |= RTL8211F_LEDCR_LINK_100; + + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + reg |= RTL8211F_LEDCR_LINK_1000; + + if (test_bit(TRIGGER_NETDEV_RX, &rules) || + test_bit(TRIGGER_NETDEV_TX, &rules)) { + reg |= RTL8211F_LEDCR_ACT_TXRX; + } + + reg <<= RTL8211F_LEDCR_SHIFT * index; + reg |= RTL8211F_LEDCR_MODE; /* Mode B */ + + return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); +} + static int rtl8211e_config_init(struct phy_device *phydev) { int ret = 0, oldpage; @@ -962,6 +1069,9 @@ static struct phy_driver realtek_drvs[] = { .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, .flags = PHY_ALWAYS_CALL_SUSPEND, + .led_hw_is_supported = rtl8211f_led_hw_is_supported, + .led_hw_control_get = rtl8211f_led_hw_control_get, + .led_hw_control_set = rtl8211f_led_hw_control_set, }, { PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), .name = "RTL8211F-VD Gigabit Ethernet", diff --git a/drivers/pci/controller/dwc/pcie-ultrarisc.c b/drivers/pci/controller/dwc/pcie-ultrarisc.c index 73c9cd36ca90c..7a87fb0443807 100644 --- a/drivers/pci/controller/dwc/pcie-ultrarisc.c +++ b/drivers/pci/controller/dwc/pcie-ultrarisc.c @@ -183,9 +183,8 @@ int ultrarisc_pcie_resume(struct platform_device *pdev) } static const struct of_device_id ultrarisc_pcie_of_match[] = { - { - .compatible = "ultrarisc,dw-pcie", - }, + { .compatible = "ultrarisc,dp1000-pcie", }, + { .compatible = "ultrarisc,dw-pcie", }, {}, }; diff --git a/include/dt-bindings/pinctrl/ur-dp1000-pinctrl.h b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h similarity index 100% rename from include/dt-bindings/pinctrl/ur-dp1000-pinctrl.h rename to include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h diff --git a/include/linux/leds.h b/include/linux/leds.h index e91802cdc4161..3cdeae7ea1d9e 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -586,6 +586,9 @@ enum led_trigger_netdev_modes { TRIGGER_NETDEV_LINK_10, TRIGGER_NETDEV_LINK_100, TRIGGER_NETDEV_LINK_1000, + TRIGGER_NETDEV_LINK_2500, + TRIGGER_NETDEV_LINK_5000, + TRIGGER_NETDEV_LINK_10000, TRIGGER_NETDEV_HALF_DUPLEX, TRIGGER_NETDEV_FULL_DUPLEX, TRIGGER_NETDEV_TX,