Contribute
Register

[BUG] Black screen 3 minutes after booting, CoffeeLake UHD 630

Okay after hours of messing around I managed to get IntelBacklight.kext to dump some registers. It will still freeze my machine if I try to dump them all so I am only dumping select registers at the moment (starting with backlight).

One thing I found interesting is my bklt entry in AppleBacklightDisplay max is 0xFFFF although my value only seems to go up to 0xFF3E.

So first dump was during the black screen:
Code:
LEV2.....................................: 0x80000000
LEVL.....................................: 0x0
P0BL.....................................: 0x1BEF
GRAN.....................................: 0xF00
LEVW.....................................: 0x80000000
LEVX.....................................: 0x56CE
LEVD.....................................: 0x568C
PCHL.....................................: 0x0
Second dump was after the screen came on (approx. 3 minutes later):
Code:
LEV2.....................................: 0x80000000
LEVL.....................................: 0x0
P0BL.....................................: 0x315E
GRAN.....................................: 0xF00
LEVW.....................................: 0x80000000
LEVX.....................................: 0x56CE
LEVD.....................................: 0x568C
PCHL.....................................: 0x0
Only register that appears to change is P0BL (not sure what that is?).

Also do you notice the frequency 0x56CE? That's one of the values I found in the CFL kext (along with 0x4571). So let's try the formula I found:
Code:
0xFF3E * 0x56CE / 0xFFFF = 0x568C
So it appears to be correct.

Unfortunately when I try this in Clover I still get a black screen:
Code:
LEVX = 0xFF3E;
UINT32 LEVF = 0x56CE; // 0x4571
LEVD = LEVX * FREQ / 0xFFFF;
LEVW = 0xC0000000;
MsgLog ("  LEVX = 0x%x LEVD = 0x%x LEVF = 0x%x LEVW = 0x%x\n", LEVX, LEVD, LEVF, OSXLEVW);

PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, 0, 0xC8254, 1, &LEVF);
PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, 0, 0xC8258, 1, &LEVD);
PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, 0, 0xC8250, 1, &LEVW);

I have a log from Clover showing the register values before I set them:
Code:
3:973  0:000    LEV2 = 0x80000000, LEVL = 0x0, P0BL = 0x37A, GRAN = 0xF00
3:973  0:000    LEVW = 0x80000000, LEVX = 0x1D4C0, LEVD = 0x1D4C0, PCHL = 0x0

So making some progress I guess?
 
Last edited:
One thing I found interesting is my bklt entry in AppleBacklightDisplay max is 0xFFFF although my value only seems to go up to 0xFF3E.

It is what Apple typically does... For example, Sandy Bridge LMAX is 0x710, but all profile data in AppleBacklight Info.plist is slightly less than that max. It means the backlight is never pushed to the max.

It means we should probably use COFFEELAKE_PWMMAX 0xFFFF in SSDT-PNLF to match pre-sleep/wake values with post-sleep/wake values.

So first dump was during the black screen:
Code:
LEV2.....................................: 0x80000000
LEVL.....................................: 0x0
P0BL.....................................: 0x1BEF
GRAN.....................................: 0xF00
LEVW.....................................: 0x80000000
LEVX.....................................: 0x56CE
LEVD.....................................: 0x568C
PCHL.....................................: 0x0
Second dump was after the screen came on (approx. 3 minutes later):
Code:
LEV2.....................................: 0x80000000
LEVL.....................................: 0x0
P0BL.....................................: 0x315E
GRAN.....................................: 0xF00
LEVW.....................................: 0x80000000
LEVX.....................................: 0x56CE
LEVD.....................................: 0x568C
PCHL.....................................: 0x0
Only register that appears to change is P0BL (not sure what that is?).

No real change,...

So the problem register must be some other register that you're not dumping.
More reading of the PRM/programming guide/Intel datasheet will be required.

From memory (it has been a while) P0BL is a horizontal blank countdown... when it hits 0, you're at vertical blank. So the value here for dumping is not relevant/randomish.
 
There are some kPEDisableScreens and kPEEnableScreens in this. Are they related to this issue?
 

Attachments

  • kernel_log.zip
    34.1 KB · Views: 74
