Commit 3f1a3a28 authored by Maxime Ripard's avatar Maxime Ripard

Merge tag 'backlight-detect-refactor-1' of...

Merge tag 'backlight-detect-refactor-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 into drm-misc-next

Immutable backlight-detect-refactor branch between acpi, drm-* and pdx86

Tag (immutable branch) with v6.0-rc1 + the (acpi/x86) backlight
detect refactor work. For merging into the acpi, drm-* and pdx86
subsystems.
Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmMVsogUHGhkZWdvZWRl
# QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9yy6wgAlig+7hkq940L62lTpj0g2gNQv8zc
# HCsMpnU7dnJcZYaEvIjouZhf33ZbN52c0fQq2JWjt7fFX04LLyIiyrJ26Lc293JR
# ++yXpJcVoewRGqApy/P3Z05TKUCLll5bexvK4t8isnhOtEXD/nDPWKTLIV2Kd1DK
# nLY4KgRznXZ85RhYheUEdidZ7Lwlzt1JVBMq7tpnzu3nVdDExyZmqlqCUITcLynu
# ysuASQGr0D2i+1vb9eifHIA3xsQO0S37Bv62aBMBKxB6B8Fz1DYr8VA2YvoT82Hv
# IFT0hzCCZ/63Ljga05O78TwraxAQX0RvZWqjqGgnZg6fIBh2hxUiqeQY6g==
# =SA1R
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 05 Sep 2022 09:25:44 AM IST
# gpg:                using RSA key BAF03B5D2718411A5E9E177E92EC4779440327DC
# gpg:                issuer "hdegoede@redhat.com"
# gpg: Can't check signature: No public key
From: Hans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/261afe3d-7790-e945-adf6-a2c96c9b1eff@redhat.com
parents a108772d 4f96b1bc
......@@ -679,6 +679,74 @@ Contact: Sam Ravnborg
Level: Advanced
Brightness handling on devices with multiple internal panels
============================================================
On x86/ACPI devices there can be multiple backlight firmware interfaces:
(ACPI) video, vendor specific and others. As well as direct/native (PWM)
register programming by the KMS driver.
To deal with this backlight drivers used on x86/ACPI call
acpi_video_get_backlight_type() which has heuristics (+quirks) to select
which backlight interface to use; and backlight drivers which do not match
the returned type will not register themselves, so that only one backlight
device gets registered (in a single GPU setup, see below).
At the moment this more or less assumes that there will only
be 1 (internal) panel on a system.
On systems with 2 panels this may be a problem, depending on
what interface acpi_video_get_backlight_type() selects:
1. native: in this case the KMS driver is expected to know which backlight
device belongs to which output so everything should just work.
2. video: this does support controlling multiple backlights, but some work
will need to be done to get the output <-> backlight device mapping
The above assumes both panels will require the same backlight interface type.
Things will break on systems with multiple panels where the 2 panels need
a different type of control. E.g. one panel needs ACPI video backlight control,
where as the other is using native backlight control. Currently in this case
only one of the 2 required backlight devices will get registered, based on
the acpi_video_get_backlight_type() return value.
If this (theoretical) case ever shows up, then supporting this will need some
work. A possible solution here would be to pass a device and connector-name
to acpi_video_get_backlight_type() so that it can deal with this.
Note in a way we already have a case where userspace sees 2 panels,
in dual GPU laptop setups with a mux. On those systems we may see
either 2 native backlight devices; or 2 native backlight devices.
Userspace already has code to deal with this by detecting if the related
panel is active (iow which way the mux between the GPU and the panels
points) and then uses that backlight device. Userspace here very much
assumes a single panel though. It picks only 1 of the 2 backlight devices
and then only uses that one.
Note that all userspace code (that I know off) is currently hardcoded
to assume a single panel.
Before the recent changes to not register multiple (e.g. video + native)
/sys/class/backlight devices for a single panel (on a single GPU laptop),
userspace would see multiple backlight devices all controlling the same
backlight.
To deal with this userspace had to always picks one preferred device under
/sys/class/backlight and will ignore the others. So to support brightness
control on multiple panels userspace will need to be updated too.
There are plans to allow brightness control through the KMS API by adding
a "display brightness" property to drm_connector objects for panels. This
solves a number of issues with the /sys/class/backlight API, including not
being able to map a sysfs backlight device to a specific connector. Any
userspace changes to add support for brightness control on devices with
multiple panels really should build on top of this new KMS property.
Contact: Hans de Goede
Level: Advanced
Outside DRM
===========
......
......@@ -14532,6 +14532,7 @@ M: Daniel Dadap <ddadap@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/nvidia-wmi-ec-backlight.c
F: include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
NVM EXPRESS DRIVER
M: Keith Busch <kbusch@kernel.org>
......
......@@ -212,6 +212,7 @@ config ACPI_VIDEO
tristate "Video"
depends on BACKLIGHT_CLASS_DEVICE
depends on INPUT
depends on ACPI_WMI || !X86
select THERMAL
help
This driver implements the ACPI Extensions For Display Adapters
......
......@@ -73,6 +73,16 @@ module_param(device_id_scheme, bool, 0444);
static int only_lcd = -1;
module_param(only_lcd, int, 0444);
/*
* Display probing is known to take up to 5 seconds, so delay the fallback
* backlight registration by 5 seconds + 3 seconds for some extra margin.
*/
static int register_backlight_delay = 8;
module_param(register_backlight_delay, int, 0444);
MODULE_PARM_DESC(register_backlight_delay,
"Delay in seconds before doing fallback (non GPU driver triggered) "
"backlight registration, set to 0 to disable.");
static bool may_report_brightness_keys;
static int register_count;
static DEFINE_MUTEX(register_count_mutex);
......@@ -81,7 +91,9 @@ static LIST_HEAD(video_bus_head);
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
void acpi_video_detect_exit(void);
static void acpi_video_bus_register_backlight_work(struct work_struct *ignored);
static DECLARE_DELAYED_WORK(video_bus_register_backlight_work,
acpi_video_bus_register_backlight_work);
/*
* Indices in the _BCL method response: the first two items are special,
......@@ -1859,8 +1871,6 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
if (video->backlight_registered)
return 0;
acpi_video_run_bcl_for_osi(video);
if (acpi_video_get_backlight_type() != acpi_backlight_video)
return 0;
......@@ -2086,7 +2096,11 @@ static int acpi_video_bus_add(struct acpi_device *device)
list_add_tail(&video->entry, &video_bus_head);
mutex_unlock(&video_list_lock);
acpi_video_bus_register_backlight(video);
/*
* The userspace visible backlight_device gets registered separately
* from acpi_video_register_backlight().
*/
acpi_video_run_bcl_for_osi(video);
acpi_video_bus_add_notify_handler(video);
return 0;
......@@ -2111,20 +2125,25 @@ static int acpi_video_bus_remove(struct acpi_device *device)
video = acpi_driver_data(device);
acpi_video_bus_remove_notify_handler(video);
acpi_video_bus_unregister_backlight(video);
acpi_video_bus_put_devices(video);
mutex_lock(&video_list_lock);
list_del(&video->entry);
mutex_unlock(&video_list_lock);
acpi_video_bus_remove_notify_handler(video);
acpi_video_bus_unregister_backlight(video);
acpi_video_bus_put_devices(video);
kfree(video->attached_array);
kfree(video);
return 0;
}
static void acpi_video_bus_register_backlight_work(struct work_struct *ignored)
{
acpi_video_register_backlight();
}
static int __init is_i740(struct pci_dev *dev)
{
if (dev->device == 0x00D1)
......@@ -2235,6 +2254,18 @@ int acpi_video_register(void)
*/
register_count = 1;
/*
* acpi_video_bus_add() skips registering the userspace visible
* backlight_device. The intend is for this to be registered by the
* drm/kms driver calling acpi_video_register_backlight() *after* it is
* done setting up its own native backlight device. The delayed work
* ensures that acpi_video_register_backlight() always gets called
* eventually, in case there is no drm/kms driver or it is disabled.
*/
if (register_backlight_delay)
schedule_delayed_work(&video_bus_register_backlight_work,
register_backlight_delay * HZ);
leave:
mutex_unlock(&register_count_mutex);
return ret;
......@@ -2245,6 +2276,7 @@ void acpi_video_unregister(void)
{
mutex_lock(&register_count_mutex);
if (register_count) {
cancel_delayed_work_sync(&video_bus_register_backlight_work);
acpi_bus_unregister_driver(&acpi_video_bus);
register_count = 0;
may_report_brightness_keys = false;
......@@ -2253,19 +2285,16 @@ void acpi_video_unregister(void)
}
EXPORT_SYMBOL(acpi_video_unregister);
void acpi_video_unregister_backlight(void)
void acpi_video_register_backlight(void)
{
struct acpi_video_bus *video;
mutex_lock(&register_count_mutex);
if (register_count) {
mutex_lock(&video_list_lock);
list_for_each_entry(video, &video_bus_head, entry)
acpi_video_bus_unregister_backlight(video);
mutex_unlock(&video_list_lock);
}
mutex_unlock(&register_count_mutex);
mutex_lock(&video_list_lock);
list_for_each_entry(video, &video_bus_head, entry)
acpi_video_bus_register_backlight(video);
mutex_unlock(&video_list_lock);
}
EXPORT_SYMBOL(acpi_video_register_backlight);
bool acpi_video_handles_brightness_key_presses(void)
{
......@@ -2302,7 +2331,6 @@ static int __init acpi_video_init(void)
static void __exit acpi_video_exit(void)
{
acpi_video_detect_exit();
acpi_video_unregister();
}
......
......@@ -17,8 +17,9 @@
* Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
* sony_acpi,... can take care about backlight brightness.
*
* Backlight drivers can use acpi_video_get_backlight_type() to determine
* which driver should handle the backlight.
* Backlight drivers can use acpi_video_get_backlight_type() to determine which
* driver should handle the backlight. RAW/GPU-driver backlight drivers must
* use the acpi_video_backlight_use_native() helper for this.
*
* If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
* this file will not be compiled and acpi_video_get_backlight_type() will
......@@ -27,20 +28,16 @@
#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/apple-gmux.h>
#include <linux/backlight.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <acpi/video.h>
void acpi_video_unregister_backlight(void);
static bool backlight_notifier_registered;
static struct notifier_block backlight_nb;
static struct work_struct backlight_notify_work;
static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
......@@ -78,6 +75,36 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
/* This depends on ACPI_WMI which is X86 only */
#ifdef CONFIG_X86
static bool nvidia_wmi_ec_supported(void)
{
struct wmi_brightness_args args = {
.mode = WMI_BRIGHTNESS_MODE_GET,
.val = 0,
.ret = 0,
};
struct acpi_buffer buf = { (acpi_size)sizeof(args), &args };
acpi_status status;
status = wmi_evaluate_method(WMI_BRIGHTNESS_GUID, 0,
WMI_BRIGHTNESS_METHOD_SOURCE, &buf, &buf);
if (ACPI_FAILURE(status))
return false;
/*
* If brightness is handled by the EC then nvidia-wmi-ec-backlight
* should be used, else the GPU driver(s) should be used.
*/
return args.ret == WMI_BRIGHTNESS_SOURCE_EC;
}
#else
static bool nvidia_wmi_ec_supported(void)
{
return false;
}
#endif
/* Force to use vendor driver when the ACPI device is known to be
* buggy */
static int video_detect_force_vendor(const struct dmi_system_id *d)
......@@ -105,62 +132,142 @@ static int video_detect_force_none(const struct dmi_system_id *d)
}
static const struct dmi_system_id video_detect_dmi_table[] = {
/* On Samsung X360, the BIOS will set a flag (VDRV) if generic
* ACPI backlight device is used. This flag will definitively break
* the backlight interface (even the vendor interface) until next
* reboot. It's why we should prevent video.ko from being used here
* and we can't rely on a later call to acpi_video_unregister().
*/
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */
.callback = video_detect_force_vendor,
/* X360 */
/* Acer KAV80 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
DMI_MATCH(DMI_BOARD_NAME, "X360"),
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus UL30VT */
.matches = {
.callback = video_detect_force_vendor,
/* Asus UL30VT */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus UL30A */
.matches = {
.callback = video_detect_force_vendor,
/* Asus UL30A */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
},
},
{
.callback = video_detect_force_vendor,
/* GIGABYTE GB-BXBT-2807 */
.matches = {
.callback = video_detect_force_vendor,
/* Asus X55U */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus X101CH */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus X401U */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus X501U */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
},
},
{
.callback = video_detect_force_vendor,
/* Asus 1015CX */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
},
},
{
.callback = video_detect_force_vendor,
/* GIGABYTE GB-BXBT-2807 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
},
},
{
.callback = video_detect_force_vendor,
/* Sony VPCEH3U1E */
.matches = {
.callback = video_detect_force_vendor,
/* Samsung N150/N210/N220 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
},
},
{
.callback = video_detect_force_vendor,
/* Samsung NF110/NF210/NF310 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
},
},
{
.callback = video_detect_force_vendor,
/* Samsung NC210 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
},
},
{
.callback = video_detect_force_vendor,
/* Sony VPCEH3U1E */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
},
},
{
.callback = video_detect_force_vendor,
/* Xiaomi Mi Pad 2 */
.matches = {
.callback = video_detect_force_vendor,
/* Xiaomi Mi Pad 2 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
},
},
/*
* Toshiba models with Transflective display, these need to use
* the toshiba_acpi vendor driver for proper Transflective handling.
*/
{
.callback = video_detect_force_vendor,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"),
},
},
{
.callback = video_detect_force_vendor,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"),
},
},
/*
* These models have a working acpi_video backlight control, and using
* native backlight causes a regression where backlight does not work
......@@ -390,130 +497,119 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
/* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
/* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */
.callback = video_detect_force_native,
/* Acer TravelMate 5735Z */
/* Acer Aspire 5741 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
},
},
{
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA401 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
},
},
{
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA502 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
/* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */
.callback = video_detect_force_native,
/* Acer Aspire 5750 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
},
},
{
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA503 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
/* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */
.callback = video_detect_force_native,
/* Acer Extensa 5235 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
},
},
/*
* Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
* working native and video interface. However the default detection
* mechanism first registers the video interface before unregistering
* it again and switching to the native interface during boot. This
* results in a dangling SBIOS request for backlight change for some
* reason, causing the backlight to switch to ~2% once per boot on the
* first power cord connect or disconnect event. Setting the native
* interface explicitly circumvents this buggy behaviour, by avoiding
* the unregistering process.
*/
{
.callback = video_detect_force_native,
.ident = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
.callback = video_detect_force_native,
/* Acer TravelMate 4750 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
},
},
{
.callback = video_detect_force_native,
.ident = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
/* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
.callback = video_detect_force_native,
/* Acer TravelMate 5735Z */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
},
},
{
.callback = video_detect_force_native,
.ident = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
/* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */
.callback = video_detect_force_native,
/* Acer TravelMate 5760 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
},
},
{
.callback = video_detect_force_native,
.ident = "Clevo NL5xNU",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA401 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
},
},
/*
* The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
* Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
* NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
* above.
*/
{
.callback = video_detect_force_native,
.ident = "TongFang PF5PU1G",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA502 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF4NU1F",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
.callback = video_detect_force_native,
/* ASUSTeK COMPUTER INC. GA503 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF4NU1F",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
.callback = video_detect_force_native,
/* Asus UX303UB */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF5NU1G",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
.callback = video_detect_force_native,
/* Samsung N150P */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
DMI_MATCH(DMI_BOARD_NAME, "N150P"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF5NU1G",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
.callback = video_detect_force_native,
/* Samsung N145P/N250P/N260P */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF5LUXG",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
.callback = video_detect_force_native,
/* Samsung N250P */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
DMI_MATCH(DMI_BOARD_NAME, "N250P"),
},
},
/*
* Desktops which falsely report a backlight and which our heuristics
* for this do not catch.
......@@ -537,43 +633,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
{ },
};
/* This uses a workqueue to avoid various locking ordering issues */
static void acpi_video_backlight_notify_work(struct work_struct *work)
{
if (acpi_video_get_backlight_type() != acpi_backlight_video)
acpi_video_unregister_backlight();
}
static int acpi_video_backlight_notify(struct notifier_block *nb,
unsigned long val, void *bd)
{
struct backlight_device *backlight = bd;
/* A raw bl registering may change video -> native */
if (backlight->props.type == BACKLIGHT_RAW &&
val == BACKLIGHT_REGISTERED)
schedule_work(&backlight_notify_work);
return NOTIFY_OK;
}
/*
* Determine which type of backlight interface to use on this system,
* First check cmdline, then dmi quirks, then do autodetect.
*
* The autodetect order is:
* 1) Is the acpi-video backlight interface supported ->
* no, use a vendor interface
* 2) Is this a win8 "ready" BIOS and do we have a native interface ->
* yes, use a native interface
* 3) Else use the acpi-video interface
*
* Arguably the native on win8 check should be done first, but that would
* be a behavior change, which may causes issues.
*/
enum acpi_backlight_type acpi_video_get_backlight_type(void)
static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
{
static DEFINE_MUTEX(init_mutex);
static bool nvidia_wmi_ec_present;
static bool native_available;
static bool init_done;
static long video_caps;
......@@ -585,48 +653,60 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void)
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_video, NULL,
&video_caps, NULL);
INIT_WORK(&backlight_notify_work,
acpi_video_backlight_notify_work);
backlight_nb.notifier_call = acpi_video_backlight_notify;
backlight_nb.priority = 0;
if (backlight_register_notifier(&backlight_nb) == 0)
backlight_notifier_registered = true;
nvidia_wmi_ec_present = nvidia_wmi_ec_supported();
init_done = true;
}
if (native)
native_available = true;
mutex_unlock(&init_mutex);
/*
* The below heuristics / detection steps are in order of descending
* presedence. The commandline takes presedence over anything else.
*/
if (acpi_backlight_cmdline != acpi_backlight_undef)
return acpi_backlight_cmdline;
/* DMI quirks override any autodetection. */
if (acpi_backlight_dmi != acpi_backlight_undef)
return acpi_backlight_dmi;
if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
return acpi_backlight_vendor;
/* Special cases such as nvidia_wmi_ec and apple gmux. */
if (nvidia_wmi_ec_present)
return acpi_backlight_nvidia_wmi_ec;
if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW))
return acpi_backlight_native;
if (apple_gmux_present())
return acpi_backlight_apple_gmux;
/* On systems with ACPI video use either native or ACPI video. */
if (video_caps & ACPI_VIDEO_BACKLIGHT) {
/*
* Windows 8 and newer no longer use the ACPI video interface,
* so it often does not work. If the ACPI tables are written
* for win8 and native brightness ctl is available, use that.
*
* The native check deliberately is inside the if acpi-video
* block on older devices without acpi-video support native
* is usually not the best choice.
*/
if (acpi_osi_is_win8() && native_available)
return acpi_backlight_native;
else
return acpi_backlight_video;
}
return acpi_backlight_video;
/* No ACPI video (old hw), use vendor specific fw methods. */
return acpi_backlight_vendor;
}
EXPORT_SYMBOL(acpi_video_get_backlight_type);
/*
* Set the preferred backlight interface type based on DMI info.
* This function allows DMI blacklists to be implemented by external
* platform drivers instead of putting a big blacklist in video_detect.c
*/
void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
enum acpi_backlight_type acpi_video_get_backlight_type(void)
{
acpi_backlight_dmi = type;
/* Remove acpi-video backlight interface if it is no longer desired */
if (acpi_video_get_backlight_type() != acpi_backlight_video)
acpi_video_unregister_backlight();
return __acpi_video_get_backlight_type(false);
}
EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
EXPORT_SYMBOL(acpi_video_get_backlight_type);
void __exit acpi_video_detect_exit(void)
bool acpi_video_backlight_use_native(void)
{
if (backlight_notifier_registered)
backlight_unregister_notifier(&backlight_nb);
return __acpi_video_get_backlight_type(true) == acpi_backlight_native;
}
EXPORT_SYMBOL(acpi_video_backlight_use_native);
......@@ -235,6 +235,13 @@ config DRM_RADEON
select HWMON
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
# radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
# ACPI_VIDEO's dependencies must also be selected.
select INPUT if ACPI
select ACPI_VIDEO if ACPI
# On x86 ACPI_VIDEO also needs ACPI_WMI
select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to
......@@ -260,6 +267,13 @@ config DRM_AMDGPU
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
select DRM_BUDDY
# amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
# ACPI_VIDEO's dependencies must also be selected.
select INPUT if ACPI
select ACPI_VIDEO if ACPI
# On x86 ACPI_VIDEO also needs ACPI_WMI
select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86
help
Choose this option if you have a recent AMD Radeon graphics card.
......
......@@ -26,6 +26,8 @@
#include <linux/pci.h>
#include <acpi/video.h>
#include <drm/drm_crtc_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
......@@ -182,7 +184,12 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode
return;
if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
return;
goto register_acpi_backlight;
if (!acpi_video_backlight_use_native()) {
drm_info(dev, "Skipping amdgpu atom DIG backlight registration\n");
goto register_acpi_backlight;
}
pdata = kmalloc(sizeof(struct amdgpu_backlight_privdata), GFP_KERNEL);
if (!pdata) {
......@@ -218,6 +225,11 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode
error:
kfree(pdata);
return;
register_acpi_backlight:
/* Try registering an ACPI video backlight device instead. */
acpi_video_register_backlight();
return;
}
void
......
......@@ -90,6 +90,8 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <acpi/video.h>
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
#include "dcn/dcn_1_0_offset.h"
......@@ -4032,6 +4034,13 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
amdgpu_dm_update_backlight_caps(dm, dm->num_of_edps);
dm->brightness[dm->num_of_edps] = AMDGPU_MAX_BL_LEVEL;
if (!acpi_video_backlight_use_native()) {
drm_info(adev_to_drm(dm->adev), "Skipping amdgpu DM backlight registration\n");
/* Try registering an ACPI video backlight device instead. */
acpi_video_register_backlight();
return;
}
props.max_brightness = AMDGPU_MAX_BL_LEVEL;
props.brightness = AMDGPU_MAX_BL_LEVEL;
props.type = BACKLIGHT_RAW;
......
......@@ -7,6 +7,8 @@ config DRM_GMA500
select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select X86_PLATFORM_DEVICES if ACPI
select ACPI_WMI if ACPI
help
Say yes for an experimental 2D KMS framebuffer driver for the
Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and
......
......@@ -23,6 +23,8 @@ config DRM_I915
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select X86_PLATFORM_DEVICES if ACPI
select ACPI_WMI if ACPI
select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
select SYNC_FILE
......
......@@ -7,6 +7,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/video.h>
#include "i915_drv.h"
#include "intel_acpi.h"
......@@ -331,3 +332,29 @@ void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915)
*/
fwnode_handle_put(fwnode);
}
void intel_acpi_video_register(struct drm_i915_private *i915)
{
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
acpi_video_register();
/*
* If i915 is driving an internal panel without registering its native
* backlight handler try to register the acpi_video backlight.
* For panels not driven by i915 another GPU driver may still register
* a native backlight later and acpi_video_register_backlight() should
* only be called after any native backlights have been registered.
*/
drm_connector_list_iter_begin(&i915->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct intel_panel *panel = &to_intel_connector(connector)->panel;
if (panel->backlight.funcs && !panel->backlight.device) {
acpi_video_register_backlight();
break;
}
}
drm_connector_list_iter_end(&conn_iter);
}
......@@ -14,6 +14,7 @@ void intel_unregister_dsm_handler(void);
void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915);
void intel_acpi_device_id_update(struct drm_i915_private *i915);
void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915);
void intel_acpi_video_register(struct drm_i915_private *i915);
#else
static inline void intel_register_dsm_handler(void) { return; }
static inline void intel_unregister_dsm_handler(void) { return; }
......@@ -23,6 +24,8 @@ static inline
void intel_acpi_device_id_update(struct drm_i915_private *i915) { return; }
static inline
void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) { return; }
static inline
void intel_acpi_video_register(struct drm_i915_private *i915) { return; }
#endif /* CONFIG_ACPI */
#endif /* __INTEL_ACPI_H__ */
......@@ -8,6 +8,8 @@
#include <linux/pwm.h>
#include <linux/string_helpers.h>
#include <acpi/video.h>
#include "intel_backlight.h"
#include "intel_connector.h"
#include "intel_de.h"
......@@ -950,6 +952,11 @@ int intel_backlight_device_register(struct intel_connector *connector)
WARN_ON(panel->backlight.max == 0);
if (!acpi_video_backlight_use_native()) {
drm_info(&i915->drm, "Skipping intel_backlight registration\n");
return 0;
}
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
......
......@@ -9089,7 +9089,7 @@ void intel_display_driver_register(struct drm_i915_private *i915)
/* Must be done after probing outputs */
intel_opregion_register(i915);
acpi_video_register();
intel_acpi_video_register(i915);
intel_audio_init(i915);
......
......@@ -386,3 +386,13 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
}
bool nouveau_acpi_video_backlight_use_native(void)
{
return acpi_video_backlight_use_native();
}
void nouveau_acpi_video_register_backlight(void)
{
acpi_video_register_backlight();
}
......@@ -11,6 +11,8 @@ void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
void nouveau_switcheroo_optimus_dsm(void);
void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
bool nouveau_acpi_video_backlight_use_native(void);
void nouveau_acpi_video_register_backlight(void);
#else
static inline bool nouveau_is_optimus(void) { return false; };
static inline bool nouveau_is_v1_dsm(void) { return false; };
......@@ -18,6 +20,8 @@ static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline void nouveau_switcheroo_optimus_dsm(void) {}
static inline void *nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return NULL; }
static inline bool nouveau_acpi_video_backlight_use_native(void) { return true; }
static inline void nouveau_acpi_video_register_backlight(void) {}
#endif
#endif
......@@ -38,6 +38,7 @@
#include "nouveau_reg.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_acpi.h"
static struct ida bl_ida;
#define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0'
......@@ -405,6 +406,11 @@ nouveau_backlight_init(struct drm_connector *connector)
goto fail_alloc;
}
if (!nouveau_acpi_video_backlight_use_native()) {
NV_INFO(drm, "Skipping nv_backlight registration\n");
goto fail_alloc;
}
if (!nouveau_get_backlight_name(backlight_name, bl)) {
NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n");
goto fail_alloc;
......@@ -430,6 +436,13 @@ nouveau_backlight_init(struct drm_connector *connector)
fail_alloc:
kfree(bl);
/*
* If we get here we have an internal panel, but no nv_backlight,
* try registering an ACPI video backlight device instead.
*/
if (ret == 0)
nouveau_acpi_video_register_backlight();
return ret;
}
......
......@@ -32,6 +32,8 @@
#include <drm/drm_file.h>
#include <drm/radeon_drm.h>
#include <acpi/video.h>
#include "atom.h"
#include "radeon_atombios.h"
#include "radeon.h"
......@@ -209,6 +211,11 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
return;
if (!acpi_video_backlight_use_native()) {
drm_info(dev, "Skipping radeon atom DIG backlight registration\n");
return;
}
pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
if (!pdata) {
DRM_ERROR("Memory allocation failed\n");
......
......@@ -30,6 +30,8 @@
#include <drm/drm_device.h>
#include <drm/radeon_drm.h>
#include <acpi/video.h>
#include "radeon.h"
#include "radeon_atombios.h"
#include "radeon_legacy_encoders.h"
......@@ -167,7 +169,7 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
return;
if (radeon_backlight == 0) {
return;
use_bl = false;
} else if (radeon_backlight == 1) {
use_bl = true;
} else if (radeon_backlight == -1) {
......@@ -193,6 +195,13 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
else
radeon_legacy_backlight_init(radeon_encoder, connector);
}
/*
* If there is no native backlight device (which may happen even when
* use_bl==true) try registering an ACPI video backlight device instead.
*/
if (!rdev->mode_info.bl_encoder)
acpi_video_register_backlight();
}
void
......
......@@ -33,6 +33,8 @@
#include <drm/drm_util.h>
#include <drm/radeon_drm.h>
#include <acpi/video.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_legacy_encoders.h"
......@@ -387,6 +389,11 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
return;
#endif
if (!acpi_video_backlight_use_native()) {
drm_info(dev, "Skipping radeon legacy LVDS backlight registration\n");
return;
}
pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
if (!pdata) {
DRM_ERROR("Memory allocation failed\n");
......
......@@ -93,6 +93,7 @@ config PEAQ_WMI
config NVIDIA_WMI_EC_BACKLIGHT
tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems"
depends on ACPI_VIDEO
depends on ACPI_WMI
depends on BACKLIGHT_CLASS_DEVICE
help
......
......@@ -643,69 +643,6 @@ static const struct dmi_system_id non_acer_quirks[] __initconst = {
{}
};
static int __init
video_set_backlight_video_vendor(const struct dmi_system_id *d)
{
interface->capability &= ~ACER_CAP_BRIGHTNESS;
pr_info("Brightness must be controlled by generic video driver\n");
return 0;
}
static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer TravelMate 4750",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
},
},
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer Extensa 5235",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
},
},
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer TravelMate 5760",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
},
},
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer Aspire 5750",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
},
},
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer Aspire 5741",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
},
},
{
/*
* Note no video_set_backlight_video_vendor, we must use the
* acer interface, as there is no native backlight interface.
*/
.ident = "Acer KAV80",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
},
},
{}
};
/* Find which quirks are needed for a particular vendor/ model pair */
static void __init find_quirks(void)
{
......@@ -2477,9 +2414,6 @@ static int __init acer_wmi_init(void)
set_quirks();
if (dmi_check_system(video_vendor_dmi_table))
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
interface->capability &= ~ACER_CAP_BRIGHTNESS;
......
......@@ -21,7 +21,6 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
#include <acpi/video.h>
#include <asm/io.h>
/**
......@@ -694,7 +693,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
* backlight control and supports more levels than other options.
* Disable the other backlight choices.
*/
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
apple_bl_unregister();
gmux_data->power_state = VGA_SWITCHEROO_ON;
......@@ -804,7 +802,6 @@ static void gmux_remove(struct pnp_dev *pnp)
apple_gmux_data = NULL;
kfree(gmux_data);
acpi_video_register();
apple_bl_register();
}
......
......@@ -79,12 +79,10 @@ static struct quirk_entry quirk_asus_q500a = {
/*
* For those machines that need software to control bt/wifi status
* and can't adjust brightness through ACPI interface
* and have duplicate events(ACPI and WMI) for display toggle
*/
static struct quirk_entry quirk_asus_x55u = {
.wapf = 4,
.wmi_backlight_power = true,
.wmi_backlight_set_devstate = true,
.no_display_toggle = true,
};
......@@ -99,11 +97,6 @@ static struct quirk_entry quirk_asus_x200ca = {
.wmi_backlight_set_devstate = true,
};
static struct quirk_entry quirk_asus_ux303ub = {
.wmi_backlight_native = true,
.wmi_backlight_set_devstate = true,
};
static struct quirk_entry quirk_asus_x550lb = {
.wmi_backlight_set_devstate = true,
.xusb2pr = 0x01D9,
......@@ -147,11 +140,6 @@ static const struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
},
/*
* Note this machine has a Brazos APU, and most Brazos Asus
* machines need quirk_asus_x55u / wmi_backlight_power but
* here acpi-video seems to work fine for backlight control.
*/
.driver_data = &quirk_asus_wapf4,
},
{
......@@ -379,15 +367,6 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_x200ca,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. UX303UB",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
},
.driver_data = &quirk_asus_ux303ub,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. UX330UAK",
......
......@@ -3553,7 +3553,6 @@ static int asus_wmi_add(struct platform_device *pdev)
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
struct asus_wmi *asus;
const char *chassis_type;
acpi_status status;
int err;
u32 result;
......@@ -3635,18 +3634,6 @@ static int asus_wmi_add(struct platform_device *pdev)
if (asus->driver->quirks->wmi_force_als_set)
asus_wmi_set_als();
/* Some Asus desktop boards export an acpi-video backlight interface,
stop this from showing up */
chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
if (chassis_type && !strcmp(chassis_type, "3"))
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
if (asus->driver->quirks->wmi_backlight_power)
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
if (asus->driver->quirks->wmi_backlight_native)
acpi_video_set_dmi_backlight_type(acpi_backlight_native);
if (asus->driver->quirks->xusb2pr)
asus_wmi_set_xusb2pr(asus);
......
......@@ -29,8 +29,6 @@ struct quirk_entry {
bool hotplug_wireless;
bool scalar_panel_brightness;
bool store_backlight_power;
bool wmi_backlight_power;
bool wmi_backlight_native;
bool wmi_backlight_set_devstate;
bool wmi_force_als_set;
bool use_kbd_dock_devid;
......
......@@ -96,11 +96,6 @@ static struct quirk_entry quirk_asus_et2012_type3 = {
.store_backlight_power = true,
};
static struct quirk_entry quirk_asus_x101ch = {
/* We need this when ACPI function doesn't do this well */
.wmi_backlight_power = true,
};
static struct quirk_entry *quirks;
static void et2012_quirks(void)
......@@ -151,25 +146,7 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_unknown,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. X101CH",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
},
.driver_data = &quirk_asus_x101ch,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. 1015CX",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
},
.driver_data = &quirk_asus_x101ch,
},
{},
{}
};
static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
......
......@@ -7,73 +7,10 @@
#include <linux/backlight.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
#include <linux/types.h>
#include <linux/wmi.h>
/**
* enum wmi_brightness_method - WMI method IDs
* @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status
* @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source
*/
enum wmi_brightness_method {
WMI_BRIGHTNESS_METHOD_LEVEL = 1,
WMI_BRIGHTNESS_METHOD_SOURCE = 2,
WMI_BRIGHTNESS_METHOD_MAX
};
/**
* enum wmi_brightness_mode - Operation mode for WMI-wrapped method
* @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source.
* @WMI_BRIGHTNESS_MODE_SET: Set the brightness level.
* @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This
* is only valid when the WMI method is
* %WMI_BRIGHTNESS_METHOD_LEVEL.
*/
enum wmi_brightness_mode {
WMI_BRIGHTNESS_MODE_GET = 0,
WMI_BRIGHTNESS_MODE_SET = 1,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
WMI_BRIGHTNESS_MODE_MAX
};
/**
* enum wmi_brightness_source - Backlight brightness control source selection
* @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU.
* @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the
* system's Embedded Controller (EC).
* @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the
* DisplayPort AUX channel.
*/
enum wmi_brightness_source {
WMI_BRIGHTNESS_SOURCE_GPU = 1,
WMI_BRIGHTNESS_SOURCE_EC = 2,
WMI_BRIGHTNESS_SOURCE_AUX = 3,
WMI_BRIGHTNESS_SOURCE_MAX
};
/**
* struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method
* @mode: Pass in an &enum wmi_brightness_mode value to select between
* getting or setting a value.
* @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET
* mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or
* %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode.
* @ret: Out parameter returning retrieved value when operating in
* %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
* mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode.
* @ignored: Padding; not used. The ACPI method expects a 24 byte params struct.
*
* This is the parameters structure for the WmiBrightnessNotify ACPI method as
* wrapped by WMI. The value passed in to @val or returned by @ret will be a
* brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or
* an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE.
*/
struct wmi_brightness_args {
u32 mode;
u32 val;
u32 ret;
u32 ignored[3];
};
#include <acpi/video.h>
/**
* wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
......@@ -151,19 +88,10 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
{
struct backlight_properties props = {};
struct backlight_device *bdev;
u32 source;
int ret;
ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE,
WMI_BRIGHTNESS_MODE_GET, &source);
if (ret)
return ret;
/*
* This driver is only to be used when brightness control is handled
* by the EC; otherwise, the GPU driver(s) should control brightness.
*/
if (source != WMI_BRIGHTNESS_SOURCE_EC)
/* drivers/acpi/video_detect.c also checks that SOURCE == EC */
if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
return -ENODEV;
/*
......@@ -191,8 +119,6 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
return PTR_ERR_OR_ZERO(bdev);
}
#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = {
{ .guid_string = WMI_BRIGHTNESS_GUID },
{ }
......
......@@ -356,23 +356,13 @@ struct samsung_laptop {
};
struct samsung_quirks {
bool broken_acpi_video;
bool four_kbd_backlight_levels;
bool enable_kbd_backlight;
bool use_native_backlight;
bool lid_handling;
};
static struct samsung_quirks samsung_unknown = {};
static struct samsung_quirks samsung_broken_acpi_video = {
.broken_acpi_video = true,
};
static struct samsung_quirks samsung_use_native_backlight = {
.use_native_backlight = true,
};
static struct samsung_quirks samsung_np740u3e = {
.four_kbd_backlight_levels = true,
.enable_kbd_backlight = true,
......@@ -1540,76 +1530,6 @@ static const struct dmi_system_id samsung_dmi_table[] __initconst = {
},
},
/* Specific DMI ids for laptop with quirks */
{
.callback = samsung_dmi_matched,
.ident = "N150P",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
DMI_MATCH(DMI_BOARD_NAME, "N150P"),
},
.driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
.ident = "N145P/N250P/N260P",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
},
.driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
.ident = "N150/N210/N220",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
},
.driver_data = &samsung_broken_acpi_video,
},
{
.callback = samsung_dmi_matched,
.ident = "NF110/NF210/NF310",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
},
.driver_data = &samsung_broken_acpi_video,
},
{
.callback = samsung_dmi_matched,
.ident = "X360",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
DMI_MATCH(DMI_BOARD_NAME, "X360"),
},
.driver_data = &samsung_broken_acpi_video,
},
{
.callback = samsung_dmi_matched,
.ident = "N250P",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
DMI_MATCH(DMI_BOARD_NAME, "N250P"),
},
.driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
.ident = "NC210",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
},
.driver_data = &samsung_broken_acpi_video,
},
{
.callback = samsung_dmi_matched,
.ident = "730U3E/740U3E",
......@@ -1654,15 +1574,8 @@ static int __init samsung_init(void)
samsung->handle_backlight = true;
samsung->quirks = quirks;
#ifdef CONFIG_ACPI
if (samsung->quirks->broken_acpi_video)
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
if (samsung->quirks->use_native_backlight)
acpi_video_set_dmi_backlight_type(acpi_backlight_native);
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
samsung->handle_backlight = false;
#endif
ret = samsung_platform_init(samsung);
if (ret)
......
......@@ -271,14 +271,6 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_END, 0 },
};
/*
* List of models which have a broken acpi-video backlight interface and thus
* need to use the toshiba (vendor) interface instead.
*/
static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = {
{}
};
/*
* Utility
*/
......@@ -2881,14 +2873,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
return 0;
}
/*
* Tell acpi-video-detect code to prefer vendor backlight on all
* systems with transflective backlight and on dmi matched systems.
*/
if (dev->tr_backlight_supported ||
dmi_check_system(toshiba_vendor_backlight_dmi))
acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
return 0;
......
......@@ -48,15 +48,18 @@ enum acpi_backlight_type {
acpi_backlight_video,
acpi_backlight_vendor,
acpi_backlight_native,
acpi_backlight_nvidia_wmi_ec,
acpi_backlight_apple_gmux,
};
#if IS_ENABLED(CONFIG_ACPI_VIDEO)
extern int acpi_video_register(void);
extern void acpi_video_unregister(void);
extern void acpi_video_register_backlight(void);
extern int acpi_video_get_edid(struct acpi_device *device, int type,
int device_id, void **edid);
extern enum acpi_backlight_type acpi_video_get_backlight_type(void);
extern void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type);
extern bool acpi_video_backlight_use_native(void);
/*
* Note: The value returned by acpi_video_handles_brightness_key_presses()
* may change over time and should not be cached.
......@@ -68,6 +71,7 @@ extern int acpi_video_get_levels(struct acpi_device *device,
#else
static inline int acpi_video_register(void) { return -ENODEV; }
static inline void acpi_video_unregister(void) { return; }
static inline void acpi_video_register_backlight(void) { return; }
static inline int acpi_video_get_edid(struct acpi_device *device, int type,
int device_id, void **edid)
{
......@@ -77,8 +81,9 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
{
return acpi_backlight_vendor;
}
static inline void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
static inline bool acpi_video_backlight_use_native(void)
{
return true;
}
static inline bool acpi_video_handles_brightness_key_presses(void)
{
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*/
#ifndef __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H
#define __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H
#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
/**
* enum wmi_brightness_method - WMI method IDs
* @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status
* @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source
*/
enum wmi_brightness_method {
WMI_BRIGHTNESS_METHOD_LEVEL = 1,
WMI_BRIGHTNESS_METHOD_SOURCE = 2,
WMI_BRIGHTNESS_METHOD_MAX
};
/**
* enum wmi_brightness_mode - Operation mode for WMI-wrapped method
* @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source.
* @WMI_BRIGHTNESS_MODE_SET: Set the brightness level.
* @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This
* is only valid when the WMI method is
* %WMI_BRIGHTNESS_METHOD_LEVEL.
*/
enum wmi_brightness_mode {
WMI_BRIGHTNESS_MODE_GET = 0,
WMI_BRIGHTNESS_MODE_SET = 1,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
WMI_BRIGHTNESS_MODE_MAX
};
/**
* enum wmi_brightness_source - Backlight brightness control source selection
* @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU.
* @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the
* system's Embedded Controller (EC).
* @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the
* DisplayPort AUX channel.
*/
enum wmi_brightness_source {
WMI_BRIGHTNESS_SOURCE_GPU = 1,
WMI_BRIGHTNESS_SOURCE_EC = 2,
WMI_BRIGHTNESS_SOURCE_AUX = 3,
WMI_BRIGHTNESS_SOURCE_MAX
};
/**
* struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method
* @mode: Pass in an &enum wmi_brightness_mode value to select between
* getting or setting a value.
* @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET
* mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or
* %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode.
* @ret: Out parameter returning retrieved value when operating in
* %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
* mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode.
* @ignored: Padding; not used. The ACPI method expects a 24 byte params struct.
*
* This is the parameters structure for the WmiBrightnessNotify ACPI method as
* wrapped by WMI. The value passed in to @val or returned by @ret will be a
* brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or
* an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE.
*/
struct wmi_brightness_args {
u32 mode;
u32 val;
u32 ret;
u32 ignored[3];
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment