OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 9:56 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: GMBUS never asserts HW_RDY during read
PostPosted: Mon Jun 13, 2022 4:51 am 
Offline
Member
Member
User avatar

Joined: Fri Jun 11, 2021 6:02 am
Posts: 96
Location: Belgium
I'm writing a driver for Intel HD Graphics (specifically, a HD Graphics 5500 from a HP EliteBook Folio 1040 G2). Right now I'm trying to get the EDID of my laptop's display but the GMBUS seems to get stuck while reading from some ports.

I'm trying to get the EDID as follows:

- Reset the GMBUS by asserting and deasserting bit 31 of GMBUS1 ("Software Clear Interrupt").
- Write either 0x2, 0x4, 0x5 or 0x6 to GMBUS0 (pin pair DAC DDC, DDIC, DDIB, DDID at 100KHz respectively).
- Write 0x468000a1 to GMBUS1 ("Software Ready", Bus cycle "Index, No Stop, Wait", 128 byte count, index 0, address 0x50, read).
- Wait for "Hardware Ready" or "Not Acknowledged".

I get the following values for each pin pair:

- DAC DDC: GMBUS2 reads 0x0800 after setting GMBUS0 ("Hardware Ready"), 0x8200 during read ("INUSE" and "GMBUS Active").
- DDIB: GMBUS2 reads 0x8c00 after setting GMBUS0 ("INUSE", "Hardware Ready" and "NAK Indicator"), same during read.
- DDIC: GMBUS2 reads 0x8000 after setting GMBUS0 ("INUSE"), 0x8c00 during read.
- DDID: GMBUS2 reads 0x8000 after setting GMBUS0, 0x8200 during read.

I would expect to read 0x8a00 ("INUSE", "Hardware Ready" and "GMBUS Active") at some point, though this is evidently not happening. Switching the order of each attempt on each pin doesn't seem to affect the results. Trying to write a byte first like in managarm's driver doesn't seem to do anything either.

You can find my current code here. It is based on:
- managarm's Intel Native Graphics driver
- Intel's GPU documentation for Broadwell chips
- The OSDev's wiki article on Intel HD Graphics

_________________
My OS is Norost B (website, Github, sourcehut)
My filesystem is NRFS (Github, sourcehut)


Top
 Profile  
 
 Post subject: Re: GMBUS never asserts HW_RDY during read
PostPosted: Mon Jun 13, 2022 7:57 am 
Offline
Member
Member
User avatar

Joined: Fri Jun 11, 2021 6:02 am
Posts: 96
Location: Belgium
I believe the issue is that both of the ports that get stuck are DisplayPort ports: one external and one internal (eDP). I'll read up on DP and try to make I2C work. If it does, then we know that GMBUS can't be used for DP devices :)

_________________
My OS is Norost B (website, Github, sourcehut)
My filesystem is NRFS (Github, sourcehut)


Top
 Profile  
 
 Post subject: Re: GMBUS never asserts HW_RDY during read
PostPosted: Tue Jun 14, 2022 4:54 am 
Offline
Member
Member
User avatar

Joined: Fri Jun 11, 2021 6:02 am
Posts: 96
Location: Belgium
I've successfully managed to retrieve the EDID! :D

Code:
00 ff ff ff ff ff ff 00  30 e4 0a 04 00 00 00 00
00 17 01 04 95 1f 11 78  ea dc 95 a3 58 55 a0 26
0d 50 54 00 00 00 01 01  01 01 01 01 01 01 01 01
01 01 01 01 01 01 ba 36  80 ac 70 38 24 40 3c 24
35 00 35 af 10 00 00 1a  7c 24 80 ac 70 38 24 40
3c 24 35 00 35 af 10 00  00 1a 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 02
00 0c 33 ff 0f 3c 96 19  16 32 96 00 00 00 00 fb


