Skip to content

Commit a056281

Browse files
committed
drm/i915: Get panel_type from OpRegion panel details
We've had problems on several occasions with using the panel type from the VBT block 40. Usually it seems to be 2, which often doesn't give us the correct timings for the panel. After some more digging I found a way to get a panel type via the OpRegion SWSCI GBDA "Get Panel Details" method. Let's try to use it. The spec has this to say about the output: "Bits [15:8] - Panel Type Bits contain the panel type user setting from CMOS 00h = Not Valid, use default Panel Type & Timings from VBT 01h - 0Fh = Panel Number" Another version of the spec lists the valid range as 1-16, which makes more sense since VBT supports 16 panels. Based on actual results from Rob's G45, 1-16 is what we need to accept. The other bits in the output don't look relevant for the problem at hand. The input is specified as: "Bits [31:4] - Reserved Reserved (must be zero) Bits [3:0] - Panel Number These bits contain the sequential index of Panel, starting at 0 and counting upwards from the first integrated Internal Flat-Panel Display Encoder present, and then from the first external Display Encoder (e.g., S/DVO-B then S/DVO-C) which supports Internal Flat-Panels. 0h - 0Fh = Panel number" For now I've just hardcoded the input panel number as 0. That would seem like a decent choise for LVDS. Not so sure about eDP when port != A. v2: Accept values 1-16 Filter out bogus results in opregion code (Jani) Add debug logging for all the different branches (Jani) Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Rob Kramer <rob@solution-space.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94825 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1460359431-11003-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> Tested-by: Rob Kramer <rob@solution-space.com>
1 parent 3e845c7 commit a056281

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3457,6 +3457,7 @@ extern int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
34573457
bool enable);
34583458
extern int intel_opregion_notify_adapter(struct drm_device *dev,
34593459
pci_power_t state);
3460+
extern int intel_opregion_get_panel_type(struct drm_device *dev);
34603461
#else
34613462
static inline int intel_opregion_setup(struct drm_device *dev) { return 0; }
34623463
static inline void intel_opregion_init(struct drm_device *dev) { return; }
@@ -3472,6 +3473,10 @@ intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
34723473
{
34733474
return 0;
34743475
}
3476+
static inline int intel_opregion_get_panel_type(struct drm_device *dev)
3477+
{
3478+
return -ENODEV;
3479+
}
34753480
#endif
34763481

34773482
/* intel_acpi.c */

drivers/gpu/drm/i915/intel_bios.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,29 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
205205
struct drm_display_mode *panel_fixed_mode;
206206
int panel_type;
207207
int drrs_mode;
208+
int ret;
208209

209210
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
210211
if (!lvds_options)
211212
return;
212213

213214
dev_priv->vbt.lvds_dither = lvds_options->pixel_dither;
214-
if (lvds_options->panel_type > 0xf) {
215-
DRM_DEBUG_KMS("Invalid VBT panel type 0x%x\n",
216-
lvds_options->panel_type);
217-
return;
215+
216+
ret = intel_opregion_get_panel_type(dev_priv->dev);
217+
if (ret >= 0) {
218+
WARN_ON(ret > 0xf);
219+
panel_type = ret;
220+
DRM_DEBUG_KMS("Panel type: %d (OpRegion)\n", panel_type);
221+
} else {
222+
if (lvds_options->panel_type > 0xf) {
223+
DRM_DEBUG_KMS("Invalid VBT panel type 0x%x\n",
224+
lvds_options->panel_type);
225+
return;
226+
}
227+
panel_type = lvds_options->panel_type;
228+
DRM_DEBUG_KMS("Panel type: %d (VBT)\n", panel_type);
218229
}
219230

220-
panel_type = lvds_options->panel_type;
221231
dev_priv->vbt.panel_type = panel_type;
222232

223233
drrs_mode = (lvds_options->dps_panel_type_bits

drivers/gpu/drm/i915/intel_opregion.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,3 +1024,31 @@ int intel_opregion_setup(struct drm_device *dev)
10241024
memunmap(base);
10251025
return err;
10261026
}
1027+
1028+
int
1029+
intel_opregion_get_panel_type(struct drm_device *dev)
1030+
{
1031+
u32 panel_details;
1032+
int ret;
1033+
1034+
ret = swsci(dev, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details);
1035+
if (ret) {
1036+
DRM_DEBUG_KMS("Failed to get panel details from OpRegion (%d)\n",
1037+
ret);
1038+
return ret;
1039+
}
1040+
1041+
ret = (panel_details >> 8) & 0xff;
1042+
if (ret > 0x10) {
1043+
DRM_DEBUG_KMS("Invalid OpRegion panel type 0x%x\n", ret);
1044+
return -EINVAL;
1045+
}
1046+
1047+
/* fall back to VBT panel type? */
1048+
if (ret == 0x0) {
1049+
DRM_DEBUG_KMS("No panel type in OpRegion\n");
1050+
return -ENODEV;
1051+
}
1052+
1053+
return ret - 1;
1054+
}

0 commit comments

Comments
 (0)