They are. This time I dropped SSDT-PNLF.aml and found that the kPEDisableScreen was not called at the start and neither did the screen go off during the very start of boot process as it usually does when using SSDT-PNLF.
 

Attachments

  • After dropping PNLF.zip
    32.8 KB · Views: 72
I have figured out the registers causing the freeze in Coffee Lake and now have a full dump with them removed. I will be forking the AppleIntelInfo with my Coffee Lake additions at some point.

They are. This time I dropped SSDT-PNLF.aml and found that the kPEDisableScreen was not called at the start and neither did the screen go off during the very start of boot process as it usually does when using SSDT-PNLF.

Removing SSDT-PNLF.aml doesn't make a difference for me.
 
Last edited:
I have been working on this issue for several days, and I want to share what I have found so far.

So my issue is that the internal display stays at the lowest brightness level and becomes normal after about 3 minutes, and I think @Amandeep's issue is exactly the same as mine. The only difference is that the lowest brightness level on his machine is "black screen".

In order to figure out which registers are related to the brightness level, I read several data sheets and conducted a number of experiment under Windows and Mac on my laptop. It turns out that Coffee Lake now has three key registers related to backlight control.

Code:
Offset    UInt32 Value    KBL::Name      APL::Name     CFL::Name
0xC8250    0x80000000    SBLC_PWM_CTL1   BLC_PWM_CTL       ??
0xC8254    0x0001D4C0    SBLC_PWM_CTL2   BLC_PWM_FREQ      ??
0xC8258    0x00008BB0      Unused        BLC_PWM_DUTY      ??

Notes:
1. KBL::Name means the register name in Kaby Lake data sheet.
2. APL::Name means the register name in Apollo Lake data sheet. (https://01.org/sites/default/files/...src-bxt-vol02b-commandreference-registers.pdf, Page 13, 14, 15)


I was able to read from and write to these registers under Windows via R/W Everything, and I found that 0xC8258 holds the value of the actual brightness level and the other two registers values remain unchanged. i.e. when I wrote a new value to 0xC8258, the brightness changed accordingly.

While the register at 0xC8258 is not used on Kaby Lake platform, I found an example usage in the data sheet for Apollo Lake, so I made a hypothesis that these three registers on Coffee Lake platform now have the same meanings and usages as Apollo Lake.

So I made a new SSDT for Device(PNLF) and simply initialized values (hard-coding) for these three registers inside Method (_INI).

Guess what? The brightness level becomes normal (I say normal because the display brightness now stays at 0x8BB0.) during system boot.

But the bad news is the brightness stays at the lowest level again AFTER the framebuffer driver loads and sets up the internal display.

Hmm, interesting. It seems that the framebuffer driver writes a new value (which is the lowest brightness level) during setting up the display.

So I started to find related functions inside the framebuffer driver that might write new values to this register.

And there are three key functions and we should also keep an eye on their callers.

Code:
// Called by doSetPowerState(), LightUpEDP(), etc.
AppleIntelFramebufferController::hwSetPanelPower(UInt32 arg0)
{
    ......

    AppleIntelFramebufferController::WriteRegister32(arg0, 0xc8254);    // 0x3a9e3 (macOS 10.14.1 b1)
    AppleIntelFramebufferController::WriteRegister32(arg0, 0xc8258);

    ......
}

AppleIntelFramebufferController::hwSetBacklight(UInt32 arg0)

AppleIntelFramebufferController::LightUpEDP(AppleIntelFramebuffer* arg0, AppleIntelDisplayPath* arg1, IODetailedTimingInformationV2* arg2)

After investigating these functions and their callers for a while, I started to realized that this backlight issue might be related to the issue I found (see this post) in the framebuffer driver a few days ago.

I kept researching on it and found that the kernel panic happens because Apple's driver fails to read the DPCD info.

Sample Kernel Logs:
(When the internal 4K display is working with the divide-by-zero patch and CoreDisplayFixup)
Code:
// Inside AppleIntelFramebufferController::GetDPCDInfo()
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: OUI for display
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  38 EC 11 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  0 0 0 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Display port config ver is 1.4
// AppleIntelFramebufferController::GetDPCDInfo() returns 
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Setting display mode 3840 x 2160 -> 0 x 0 encoded with 0x1  2 bpc with color 1 and range 1
// Inside AppleIntelFramebufferController::SetupClock()
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][ERROR  ] Invalid link parameters..re-attempt a DPCD read
// Inside AppleIntelFramebufferController::GetDPCDInfo()
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: OUI for display
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  38 EC 11 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  0 0 0 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Display port config ver is 1.4
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][ERROR  ] DPCD read re-attempt too failed
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Panel Fitter modeset
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Transitioning wsaa from 0 to 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Setting display mode 3840 x 2160 -> 0 x 0 encoded with 0x1  2 bpc with color 1 and range 1
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][ERROR  ] Invalid link parameters..re-attempt a DPCD read

