Bug 55071

Summary: Backlight brightness switching doesn't work on Dell Inspiron 15R SE (7520)
Product: ACPI Reporter: Danny Baumann (dannybaumann)
Component: Power-VideoAssignee: Aaron Lu (aaron.lu)
Status: CLOSED WILL_NOT_FIX    
Severity: normal CC: aaron.lu, pachoramos1
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 3.9-rc2 Subsystem:
Regression: Yes Bisected commit-id:
Attachments: acpidump output
Output of lspci -vv
IGD opregion spec

Description Danny Baumann 2013-03-11 14:45:23 UTC
Created attachment 95161 [details]
acpidump output

Since kernel 3.7 I'm unable to control the brightness of the display backlight on my Dell Inspiron 15R SE (model number 7520) via ACPI methods. Neither using the hotkeys, nor manually writing values into /sys/class/backlight/acpi_video[0,1]/brightness changes the brightness. It works when either writing to intel_backlight/brightness or using kernel 3.6 or (the preinstalled) Windows 8.

The actual commit that broke it was a57f7f9175b8ccbc9df83ac13860488913115de4 (   ACPICA: Add Windows8/Server2012 string for _OSI method). With that commit, _BCL exposes a 102 item list instead of an 18 item one, and _BQC always seems to return the value 100 (which is what breaks the brightness control via hotkey).

I've attached the output of acpidump, which shows the differentiation in behaviour between Windows 8 and !Windows 8 done by the AML code; I don't speak AML fluently enough to interpret what exactly it's doing, though :(
Comment 1 Aaron Lu 2013-03-12 05:24:49 UTC

*** This bug has been marked as a duplicate of bug 51231 ***
Comment 2 Danny Baumann 2013-03-12 08:59:37 UTC
Some more details:

- In Windows 8 mode, _BCL reports 102 levels (100, 30, and 1-100).
- In that mode, I get 2 acpi_video devices instead of previously 1.
- Executing _BCM in either output device succeeds, but doesn't have any visible effect. _BQC always returns '100' afterwards, no matter what value was written via _BCM
Comment 3 Danny Baumann 2013-03-16 12:42:04 UTC
More findings:

_BQC uses the CBLV variable as return value:

                Method (_BQC, 0, NotSerialized)
                {
                    If (LEqual (OSYS, 0x07DC))
                    {
                        Store (And (CBLV, 0xFF), Local0)
                        Return (Local0)
                    }
                    Else
                    [...]

which is updated by the i915 driver after an ASLE interrupt. The AML has a AINT method which updates BCLP and triggers the interrupt, however, it's only called in the !Windows 8 case:

                Method (_BCM, 1, NotSerialized)
                {
                    If (LEqual (OSYS, 0x07DC))
                    {
                        Store (Arg0, ^^^LPCB.EC0.BRTS)
                        Store (Arg0, BRTL)
                    }
                    Else
                    {
                        If (LAnd (LGreaterEqual (Arg0, Zero), LLessEqual (Arg0, 0x64)))
                        {
                            AINT (One, Arg0)
                            Store (Arg0, BRTL)
                        }
                    }
                }

In the Windows 8 case, only the BRTS variable in the EC is written, thus no interrupt, thus no CBLV update, thus _BQC always stays at the same value. Does BRTS have some special meaning that I've missed?
Comment 4 Aaron Lu 2013-03-20 08:56:30 UTC
(In reply to comment #2)
> Some more details:
> 
> - In Windows 8 mode, _BCL reports 102 levels (100, 30, and 1-100).
> - In that mode, I get 2 acpi_video devices instead of previously 1.

You have 2 vga controllers?
lspci please.

> - Executing _BCM in either output device succeeds, but doesn't have any
> visible
> effect. _BQC always returns '100' afterwards, no matter what value was
> written
> via _BCM

What about the values in device LCD's _BCL list, like 10,20,etc.?
Comment 5 Danny Baumann 2013-03-20 09:32:08 UTC
Created attachment 95791 [details]
Output of lspci -vv
Comment 6 Danny Baumann 2013-03-20 09:38:26 UTC
(In reply to comment #4)
> (In reply to comment #2)
> > Some more details:
> > 
> > - In Windows 8 mode, _BCL reports 102 levels (100, 30, and 1-100).
> > - In that mode, I get 2 acpi_video devices instead of previously 1.
> 
> You have 2 vga controllers?
> lspci please.

Yes, the processor-integrated one (which I'm using) and a Radeon 7730M (which I turned off via vgaswitcheroo). There's no mux involved, though, so only the Intel controller is driving the video outputs. lspci output attached.

> > - Executing _BCM in either output device succeeds, but doesn't have any
> visible
> > effect. _BQC always returns '100' afterwards, no matter what value was
> written
> > via _BCM
> 
> What about the values in device LCD's _BCL list, like 10,20,etc.?

Doesn't help either. The !Windows 8 _BCL table looks like this:

                Name (BFHD, Package (0x12)
                {
                    0x64,
                    0x14,
                    0x0A,
                    0x0F,
                    0x14,
                    0x19,
                    0x1E,
                    0x23,
                    0x28,
                    0x2D,
                    0x32,
                    0x38,
                    0x3F,
                    0x46,
                    0x4D,
                    0x55,
                    0x5C,
                    0x64
                })

I've tried writing the following values:
- 2 (to try one valid index)
- 20 (a value present in _BCL)
- 19 and 21 (to cover off-by-one errors in indexing)
Comment 7 Aaron Lu 2013-03-21 03:38:50 UTC
(In reply to comment #3)
> More findings:
> 
> _BQC uses the CBLV variable as return value:
> 
>                 Method (_BQC, 0, NotSerialized)
>                 {
>                     If (LEqual (OSYS, 0x07DC))
>                     {
>                         Store (And (CBLV, 0xFF), Local0)
>                         Return (Local0)
>                     }
>                     Else
>                     [...]
> 
> which is updated by the i915 driver after an ASLE interrupt. The AML has a
> AINT
> method which updates BCLP and triggers the interrupt, however, it's only
> called
> in the !Windows 8 case:

That's interesting, how did you find this out?

> 
>                 Method (_BCM, 1, NotSerialized)
>                 {
>                     If (LEqual (OSYS, 0x07DC))
>                     {
>                         Store (Arg0, ^^^LPCB.EC0.BRTS)
>                         Store (Arg0, BRTL)
>                     }
>                     Else
>                     {
>                         If (LAnd (LGreaterEqual (Arg0, Zero), LLessEqual
>                         (Arg0,
> 0x64)))
>                         {
>                             AINT (One, Arg0)
>                             Store (Arg0, BRTL)
>                         }
>                     }
>                 }
> 
> In the Windows 8 case, only the BRTS variable in the EC is written, thus no
> interrupt, thus no CBLV update, thus _BQC always stays at the same value.
> Does
> BRTS have some special meaning that I've missed?

Perhaps only EC firmware writer knows that.
I suppose on write to a variable in EC space, the EC firmware will do something accordingly, but I'm not sure.
Comment 8 Danny Baumann 2013-03-21 08:01:31 UTC
(In reply to comment #7)
> (In reply to comment #3)
> > More findings:
> > 
> > _BQC uses the CBLV variable as return value:
> > which is updated by the i915 driver after an ASLE interrupt. The AML has a
> AINT
> > method which updates BCLP and triggers the interrupt, however, it's only
> called
> > in the !Windows 8 case:
> 
> That's interesting, how did you find this out?

By just looking around :) I
- looked at the DSDT and saw it's using CBLV in _BQC
- grepped the kernel source for CBLV
- found drivers/gpu/drm/i915/intel_opregion.c
- checked it, found that the CBLV update (and the actual brightness update, which is done in the same function - asle_set_backlight) is triggered by the ASLE interrupt and the BCLP value
- grepped the DSDT for BCLP, found the AINT method which also sets ASLE
- found that it's only used in the !Windows 8 case

I verified this by adding debug statements in intel_opregion.c, which proved the expectations: In the !Windows 8 case, the ASLE interrupt is fired, CBLV (and the actual backlight brightness) are updated and everything works as intended. In the Windows 8 case, there's no ASLE interrupt, thus no CBLV update (which makes _BQC stuck) and no brightness update.

> > In the Windows 8 case, only the BRTS variable in the EC is written, thus no
> > interrupt, thus no CBLV update, thus _BQC always stays at the same value.
> Does
> > BRTS have some special meaning that I've missed?
> 
> Perhaps only EC firmware writer knows that.
> I suppose on write to a variable in EC space, the EC firmware will do
> something
> accordingly, but I'm not sure.

OK. I was thinking from a spec perspective: Might it be that there's some new mechanism for backlight control introduced with Windows 8 that the kernel just doesn't implement yet?
Comment 9 Danny Baumann 2013-03-21 08:03:52 UTC
BTW, FWIW, here's what dmesg says for the video module initialization in the Windows 8 case:

[    2.860620] [Firmware Bug]: ACPI(PEGP) defines _DOD but not _DOS
[    2.861506] acpi device:2d: registered as cooling_device8
[    2.861646] ACPI: Video Device [PEGP] (multi-head: yes  rom: no  post: no)
[    2.861679] input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:2b/LNXVIDEO:00/input/input5
[    2.861724] [Firmware Bug]: Duplicate ACPI video bus devices for the same VGA controller, please try module parameter "video.allow_duplicates=1"if the current driver doesn't work.
[    2.862467] acpi device:3c: registered as cooling_device9
[    2.862609] ACPI: Video Device [GFX0] (multi-head: yes  rom: no  post: no)
[    2.862633] input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/LNXVIDEO:02/input/input6

Setting video.allow_duplicates=1 gives me a third acpi_video devices:

[    3.033037] [Firmware Bug]: ACPI(PEGP) defines _DOD but not _DOS
[    3.033936] acpi device:2d: registered as cooling_device8
[    3.034076] ACPI: Video Device [PEGP] (multi-head: yes  rom: no  post: no)
[    3.034110] input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:2b/LNXVIDEO:00/input/input5
[    3.034149] [Firmware Bug]: Duplicate ACPI video bus devices for the same VGA controller, please try module parameter "video.allow_duplicates=1"if the current driver doesn't work.
[    3.334109] acpi device:35: registered as cooling_device9
[    3.334186] ACPI: Video Device [VGA] (multi-head: yes  rom: no  post: no)
[    3.334263] input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:2b/LNXVIDEO:01/input/input6
[    3.336576] acpi device:3c: registered as cooling_device10
[    3.336949] ACPI: Video Device [GFX0] (multi-head: yes  rom: no  post: no)
[    3.337024] input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/LNXVIDEO:02/input/input7

I can set values on this device (max_brightness is 9, I can set e.g. 5 and actual_brightness becomes 5, too), but the actual brightness of the backlight doesn't change when doing that.
Comment 10 Aaron Lu 2013-03-22 12:53:39 UTC
(In reply to comment #9)
> BTW, FWIW, here's what dmesg says for the video module initialization in the
> Windows 8 case:
> 
> [    2.860620] [Firmware Bug]: ACPI(PEGP) defines _DOD but not _DOS
> [    2.861506] acpi device:2d: registered as cooling_device8
> [    2.861646] ACPI: Video Device [PEGP] (multi-head: yes  rom: no  post: no)
> [    2.861679] input: Video Bus as
>
> /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:2b/LNXVIDEO:00/input/input5
> [    2.861724] [Firmware Bug]: Duplicate ACPI video bus devices for the same
> VGA controller, please try module parameter "video.allow_duplicates=1"if the
> current driver doesn't work.
> [    2.862467] acpi device:3c: registered as cooling_device9
> [    2.862609] ACPI: Video Device [GFX0] (multi-head: yes  rom: no  post: no)
> [    2.862633] input: Video Bus as
> /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/LNXVIDEO:02/input/input6
> 
> Setting video.allow_duplicates=1 gives me a third acpi_video devices:

The PEGP and VGA device have the same _ADR under the pci bridge named PEG0 in acpi table, don't know what BIOS wants to achieve here.

Also, it's not clear why acpi device node PEGP's existence would be affected by win8 mode.
Comment 11 Aaron Lu 2013-03-22 13:03:42 UTC
(In reply to comment #8)
> (In reply to comment #7)
> > (In reply to comment #3)
> > > More findings:
> > > 
> > > _BQC uses the CBLV variable as return value:
> > > which is updated by the i915 driver after an ASLE interrupt. The AML has
> a AINT
> > > method which updates BCLP and triggers the interrupt, however, it's only
> called
> > > in the !Windows 8 case:
> > 
> > That's interesting, how did you find this out?
> 
> By just looking around :) I
> - looked at the DSDT and saw it's using CBLV in _BQC
> - grepped the kernel source for CBLV
> - found drivers/gpu/drm/i915/intel_opregion.c
> - checked it, found that the CBLV update (and the actual brightness update,
> which is done in the same function - asle_set_backlight) is triggered by the
> ASLE interrupt and the BCLP value
> - grepped the DSDT for BCLP, found the AINT method which also sets ASLE
> - found that it's only used in the !Windows 8 case
> 
> I verified this by adding debug statements in intel_opregion.c, which proved
> the expectations: In the !Windows 8 case, the ASLE interrupt is fired, CBLV
> (and the actual backlight brightness) are updated and everything works as
> intended. In the Windows 8 case, there's no ASLE interrupt, thus no CBLV
> update
> (which makes _BQC stuck) and no brightness update.

Interesting finding, thanks for sharing. I suppose the intel IGD operation region spec can help here, but I'm not able to find it yet, though it should be publicly available.

So the problem with acpi video driver is, it neither can set backlight level, nor can report backlight level in win8 mode. I hope you can find out the problem if you have the time, since you have the knowledge and access to the system, and I will help you any way I can.

Looks like, most of the time, gpu driver's interface is more reliable than acpi's, and I'm thinking of some way to prefer gpu's interface, and have acpi video driver only handle hotkey notification.

> 
> > > In the Windows 8 case, only the BRTS variable in the EC is written, thus
> no
> > > interrupt, thus no CBLV update, thus _BQC always stays at the same value.
> Does
> > > BRTS have some special meaning that I've missed?
> > 
> > Perhaps only EC firmware writer knows that.
> > I suppose on write to a variable in EC space, the EC firmware will do
> something
> > accordingly, but I'm not sure.
> 
> OK. I was thinking from a spec perspective: Might it be that there's some new
> mechanism for backlight control introduced with Windows 8 that the kernel
> just
> doesn't implement yet?

I have no idea about this, sorry.
Comment 12 Danny Baumann 2013-03-22 13:22:30 UTC
Created attachment 95961 [details]
IGD opregion spec
Comment 13 Danny Baumann 2013-03-22 13:25:24 UTC
(In reply to comment #11)
> Interesting finding, thanks for sharing. I suppose the intel IGD operation
> region spec can help here, but I'm not able to find it yet, though it should
> be
> publicly available.

I've - after some heavy googling - found it ;) I've attached it.

> So the problem with acpi video driver is, it neither can set backlight level,
> nor can report backlight level in win8 mode. I hope you can find out the
> problem if you have the time, since you have the knowledge and access to the
> system, and I will help you any way I can.

Maybe it doesn't look like it, but I actually lack the knowledge :-(
I actually have no idea what the correct way to fix this problem is.

> Looks like, most of the time, gpu driver's interface is more reliable than
> acpi's, and I'm thinking of some way to prefer gpu's interface, and have acpi
> video driver only handle hotkey notification.

Yeah, maybe that's the solution. I guess exactly that is what's happening under Windows.
Comment 14 Aaron Lu 2013-04-07 08:57:51 UTC
(In reply to comment #2)
> Some more details:
> 
> - In Windows 8 mode, _BCL reports 102 levels (100, 30, and 1-100).
> - In that mode, I get 2 acpi_video devices instead of previously 1.
> - Executing _BCM in either output device succeeds, but doesn't have any
> visible
> effect. _BQC always returns '100' afterwards, no matter what value was
> written
> via _BCM

It looks like to me, Dell will provide some kind of platform driver, which will respond to EC memory space on write. And in win8 mode, _BCM will write the brightness level to BRTS which is in EC space; and since we don't have any special EC driver, that doesn't do anything; and in non-win8 mode, _BCM uses AINT, which uses the intel op-region method to update brightness level and worked.

When you boot into win8, is there any EC driver listed in the device manager?
Comment 15 Aaron Lu 2013-04-07 08:59:54 UTC
I think we can easily work around the _BQC problem(like the new quirk code here: http://marc.info/?l=linux-acpi&m=136529970126903&w=2), but for _BCM, it doesn't seem to be easy :-(
Comment 16 Danny Baumann 2013-04-07 09:40:27 UTC
No, there's doesn't seem to be a EC driver installed. Device PNP0C09 ("Microsoft ACPI-Compliant Embedded Controller") is listed in the device manager with a driver created by Microsoft (driver date 6/21/06, version 6.2.9200.16384), but it looks like it's an INF 'driver' only, no .sys files involved.
Comment 17 Aaron Lu 2013-04-07 11:43:38 UTC
Then my guess is, Dell do not want to support acpi interface for backlight control, they can do this by not doing anything in the EC firmware.
Comment 18 Aaron Lu 2013-04-09 05:22:38 UTC
Hi Danny,

I don't see anything we can do here to make _BCM work in win8 mode, so I'll close it as WILL_NOT_FIX, you will need the acpi_osi="!Windows 2012" kernel command line to work around this problem.
Comment 19 Aaron Lu 2013-04-19 03:03:45 UTC
I came across a document on win8 brightness control, it has words like this:

"
In Windows 8, the primary mechanism by which a platform should expose
its display brightness control functionality is the Windows Display Driver
Model (WDDM) miniport Device Driver Interfaces (DDI).
"

So I think for win8 systems, they may not export correct _BCM/_BQC implementations since win8 does not need it.

The document is here, in case you want to take a look:
http://msdn.microsoft.com/en-US/library/windows/hardware/jj159305