Compare commits

...

7 Commits

Author SHA1 Message Date
Yao Zi
d0121ff282 platform/loongarch: laptop: Unregister generic_sub_drivers on exit
Without correct unregisteration, ACPI notify handlers and the platform
drivers installed by generic_subdriver_init() will become dangling
references after removing the loongson_laptop module, triggering various
kernel faults when a hotkey is sent or at kernel shutdown.

Cc: stable@vger.kernel.org
Fixes: 6246ed0911 ("LoongArch: Add ACPI-based generic laptop driver")
Signed-off-by: Yao Zi <ziyao@disroot.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:46 +08:00
Yao Zi
d2598ed841 platform/loongarch: laptop: Add backlight power control support
loongson_laptop_turn_{on,off}_backlight() are designed for controlling
the power of the backlight, but they aren't really used in the driver
previously.

Unify these two functions since they only differ in arguments passed to
ACPI method, and wire up loongson_laptop_backlight_update() to update
the power state of the backlight as well. Tested on the TongFang L860-T2
Loongson-3A5000 laptop.

Cc: stable@vger.kernel.org
Fixes: 6246ed0911 ("LoongArch: Add ACPI-based generic laptop driver")
Signed-off-by: Yao Zi <ziyao@disroot.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:46 +08:00
Yao Zi
d239e28030 platform/loongarch: laptop: Get brightness setting from EC on probe
Previously during driver probe, 1 is unconditionally taken as current
brightness value and set to props.brightness, which will be considered
as the brightness before suspend and restored to EC on resume. Since a
brightness value of 1 almost never matches EC's state on coldboot (my
laptop's EC defaults to 80), this causes surprising changes of screen
brightness on the first time of resume after coldboot.

Let's get brightness from EC and take it as the current brightness on
probe of the laptop driver to avoid the surprising behavior. Tested on
TongFang L860-T2 Loongson-3A5000 laptop.

Cc: stable@vger.kernel.org
Fixes: 6246ed0911 ("LoongArch: Add ACPI-based generic laptop driver")
Signed-off-by: Yao Zi <ziyao@disroot.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:46 +08:00
Binbin Zhou
e771eba3ab LoongArch: dts: Add PWM support to Loongson-2K2000
The module is supported, enable it.

Reviewed-by: Yanteng Si <si.yanteng@linux.dev>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:34 +08:00
Binbin Zhou
50bae9e48f LoongArch: dts: Add PWM support to Loongson-2K1000
The module is supported, enable it.

Also, add the pwm-fan and cooling-maps associated with it.

Reviewed-by: Yanteng Si <si.yanteng@linux.dev>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:34 +08:00
Binbin Zhou
6e8265c5dd LoongArch: dts: Add PWM support to Loongson-2K0500
The module is supported, enable it.

Reviewed-by: Yanteng Si <si.yanteng@linux.dev>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:34 +08:00
Thomas Weißschuh
96d5ba5c5e LoongArch: vDSO: Correctly use asm parameters in syscall wrappers
The syscall wrappers use the "a0" register for two different register
variables, both the first argument and the return value. Here the "ret"
variable is used as both input and output while the argument register is
only used as input. Clang treats the conflicting input parameters as an
undefined behaviour and optimizes away the argument assignment.

The code seems to work by chance for the most part today but that may
change in the future. Specifically clock_gettime_fallback() fails with
clockids from 16 to 23, as implemented by the upcoming auxiliary clocks.

Switch the "ret" register variable to a pure output, similar to the
other architectures' vDSO code. This works in both clang and GCC.

Link: https://lore.kernel.org/lkml/20250602102825-42aa84f0-23f1-4d10-89fc-e8bbaffd291a@linutronix.de/
Link: https://lore.kernel.org/lkml/20250519082042.742926976@linutronix.de/
Fixes: c6b99bed6b ("LoongArch: Add VDSO and VSYSCALL support")
Fixes: 18efd0b10e ("LoongArch: vDSO: Wire up getrandom() vDSO implementation")
Cc: stable@vger.kernel.org
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Reviewed-by: Yanteng Si <si.yanteng@linux.dev>
Reviewed-by: WANG Xuerui <git@xen0n.name>
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2025-06-05 20:34:18 +08:00
7 changed files with 337 additions and 47 deletions

