On Tue, 12 Jan 2016 01:37:39 +0200
Sviatoslav Chagaev <[email protected]> wrote:
> On Sun, 10 Jan 2016 21:28:31 +0100
> Joerg Jung <[email protected]> wrote:
> > On Sun, Jan 10, 2016 at 04:59:22AM +0200, Sviatoslav Chagaev wrote:
> >
> > > An Intel developer claims [2] that it's not a bug in Intel KMS driver and
> > > people
> > > claim [3] the problem goes away when booting in legacy BIOS mode.
> >
> > That makes no sense to me. If the problem goes aways when booting
> > legacy BIOS, so it must be a bug when not, right?
>
> Judging by the code at e.g. sys/dev/pci/drm/i915/intel_panel.c:984, it
> seems Intel KMS driver expects BIOS or EFI to configure backlight,
> then reads these values and uses them itself.
>
> I found documentation for Intel Haswell [1] and glanced over
> descriptions of relevant registers (BLC_PWM_CTL, BLC_PWM2_CTL,
> BLC_PWM_DATA, BLC_MISC_CTL, BLM_HIST_CTL, BLM_HIST_BIN, BLM_HIST_GUARD,
> UTIL_PIN_CTL, SBLC_PWM_CTL1, SBLC_PWM_CTL2), they are confusing...
>
> Based on these, I agree, it might be a bug in Intel KMS.
>
> I'll add debug prints and play with these registers, maybe I'll spot
> some incorrect values.
>
> [1]
> https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-hsw-commandreference-registers_0_0.pdf
>
Had no luck with Intel KMS:
Added register dump to every backlight operation, see first diff.
State of registers I get from EFI:
pch_dump_backlight_registers(): pch_setup_backlight
MY_BLC_PWM_CTL = 0x00000000; MY_BLC_PWM_DATA = 0x00000000
MY_BLC_PWM_DATA2 = 0x00000000; MY_BLM_HIST_CTL = 0x00000000
MY_BLM_HIST_BIN = 0x00000000; MY_BLM_HIST_GUARD = 0x00000000
MY_BLC_PWM2_CTL = 0x60000000; MY_BLC_MISC_CTL = 0x00000000
MY_UTIL_PIN_CTL = 0x00000000; MY_SBLC_PWM_CTL1 = 0xc0000000
MY_SBLC_PWM_CTL2 = 0x0ad901c3;
State of registers after Intel KMS configures them:
pch_dump_backlight_registers(): pch_set_backlight
MY_BLC_PWM_CTL = 0xe0000000; MY_BLC_PWM_DATA = 0x00000ad9
MY_BLC_PWM_DATA2 = 0x00000000; MY_BLM_HIST_CTL = 0x00000006
MY_BLM_HIST_BIN = 0x00000000; MY_BLM_HIST_GUARD = 0x00000000
MY_BLC_PWM2_CTL = 0x60000000; MY_BLC_MISC_CTL = 0x00000000
MY_UTIL_PIN_CTL = 0x00000000; MY_SBLC_PWM_CTL1 = 0x80000000
MY_SBLC_PWM_CTL2 = 0x0ad90000;
BLC_PWM_CTL change seems strange.
Modified pch_*_backlight() functions so they do not change the
configuration set by EFI, see second diff, but observed no change in
behaviour.
Index: sys/dev/pci/drm/i915/i915_reg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_reg.h,v
retrieving revision 1.11
diff -u -p -r1.11 i915_reg.h
--- sys/dev/pci/drm/i915/i915_reg.h 25 Sep 2015 16:15:19 -0000 1.11
+++ sys/dev/pci/drm/i915/i915_reg.h 12 Jan 2016 02:54:49 -0000
@@ -2493,6 +2493,18 @@
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */
+#define MY_BLC_PWM_CTL 0x48250
+#define MY_BLC_PWM_DATA 0x48254
+#define MY_BLC_PWM_DATA2 0x48354
+#define MY_BLM_HIST_CTL 0x48260
+#define MY_BLM_HIST_BIN 0x48264
+#define MY_BLM_HIST_GUARD 0x48268
+#define MY_BLC_PWM2_CTL 0x48350
+#define MY_BLC_MISC_CTL 0x48360
+#define MY_UTIL_PIN_CTL 0x48400
+#define MY_SBLC_PWM_CTL1 0xc8250
+#define MY_SBLC_PWM_CTL2 0xc8254
+
#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260)
/* New registers for PCH-split platforms. Safe where new bits show up, the
Index: sys/dev/pci/drm/i915/intel_panel.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/intel_panel.c,v
retrieving revision 1.11
diff -u -p -r1.11 intel_panel.c
--- sys/dev/pci/drm/i915/intel_panel.c 23 Sep 2015 23:12:12 -0000 1.11
+++ sys/dev/pci/drm/i915/intel_panel.c 12 Jan 2016 02:54:49 -0000
@@ -36,6 +36,38 @@
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+void pch_dump_backlight_registers(struct intel_connector *connector, const
char *msg)
+{
+ struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 i = 0;
+ u32 value;
+
+ printf("%s(): %s\n", __func__, msg);
+
+#define Y(register) \
+ value = I915_READ(register); \
+ printf("%-17s = 0x%08x%s", \
+ #register, value, (i++ & 1) ? "\n" : "; ");
+
+ Y(MY_BLC_PWM_CTL);
+ Y(MY_BLC_PWM_DATA);
+ Y(MY_BLC_PWM_DATA2);
+ Y(MY_BLM_HIST_CTL);
+ Y(MY_BLM_HIST_BIN);
+ Y(MY_BLM_HIST_GUARD);
+ Y(MY_BLC_PWM2_CTL);
+ Y(MY_BLC_MISC_CTL);
+ Y(MY_UTIL_PIN_CTL);
+ Y(MY_SBLC_PWM_CTL1);
+ Y(MY_SBLC_PWM_CTL2);
+
+ if (i & 1)
+ printf("\n");
+
+#undef Y
+}
+
void
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode)
@@ -366,6 +398,8 @@ static u32 pch_get_backlight(struct inte
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ pch_dump_backlight_registers(connector, __func__);
+
return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
}
@@ -439,6 +473,8 @@ static void pch_set_backlight(struct int
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
+ pch_dump_backlight_registers(connector, __func__);
+
tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
}
@@ -535,6 +571,8 @@ static void pch_disable_backlight(struct
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
+ pch_dump_backlight_registers(connector, __func__);
+
intel_panel_actually_set_backlight(connector, 0);
tmp = I915_READ(BLC_PWM_CPU_CTL2);
@@ -648,6 +686,8 @@ static void pch_enable_backlight(struct
intel_pipe_to_cpu_transcoder(dev_priv, pipe);
u32 cpu_ctl2, pch_ctl1, pch_ctl2;
+ pch_dump_backlight_registers(connector, __func__);
+
cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
if (cpu_ctl2 & BLM_PWM_ENABLE) {
DRM_DEBUG_KMS("cpu backlight already enabled\n");
@@ -980,6 +1020,8 @@ static int pch_setup_backlight(struct in
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_panel *panel = &connector->panel;
u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
+
+ pch_dump_backlight_registers(connector, __func__);
pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
Index: sys/dev/pci/drm/i915/i915_reg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_reg.h,v
retrieving revision 1.11
diff -u -p -r1.11 i915_reg.h
--- sys/dev/pci/drm/i915/i915_reg.h 25 Sep 2015 16:15:19 -0000 1.11
+++ sys/dev/pci/drm/i915/i915_reg.h 12 Jan 2016 23:07:04 -0000
@@ -2493,6 +2493,18 @@
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */
+#define MY_BLC_PWM_CTL 0x48250
+#define MY_BLC_PWM_DATA 0x48254
+#define MY_BLC_PWM_DATA2 0x48354
+#define MY_BLM_HIST_CTL 0x48260
+#define MY_BLM_HIST_BIN 0x48264
+#define MY_BLM_HIST_GUARD 0x48268
+#define MY_BLC_PWM2_CTL 0x48350
+#define MY_BLC_MISC_CTL 0x48360
+#define MY_UTIL_PIN_CTL 0x48400
+#define MY_SBLC_PWM_CTL1 0xc8250
+#define MY_SBLC_PWM_CTL2 0xc8254
+
#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260)
/* New registers for PCH-split platforms. Safe where new bits show up, the
Index: sys/dev/pci/drm/i915/intel_panel.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/intel_panel.c,v
retrieving revision 1.11
diff -u -p -r1.11 intel_panel.c
--- sys/dev/pci/drm/i915/intel_panel.c 23 Sep 2015 23:12:12 -0000 1.11
+++ sys/dev/pci/drm/i915/intel_panel.c 12 Jan 2016 23:07:05 -0000
@@ -36,6 +36,38 @@
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+void pch_dump_backlight_registers(struct intel_connector *connector, const
char *msg)
+{
+ struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 i = 0;
+ u32 value;
+
+ printf("%s(): %s\n", __func__, msg);
+
+#define Y(register) \
+ value = I915_READ(register); \
+ printf("%-17s = 0x%08x%s", \
+ #register, value, (i++ & 1) ? "\n" : "; ");
+
+ Y(MY_BLC_PWM_CTL);
+ Y(MY_BLC_PWM_DATA);
+ Y(MY_BLC_PWM_DATA2);
+ Y(MY_BLM_HIST_CTL);
+ Y(MY_BLM_HIST_BIN);
+ Y(MY_BLM_HIST_GUARD);
+ Y(MY_BLC_PWM2_CTL);
+ Y(MY_BLC_MISC_CTL);
+ Y(MY_UTIL_PIN_CTL);
+ Y(MY_SBLC_PWM_CTL1);
+ Y(MY_SBLC_PWM_CTL2);
+
+ if (i & 1)
+ printf("\n");
+
+#undef Y
+}
+
void
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode)
@@ -366,7 +398,9 @@ static u32 pch_get_backlight(struct inte
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+ pch_dump_backlight_registers(connector, __func__);
+
+ return I915_READ(MY_SBLC_PWM_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 i9xx_get_backlight(struct intel_connector *connector)
@@ -439,8 +473,10 @@ static void pch_set_backlight(struct int
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
- tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
- I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
+ pch_dump_backlight_registers(connector, __func__);
+
+ tmp = I915_READ(MY_SBLC_PWM_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ I915_WRITE(MY_SBLC_PWM_CTL2, tmp | level);
}
static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
@@ -535,13 +571,10 @@ static void pch_disable_backlight(struct
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
- intel_panel_actually_set_backlight(connector, 0);
-
- tmp = I915_READ(BLC_PWM_CPU_CTL2);
- I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+ pch_dump_backlight_registers(connector, __func__);
- tmp = I915_READ(BLC_PWM_PCH_CTL1);
- I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+ tmp = I915_READ(MY_SBLC_PWM_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ I915_WRITE(MY_SBLC_PWM_CTL2, tmp);
}
static void i9xx_disable_backlight(struct intel_connector *connector)
@@ -642,51 +675,23 @@ static void pch_enable_backlight(struct
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_panel *panel = &connector->panel;
- enum pipe pipe = intel_get_pipe_from_connector(connector);
- enum transcoder cpu_transcoder =
- intel_pipe_to_cpu_transcoder(dev_priv, pipe);
- u32 cpu_ctl2, pch_ctl1, pch_ctl2;
-
- cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
- if (cpu_ctl2 & BLM_PWM_ENABLE) {
- DRM_DEBUG_KMS("cpu backlight already enabled\n");
- cpu_ctl2 &= ~BLM_PWM_ENABLE;
- I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
- }
-
- pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
- if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
- DRM_DEBUG_KMS("pch backlight already enabled\n");
- pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
- I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
- }
+ u32 tmp;
- if (cpu_transcoder == TRANSCODER_EDP)
- cpu_ctl2 = BLM_TRANSCODER_EDP;
- else
- cpu_ctl2 = BLM_PIPE(cpu_transcoder);
- I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
- POSTING_READ(BLC_PWM_CPU_CTL2);
- I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
+ pch_dump_backlight_registers(connector, __func__);
- /* This won't stick until the above enable. */
- intel_panel_actually_set_backlight(connector, panel->backlight.level);
+ if (I915_READ(MY_BLC_PWM_CTL) != 0)
+ I915_WRITE(MY_BLC_PWM_CTL, 0);
- pch_ctl2 = panel->backlight.max << 16;
- I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
-
- /* XXX: transitional */
- if (dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)
- return;
+ if (I915_READ(MY_SBLC_PWM_CTL2) == 0)
+ I915_WRITE(MY_SBLC_PWM_CTL2, 0x0ad90ad9);
- pch_ctl1 = 0;
- if (panel->backlight.active_low_pwm)
- pch_ctl1 |= BLM_PCH_POLARITY;
+ /* SBLC_PWM_CTL1 must be programmed *after* SBLC_PWM_CTL2 */
+ if (I915_READ(MY_SBLC_PWM_CTL1) != 0xc0000000)
+ I915_WRITE(MY_SBLC_PWM_CTL1, 0xc0000000);
- I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
- POSTING_READ(BLC_PWM_PCH_CTL1);
- I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
+ tmp = I915_READ(MY_SBLC_PWM_CTL2);
+ tmp |= tmp >> 16;
+ I915_WRITE(MY_SBLC_PWM_CTL2, tmp);
}
static void i9xx_enable_backlight(struct intel_connector *connector)
@@ -979,22 +984,23 @@ static int pch_setup_backlight(struct in
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_panel *panel = &connector->panel;
- u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
- pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
- panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+ pch_dump_backlight_registers(connector, __func__);
- pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
- panel->backlight.max = pch_ctl2 >> 16;
- if (!panel->backlight.max)
- return -ENODEV;
+ if (I915_READ(MY_BLC_PWM_CTL) != 0)
+ I915_WRITE(MY_BLC_PWM_CTL, 0);
- val = pch_get_backlight(connector);
- panel->backlight.level = intel_panel_compute_brightness(connector, val);
+ if (I915_READ(MY_SBLC_PWM_CTL2) == 0)
+ I915_WRITE(MY_SBLC_PWM_CTL2, 0x0ad90ad9);
- cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
- panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
- (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
+ /* SBLC_PWM_CTL1 must be programmed *after* SBLC_PWM_CTL2 */
+ if (I915_READ(MY_SBLC_PWM_CTL1) != 0xc0000000)
+ I915_WRITE(MY_SBLC_PWM_CTL1, 0xc0000000);
+
+ panel->backlight.active_low_pwm = false;
+ panel->backlight.max = I915_READ(MY_SBLC_PWM_CTL2) >> 16;
+ panel->backlight.level = intel_panel_compute_brightness(connector,
+ I915_READ(MY_SBLC_PWM_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK);
return 0;
}