Sample Kernel Logs:
(When CoreDisplayFixup is disabled (and therefore the internal 4K display is off) and with HDMI plugged in)
Code:
// Inside AppleIntelFramebufferController::GetDPCDInfo()
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: OUI for display
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  0 0 0 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ]  0 0 0 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Display port config ver is 1.2
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2 Maximum link rate is 0x14
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Maximum lanes is 4
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Display has 1 downstream ports
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Down stream port number 0 is HDMI
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Max dongle clock=600000000
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: Dongle BPC=2
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: YUV422 pass throughSupport = 0  YUV420 pass through support = 0 YUV444->YUV422 = 0 and YUV444->YUV420 = 0
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB2: VSC SDP extention [colorimetry_supported] = 0  VSC Ext VESA SDP support = 0 VSC Ext CEA SDP supported = 0 and Sink sleep to wake timeOut request = 0
// AppleIntelFramebufferController::GetDPCDInfo() returns
kernel: (AppleIntelCFLGraphicsFramebuffer) [IGFB][INFO   ] FB0: Transitioning wsaa from 0 to 0

So another important function comes to play, and I translated it a little bit.

Code:
// AppleIntelFramebuffer:
// 0x2384: (UInt8) dp port config full ver (e.g. 1.4)
// 0x2385: (UInt8) dp port config minor ver (1.[4])
// 0x2386: (UInt8) dp port config major ver ([1].4)
// 0x2387: (UInt8) maximum link rate
// 0x2388: (UInt8)
// 0x2389: (UInt8) maximum # of lanes

int AppleIntelFramebufferController::GetDPCDInfo(/* hidden arg self */ AppleIntelFramebuffer* arg0, AppleIntelDisplayPath* arg1)
{
    r14 = rdi; // self (AppleIntelFramebufferController*)
    r12 = rsi; // arg0 (AppleIntelFramebuffer*)
    r15 = rdx; // arg1 (AppleIntelDisplayPath*)

    // These two local variables contains very important information
    UInt64 var_30; // var_30's value is from a global var in the __got section.
    UInt64 var_38; // I don't know how this local var is initialized

    // I managed to read these two local vars values
    // var_30 = 0x683db337149800a1
    // var_38 = 0x00000b0000000002
    // And you can see from below that these values cause
    // this function to return an unsupported value.

    // Set dp power state
    // ... some code...

    // Get OUI for display
    // ... some code...
 
    // Get dp port config ver
    // ... some code...
 
    // var_3F: UInt8 link rate???
    switch (var_3F) // rax = var_3F
    {
        case 0x1E:
            // Some check
            rcx = 0x1E;
        case 0x14:
            // Some check
            rcx = 0x14;

        case 0x06:
            // NO CHECK
            rcx = 0x06;

        case 0x0A:
            // NO CHECK
            rcx = 0x0A;

        default:
            // Unsupported
            return failed;
    }
 
    // loc_8876:
    arg0->field@0x2387 = rcx;
    if (some check)
    {
        // Adjust the maximum link rate
        arg0->field@0x2387 = 0xC;
    }
    kprintf("Maximum link rate is 0x%x\n", rcx);

    // var_3E: UInt8 (lower 5 bits) contains maximum # of lanes
    rax = var_3E & 0x1F;
    arg0->field@0x2389 = rax;
    switch (var_3E & 0x1F)
    {
        case 1:
            goto loc_88ea;

        case 2:
            goto loc_88ea;

        case 4:
            goto loc_88ea;

        default:
            // Unsupported
            // lanes can only be one of 1, 2 and 4.
            return failed;
    }

    // loc_88ea:
    kprintf("Maximum lanes is %d\n", rax);

    arg0->field@0x238a = (rax >> 0x6) & 0x1 & 0xFF;

    if (arg0->dpVersion == 1.0)
    {
        arg0->field@0x2388 = 0x0;
    }
    else
    {
        arg0->field@0x2388 = rax >> 0x7;
    }

    ... some other code...

}