(btw, the wiki says that the last byte is "Checksum (Low Byte of 16-bit sum of 00-7Eh)". I don't think this makes it clear that the sum of all 128 bytes mod 256 should be 0.)

I'm going to collect my thoughts here, then later add a wikipage about DisplayPort (and maybe DDC) and update the Intel HD Graphics page.

Here my the current code. I'll clean it up later.

I2C

I2C is a very simple protocol: there is a master and up to 128 slaves. When reading/writing data, bits 7:1 indicate the address and bit 0 indicate a read if set, a write otherwise (i.e. direction). Then bytes are written until a NACK is sent.

DDC2 & EDID

DDC2 is what is used to retrieve the EDID. You must first write the offset, which should be 0, then read 128 bytes. If the data starts with 00 FF FF FF FF FF FF 00 and the sum of the data modulo 256 is 0 you've got it.

DDC/CI

DDC/CI is a protocol that is built on top of I2C. http://boichat.ch/nicolas/ddcci/specs.html

DisplayPort

DisplayPort has two channels: a main channel for video, audio ... and an auxiliary channel for I2C and whatever else.

The AUX CH is a packet-based protocol: each packet is up to 16 (20?) bytes large. The "Source" initiates a request and a "Sink" always replies within a timeout.

Each request starts with a header byte with the following format:

- bit 7: 0 for I2C data, 1 for "native" AUX CH data
- I2C: bit 6: middle-of-transaction (remember, DP packets are max 16 bytes but I2C data can be much longer)
- I2C: bit 5:4: 00 = write, 01 = read, 10 = status_request, 11 = reserved

Each reply also starts with a header byte. For I2C packets it's as follows:
- bit 5:4: 00 = AUX_ACK, 01 = AUX_NACK, 10 = AUX_DEFER, 11 = reserved
- if AUX_ACK: bit 7:6: 00 = I2C_ACK, 01 = I2C_NACK, 10 = I2C_DEFER, 11 = reserved
- if !AUX_ACK: bit 7:6 must be 00

The remaining bits are 0. The DP documentation says the header is in bits 3:0 bit this is misleading since the padding is prepended. The remaining bytes are data.

I2C_DEFER is sent if the I2C device is unable to fill the requested (expected) amount of data before the timeout (300µs). For reading EDID data at >50KHz this shouldn't be an issue if you read byte-by-byte.

The length is encoded as a 4 bit value minus 1 (e.g. 4 bytes of data -> 0b0011)

To read the EDID, the communication looks as follows (> is data sent, < is data received):

Code:
> 0b0_1_00_0000, 0, 0x50 (I2C, MOT = 1, write, address 0x50)
< 0b00_00_0000 (AUX_ACK, I2C_ACK)
> 0b0_1_00_0000, 0, 0x50, 0, 0 (I2C, MOT = 1, write, address 0x50, length 1, data 0)
< 0b00_00_0000 (AUX_ACK, I2C_ACK)
> 0b0_1_01_0000, 0, 0x50 (I2C, MOT = 1, read, address 0x50)
< 0b00_00_0000 (AUX_ACK, I2C_ACK)
loop 128 times:
> 0b0_1_01_0000, 0, 0x50, 0 (I2C, MOT = 1, read, address 0x50, length 1)
< 0b00_00_0000, x (AUX_ACK, I2C_ACK, data x)
repeat loop
> 0b0_0_01_0000, 0, 0x50 (I2C, MOT = 0, read, address 0x50)
< 0b00_00_0000 (AUX_ACK, I2C_ACK)


http://file.yizimg.com/383992/2014090921252964.pdf section 2.4, 2.4.5.4

Intel HD Graphics DP registers

There are 6 registers of note:
- DDI_AUX_CTL
- DDI_AUX_DATA
- DP_AUX_CTL
- DP_AUX_DATA
- SRD_AUX_CTL
- A seemingly unnamed register at 0xC2020

DP_AUX_* and DDI_AUX_* are exactly the same except that the DDI_* can only be used if all SRD_* registers are set as disabled. *_AUX_DATA are actually 5 registers for a total of 20 bytes of data. It may be necessary to set bit 12 of 0xC2020 which does stuff with the clock apparently.

To send a request, copy the request packet to the data registers starting from the most significant byte of the first register. Then set the message length and the send_busy bit. Wait for the done bit or any of the error bits to be set, then use the message length to determine how much data is available in the data registers.

You should preserve all the bits in the *_CTL registers. The firmware has most likely set them up properly already.

https://01.org/linuxgraphics/documentat ... l-platform Volume 02A

_________________
My OS is Norost B (website, Github, sourcehut)
My filesystem is NRFS (Github, sourcehut)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Majestic-12 [Bot] and 61 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group