drm_panel_backlight_quirks.c 4.3 KB

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