122e5c7aeSThomas Weißschuh // SPDX-License-Identifier: GPL-2.0
222e5c7aeSThomas Weißschuh
322e5c7aeSThomas Weißschuh #include <linux/array_size.h>
422e5c7aeSThomas Weißschuh #include <linux/dmi.h>
522e5c7aeSThomas Weißschuh #include <linux/mod_devicetable.h>
622e5c7aeSThomas Weißschuh #include <linux/module.h>
722e5c7aeSThomas Weißschuh #include <drm/drm_edid.h>
822e5c7aeSThomas Weißschuh #include <drm/drm_utils.h>
922e5c7aeSThomas Weißschuh
1022e5c7aeSThomas Weißschuh struct drm_panel_min_backlight_quirk {
1122e5c7aeSThomas Weißschuh struct {
1222e5c7aeSThomas Weißschuh enum dmi_field field;
1322e5c7aeSThomas Weißschuh const char * const value;
1422e5c7aeSThomas Weißschuh } dmi_match;
1522e5c7aeSThomas Weißschuh struct drm_edid_ident ident;
1622e5c7aeSThomas Weißschuh u8 min_brightness;
1722e5c7aeSThomas Weißschuh };
1822e5c7aeSThomas Weißschuh
1922e5c7aeSThomas Weißschuh static const struct drm_panel_min_backlight_quirk drm_panel_min_backlight_quirks[] = {
20916ecc0dSThomas Weißschuh /* 13 inch matte panel */
21916ecc0dSThomas Weißschuh {
22916ecc0dSThomas Weißschuh .dmi_match.field = DMI_BOARD_VENDOR,
23916ecc0dSThomas Weißschuh .dmi_match.value = "Framework",
24916ecc0dSThomas Weißschuh .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0bca),
25916ecc0dSThomas Weißschuh .ident.name = "NE135FBM-N41",
26916ecc0dSThomas Weißschuh .min_brightness = 0,
27916ecc0dSThomas Weißschuh },
28*d80b5c5bSDustin L. Howett /* 13 inch glossy panel */
29*d80b5c5bSDustin L. Howett {
30*d80b5c5bSDustin L. Howett .dmi_match.field = DMI_BOARD_VENDOR,
31*d80b5c5bSDustin L. Howett .dmi_match.value = "Framework",
32*d80b5c5bSDustin L. Howett .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x095f),
33*d80b5c5bSDustin L. Howett .ident.name = "NE135FBM-N41",
34*d80b5c5bSDustin L. Howett .min_brightness = 0,
35*d80b5c5bSDustin L. Howett },
36*d80b5c5bSDustin L. Howett /* 13 inch 2.8k panel */
37*d80b5c5bSDustin L. Howett {
38*d80b5c5bSDustin L. Howett .dmi_match.field = DMI_BOARD_VENDOR,
39*d80b5c5bSDustin L. Howett .dmi_match.value = "Framework",
40*d80b5c5bSDustin L. Howett .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0cb4),
41*d80b5c5bSDustin L. Howett .ident.name = "NE135A1M-NY1",
42*d80b5c5bSDustin L. Howett .min_brightness = 0,
43*d80b5c5bSDustin L. Howett },
4422e5c7aeSThomas Weißschuh };
4522e5c7aeSThomas Weißschuh
drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk * quirk,const struct drm_edid * edid)4622e5c7aeSThomas Weißschuh static bool drm_panel_min_backlight_quirk_matches(const struct drm_panel_min_backlight_quirk *quirk,
4722e5c7aeSThomas Weißschuh const struct drm_edid *edid)
4822e5c7aeSThomas Weißschuh {
4922e5c7aeSThomas Weißschuh if (!dmi_match(quirk->dmi_match.field, quirk->dmi_match.value))
5022e5c7aeSThomas Weißschuh return false;
5122e5c7aeSThomas Weißschuh
5222e5c7aeSThomas Weißschuh if (!drm_edid_match(edid, &quirk->ident))
5322e5c7aeSThomas Weißschuh return false;
5422e5c7aeSThomas Weißschuh
5522e5c7aeSThomas Weißschuh return true;
5622e5c7aeSThomas Weißschuh }
5722e5c7aeSThomas Weißschuh
5822e5c7aeSThomas Weißschuh /**
5922e5c7aeSThomas Weißschuh * drm_get_panel_min_brightness_quirk - Get minimum supported brightness level for a panel.
6022e5c7aeSThomas Weißschuh * @edid: EDID of the panel to check
6122e5c7aeSThomas Weißschuh *
6222e5c7aeSThomas Weißschuh * This function checks for platform specific (e.g. DMI based) quirks
6322e5c7aeSThomas Weißschuh * providing info on the minimum backlight brightness for systems where this
6422e5c7aeSThomas Weißschuh * cannot be probed correctly from the hard-/firm-ware.
6522e5c7aeSThomas Weißschuh *
6622e5c7aeSThomas Weißschuh * Returns:
6722e5c7aeSThomas Weißschuh * A negative error value or
6822e5c7aeSThomas Weißschuh * an override value in the range [0, 255] representing 0-100% to be scaled to
6922e5c7aeSThomas Weißschuh * the drivers target range.
7022e5c7aeSThomas Weißschuh */
drm_get_panel_min_brightness_quirk(const struct drm_edid * edid)7122e5c7aeSThomas Weißschuh int drm_get_panel_min_brightness_quirk(const struct drm_edid *edid)
7222e5c7aeSThomas Weißschuh {
7322e5c7aeSThomas Weißschuh const struct drm_panel_min_backlight_quirk *quirk;
7422e5c7aeSThomas Weißschuh size_t i;
7522e5c7aeSThomas Weißschuh
7622e5c7aeSThomas Weißschuh if (!IS_ENABLED(CONFIG_DMI))
7722e5c7aeSThomas Weißschuh return -ENODATA;
7822e5c7aeSThomas Weißschuh
7922e5c7aeSThomas Weißschuh if (!edid)
8022e5c7aeSThomas Weißschuh return -EINVAL;
8122e5c7aeSThomas Weißschuh
8222e5c7aeSThomas Weißschuh for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) {
8322e5c7aeSThomas Weißschuh quirk = &drm_panel_min_backlight_quirks[i];
8422e5c7aeSThomas Weißschuh
8522e5c7aeSThomas Weißschuh if (drm_panel_min_backlight_quirk_matches(quirk, edid))
8622e5c7aeSThomas Weißschuh return quirk->min_brightness;
8722e5c7aeSThomas Weißschuh }
8822e5c7aeSThomas Weißschuh
8922e5c7aeSThomas Weißschuh return -ENODATA;
9022e5c7aeSThomas Weißschuh }
9122e5c7aeSThomas Weißschuh EXPORT_SYMBOL(drm_get_panel_min_brightness_quirk);
9222e5c7aeSThomas Weißschuh
9322e5c7aeSThomas Weißschuh MODULE_DESCRIPTION("Quirks for panel backlight overrides");
9422e5c7aeSThomas Weißschuh MODULE_LICENSE("GPL");
95