1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/array_size.h> 4 #include <linux/dmi.h> 5 #include <linux/export.h> 6 #include <linux/module.h> 7 #include <drm/drm_edid.h> 8 #include <drm/drm_utils.h> 9 10 struct drm_panel_match { 11 enum dmi_field field; 12 const char * const value; 13 }; 14 15 struct drm_get_panel_backlight_quirk { 16 struct drm_panel_match dmi_match; 17 struct drm_panel_match dmi_match_other; 18 struct drm_edid_ident ident; 19 struct drm_panel_backlight_quirk quirk; 20 }; 21 22 static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = { 23 /* 13 inch matte panel */ 24 { 25 .dmi_match.field = DMI_BOARD_VENDOR, 26 .dmi_match.value = "Framework", 27 .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0bca), 28 .ident.name = "NE135FBM-N41", 29 .quirk = { .min_brightness = 1, }, 30 }, 31 /* 13 inch glossy panel */ 32 { 33 .dmi_match.field = DMI_BOARD_VENDOR, 34 .dmi_match.value = "Framework", 35 .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x095f), 36 .ident.name = "NE135FBM-N41", 37 .quirk = { .min_brightness = 1, }, 38 }, 39 /* 13 inch 2.8k panel */ 40 { 41 .dmi_match.field = DMI_BOARD_VENDOR, 42 .dmi_match.value = "Framework", 43 .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x0cb4), 44 .ident.name = "NE135A1M-NY1", 45 .quirk = { .min_brightness = 1, }, 46 }, 47 /* Steam Deck models */ 48 { 49 .dmi_match.field = DMI_SYS_VENDOR, 50 .dmi_match.value = "Valve", 51 .dmi_match_other.field = DMI_PRODUCT_NAME, 52 .dmi_match_other.value = "Jupiter", 53 .quirk = { .min_brightness = 1, }, 54 }, 55 { 56 .dmi_match.field = DMI_SYS_VENDOR, 57 .dmi_match.value = "Valve", 58 .dmi_match_other.field = DMI_PRODUCT_NAME, 59 .dmi_match_other.value = "Galileo", 60 .quirk = { .min_brightness = 1, }, 61 }, 62 /* Have OLED Panels with brightness issue when last byte is 0/1 */ 63 { 64 .dmi_match.field = DMI_SYS_VENDOR, 65 .dmi_match.value = "AYANEO", 66 .dmi_match_other.field = DMI_PRODUCT_NAME, 67 .dmi_match_other.value = "AYANEO 3", 68 .quirk = { .brightness_mask = 3, }, 69 }, 70 { 71 .dmi_match.field = DMI_SYS_VENDOR, 72 .dmi_match.value = "ZOTAC", 73 .dmi_match_other.field = DMI_BOARD_NAME, 74 .dmi_match_other.value = "G0A1W", 75 .quirk = { .brightness_mask = 3, }, 76 }, 77 { 78 .dmi_match.field = DMI_SYS_VENDOR, 79 .dmi_match.value = "ZOTAC", 80 .dmi_match_other.field = DMI_BOARD_NAME, 81 .dmi_match_other.value = "G1A1W", 82 .quirk = { .brightness_mask = 3, }, 83 }, 84 { 85 .dmi_match.field = DMI_SYS_VENDOR, 86 .dmi_match.value = "ONE-NETBOOK", 87 .dmi_match_other.field = DMI_PRODUCT_NAME, 88 .dmi_match_other.value = "ONEXPLAYER F1Pro", 89 .quirk = { .brightness_mask = 3, }, 90 }, 91 { 92 .dmi_match.field = DMI_SYS_VENDOR, 93 .dmi_match.value = "ONE-NETBOOK", 94 .dmi_match_other.field = DMI_PRODUCT_NAME, 95 .dmi_match_other.value = "ONEXPLAYER F1 EVA-02", 96 .quirk = { .brightness_mask = 3, }, 97 }, 98 }; 99 100 static bool drm_panel_min_backlight_quirk_matches( 101 const struct drm_get_panel_backlight_quirk *quirk, 102 const struct drm_edid *edid) 103 { 104 if (quirk->dmi_match.field && 105 !dmi_match(quirk->dmi_match.field, quirk->dmi_match.value)) 106 return false; 107 108 if (quirk->dmi_match_other.field && 109 !dmi_match(quirk->dmi_match_other.field, 110 quirk->dmi_match_other.value)) 111 return false; 112 113 if (quirk->ident.panel_id && !drm_edid_match(edid, &quirk->ident)) 114 return false; 115 116 return true; 117 } 118 119 /** 120 * drm_get_panel_backlight_quirk - Get backlight quirks for a panel 121 * @edid: EDID of the panel to check 122 * 123 * This function checks for platform specific (e.g. DMI based) quirks 124 * providing info on the minimum backlight brightness for systems where this 125 * cannot be probed correctly from the hard-/firm-ware and other sources. 126 * 127 * Returns: 128 * a drm_panel_backlight_quirk struct if a quirk was found, otherwise an 129 * error pointer. 130 */ 131 const struct drm_panel_backlight_quirk * 132 drm_get_panel_backlight_quirk(const struct drm_edid *edid) 133 { 134 const struct drm_get_panel_backlight_quirk *quirk; 135 size_t i; 136 137 if (!IS_ENABLED(CONFIG_DMI)) 138 return ERR_PTR(-ENODATA); 139 140 if (!edid) 141 return ERR_PTR(-EINVAL); 142 143 for (i = 0; i < ARRAY_SIZE(drm_panel_min_backlight_quirks); i++) { 144 quirk = &drm_panel_min_backlight_quirks[i]; 145 146 if (drm_panel_min_backlight_quirk_matches(quirk, edid)) 147 return &quirk->quirk; 148 } 149 150 return ERR_PTR(-ENODATA); 151 } 152 EXPORT_SYMBOL(drm_get_panel_backlight_quirk); 153 154 MODULE_DESCRIPTION("Quirks for panel backlight overrides"); 155 MODULE_LICENSE("GPL"); 156