View File

@ -169,6 +169,166 @@ eiointc: interrupt-controller@1fe11600 {
interrupts = <3>;
};
pwm@1ff5c000 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c000 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c010 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c010 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c020 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c020 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c030 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c030 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c040 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c040 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c050 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c050 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c060 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c060 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c070 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c070 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c080 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c080 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c090 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c090 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0a0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0a0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0b0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0b0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0c0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0c0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0d0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0d0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0e0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0e0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1ff5c0f0 {
compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1ff5c0f0 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
gmac0: ethernet@1f020000 {
compatible = "snps,dwmac-3.70a";
reg = <0x0 0x1f020000 0x0 0x10000>;

View File

@ -5,6 +5,7 @@
/dts-v1/;
#include "dt-bindings/thermal/thermal.h"
#include "loongson-2k1000.dtsi"
/ {
@ -38,6 +39,13 @@ linux,cma {
linux,cma-default;
};
};
fan0: pwm-fan {
compatible = "pwm-fan";
cooling-levels = <255 153 85 25>;
pwms = <&pwm1 0 100000 0>;
#cooling-cells = <2>;
};
};
&gmac0 {
@ -92,6 +100,22 @@ &spi0 {
#size-cells = <0>;
};
&pwm1 {
status = "okay";
pinctrl-0 = <&pwm1_pins_default>;
pinctrl-names = "default";
};
&cpu_thermal {
cooling-maps {
map0 {
trip = <&cpu_alert>;
cooling-device = <&fan0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
};
};
&ehci0 {
status = "okay";
};

View File

@ -68,7 +68,7 @@ i2c-gpio-1 {
};
thermal-zones {
cpu-thermal {
cpu_thermal: cpu-thermal {
polling-delay-passive = <1000>;
polling-delay = <5000>;
thermal-sensors = <&tsensor 0>;
@ -322,6 +322,46 @@ i2c3: i2c@1fe21800 {
status = "disabled";
};
pwm@1fe22000 {
compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1fe22000 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm1: pwm@1fe22010 {
compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1fe22010 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1fe22020 {
compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1fe22020 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@1fe22030 {
compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x1fe22030 0x0 0x10>;
interrupt-parent = <&liointc0>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_APB_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pmc: power-management@1fe27000 {
compatible = "loongson,ls2k1000-pmc", "loongson,ls2k0500-pmc", "syscon";
reg = <0x0 0x1fe27000 0x0 0x58>;

View File

@ -165,6 +165,66 @@ msi: msi-controller@1fe01140 {
interrupt-parent = <&eiointc>;
};
pwm@100a0000 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0000 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@100a0100 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0100 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@100a0200 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0200 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@100a0300 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0300 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@100a0400 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0400 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
pwm@100a0500 {
compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm";
reg = <0x0 0x100a0500 0x0 0x10>;
interrupt-parent = <&pic>;
interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk LOONGSON2_MISC_CLK>;
#pwm-cells = <3>;
status = "disabled";
};
rtc0: rtc@100d0100 {
compatible = "loongson,ls2k2000-rtc", "loongson,ls7a-rtc";
reg = <0x0 0x100d0100 0x0 0x100>;

View File

@ -20,7 +20,7 @@ static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, uns
asm volatile(
" syscall 0\n"
: "+r" (ret)
: "=r" (ret)
: "r" (nr), "r" (buffer), "r" (len), "r" (flags)
: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8",
"memory");

View File

@ -25,7 +25,7 @@ static __always_inline long gettimeofday_fallback(
asm volatile(
" syscall 0\n"
: "+r" (ret)
: "=r" (ret)
: "r" (nr), "r" (tv), "r" (tz)
: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$t8", "memory");
@ -44,7 +44,7 @@ static __always_inline long clock_gettime_fallback(
asm volatile(
" syscall 0\n"
: "+r" (ret)
: "=r" (ret)
: "r" (nr), "r" (clkid), "r" (ts)
: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$t8", "memory");
@ -63,7 +63,7 @@ static __always_inline int clock_getres_fallback(
asm volatile(
" syscall 0\n"
: "+r" (ret)
: "=r" (ret)
: "r" (nr), "r" (clkid), "r" (ts)
: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$t8", "memory");

View File

@ -56,8 +56,7 @@ static struct input_dev *generic_inputdev;
static acpi_handle hotkey_handle;
static struct key_entry hotkey_keycode_map[GENERIC_HOTKEY_MAP_MAX];
int loongson_laptop_turn_on_backlight(void);
int loongson_laptop_turn_off_backlight(void);
static bool bl_powered;
static int loongson_laptop_backlight_update(struct backlight_device *bd);
/* 2. ACPI Helpers and device model */
@ -354,16 +353,41 @@ static int ec_backlight_level(u8 level)
return level;
}
static int ec_backlight_set_power(bool state)
{
int status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = state;
status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL);
if (ACPI_FAILURE(status)) {
pr_info("Loongson lvds error: 0x%x\n", status);
return -EIO;
}
return 0;
}
static int loongson_laptop_backlight_update(struct backlight_device *bd)
{
int lvl = ec_backlight_level(bd->props.brightness);
bool target_powered = !backlight_is_blank(bd);
int ret = 0, lvl = ec_backlight_level(bd->props.brightness);
if (lvl < 0)
return -EIO;
if (ec_set_brightness(lvl))
return -EIO;
return 0;
if (target_powered == bl_powered) {
ret = ec_set_brightness(lvl);
} else {
ret = ec_backlight_set_power(target_powered);
if (ret < 0)
return ret;
bl_powered = target_powered;
}
return ret;
}
static int loongson_laptop_get_brightness(struct backlight_device *bd)
@ -384,7 +408,7 @@ static const struct backlight_ops backlight_laptop_ops = {
static int laptop_backlight_register(void)
{
int status = 0;
int status = 0, ret;
struct backlight_properties props;
memset(&props, 0, sizeof(props));
@ -392,44 +416,20 @@ static int laptop_backlight_register(void)
if (!acpi_evalf(hotkey_handle, &status, "ECLL", "d"))
return -EIO;
props.brightness = 1;
ret = ec_backlight_set_power(true);
if (ret)
return ret;
bl_powered = true;
props.max_brightness = status;
props.brightness = ec_get_brightness();
props.power = BACKLIGHT_POWER_ON;
props.type = BACKLIGHT_PLATFORM;
backlight_device_register("loongson_laptop",
NULL, NULL, &backlight_laptop_ops, &props);
return 0;
}
int loongson_laptop_turn_on_backlight(void)
{
int status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 1;
status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL);
if (ACPI_FAILURE(status)) {
pr_info("Loongson lvds error: 0x%x\n", status);
return -ENODEV;
}
return 0;
}
int loongson_laptop_turn_off_backlight(void)
{
int status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 0;
status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL);
if (ACPI_FAILURE(status)) {
pr_info("Loongson lvds error: 0x%x\n", status);
return -ENODEV;
}
return 0;
}
@ -611,11 +611,17 @@ static int __init generic_acpi_laptop_init(void)
static void __exit generic_acpi_laptop_exit(void)
{
int i;
if (generic_inputdev) {
if (input_device_registered)
input_unregister_device(generic_inputdev);
else
if (!input_device_registered) {
input_free_device(generic_inputdev);
} else {
input_unregister_device(generic_inputdev);
for (i = 0; i < ARRAY_SIZE(generic_sub_drivers); i++)
generic_subdriver_exit(&generic_sub_drivers[i]);
}
}
}