I learnt that DPCD info is retrieved via the AUX channel and a special I2C-over-AUX protocol is used for the communication.

And Apple does have related functions to do that:
Code:
ReadAUX(), WriteAUX(), RunAUXCommand() (This is the foundation for the first two AUX functions)
ReadI2COverAUX(), WriteI2COverAUX(), RunI2COverAUX() (This is the foundation for the first two I2COverAUX functions)

I am still trying to figure out why Apple's driver fails to get the DPCD info, and I guess if we could solve the DPCD issue, the brightness issue should go away, because the framebuffer driver stops reading the DPCD info (probably because of too many failures/attempts) when the brightness becomes normal.

- Is is due to the lack of I2C driver (like VoodooI2C.kext)?
I tried VoodooI2C but no luck. VoodooI2C does not officially support Coffee Lake.
Besides this does not make sense to me, as KBL framebuffer driver has the same logic to get DPCD info and we don't have similar issues on KBL laptops.

I am following this thread, and I will post it if I find something new.
 
Last edited:
It turns out that Coffee Lake now has three key registers related to backlight control.

Yes, we've known this for a while now. I made a post in another thread also.

I was able to read from and write to these registers under Windows via R/W Everything, and I found that 0xC8258 holds the value of the actual brightness level and the other two registers values remain unchanged. i.e. when I wrote a new value to 0xC8258, the brightness changed accordingly.

Yes that's true and I've posted the alg for calculating the value. You can also read the values via my modified AppleIntelInfo.kext. As you can see from my results before and after 3 minute black screen the backlight registers don't make any state change.

So I made a new SSDT for Device(PNLF) and simply initialized values (hard-coding) for these three registers inside Method (_INI).

Interesting. Hard coding these values in Clover just results in a black screen for me. If all I do is set the CTRL register to 0xC0000000 and leave the FREQ and DUTY registers alone I'll get to see scrolling text until the screen goes off for the usual 3 minutes.

But the bad news is the brightness stays at the lowest level again AFTER the framebuffer driver loads and sets up the internal display.

If this is true we could set the backlight registers in WhateverGreen after the FB kext loads.

After investigating these functions and their callers for a while, I started to realized that this backlight issue might be related to the issue I found (see this post) in the framebuffer driver a few days ago.

I have never experienced the KP you mention in your post. Have you tried 10.4.1 beta 3?

I am still trying to figure out why Apple's driver fails to get the DPCD info, and I guess if we could solve the DPCD issue, the brightness issue should go away, because the framebuffer driver stops reading the DPCD info (probably because of too many failures/attempts) when the brightness becomes normal.

Could be an avenue worth investigating, thanks for the info.

I am following this thread, and I will post it if I find something new.

You're welcome to contact me at <username>@gmail.com if you want to discuss and share more info related to this.
 
If this is true we could set the backlight registers in WhateverGreen after the FB kext loads.

But we still cannot change the brightness at all during the first three minutes.

I have never experienced the KP you mention in your post. Have you tried 10.4.1 beta 3?

Not yet. Will do.

If you have not experienced that kernel panic, probably the framebuffer driver can read the DPCD info on your machine.

Could you please check your kernel log to see whether there are lines saying something like "Invalid link parameters..re-attempt a DPCD read"?
 
Could you please check your kernel log to see whether there are lines saying something like "Invalid link parameters..re-attempt a DPCD read"?

I don't get that error.
 
From my finds and my kernel logs I only know that the backlight will go off as soon as something backlight related is called into action. If not using SSDT PNLF or a wrong SSDT PNLF, the backlight will remain on till the os loads up and would go off when you are near the login screen(when Apple logo blinks once). If using the SSDT PNLF the issue would come as soon the as load starts means a second after you hit enter on clover screen. From my logs, there are two types of functions or whatever is being called for the above-mentioned issue. kPEDisableScreen and kPEEnableScreen.
 
Back
Top