I2C Controller Wierdness
I2C Controller Wierdness
Hey,
On my test system, my trackpad is wired up via I2C (MS HID over I2C).
The machine is an Alder Lake Dell Laptop, so series 600/700 PCH chipset I believe.
PCI enumeration gives me two I2C controllers.
I use ACPI ASL to identify the controller parameters and associated I2C devices (slave address, speed etc).
Sofar so good.. now, things go wierd.
If I try to access the I2C controller MMIO space I read back all 1's - I verified the BARs for both controllers look to be valid and initliased by firmware, also ensure bus master/memory access etc is enabled.
I then checked the PCI power management capability to find they're in D3, so I bring them into D0 (odd this - as you'd think the trackpad would be on by default?) - still read back 1's.
I then even tried using the LPSS additional registers to do the reset assert/de-assert .. no change.
The only way I can get access to the MMIO space is if I allocate my own MMIO BAR memory and re-program the device with that range as well as the D3->D0 transition.
I even tried enabling UEFI Pointer Protocol first to see if that would jumpstart anything but it made no difference.
Is there some sort of other gating mechanism that prevents access to the I2C controllers?
I also extracted all the GPIO configuration from ACPI as the I2C controllers should be setup to trigger GPEs via GPIO - what a convoluted mess that is that I can't make head nor tail of, and the 600/700 series PCH datasheet registers don't seem to align with what the ACPI _INI method does at all!
Hoping someone has some insight into how to actually get I2C from the PCH working - specifically for HID/trackpad really, and any insight into the GPIO wiring!
On my test system, my trackpad is wired up via I2C (MS HID over I2C).
The machine is an Alder Lake Dell Laptop, so series 600/700 PCH chipset I believe.
PCI enumeration gives me two I2C controllers.
I use ACPI ASL to identify the controller parameters and associated I2C devices (slave address, speed etc).
Sofar so good.. now, things go wierd.
If I try to access the I2C controller MMIO space I read back all 1's - I verified the BARs for both controllers look to be valid and initliased by firmware, also ensure bus master/memory access etc is enabled.
I then checked the PCI power management capability to find they're in D3, so I bring them into D0 (odd this - as you'd think the trackpad would be on by default?) - still read back 1's.
I then even tried using the LPSS additional registers to do the reset assert/de-assert .. no change.
The only way I can get access to the MMIO space is if I allocate my own MMIO BAR memory and re-program the device with that range as well as the D3->D0 transition.
I even tried enabling UEFI Pointer Protocol first to see if that would jumpstart anything but it made no difference.
Is there some sort of other gating mechanism that prevents access to the I2C controllers?
I also extracted all the GPIO configuration from ACPI as the I2C controllers should be setup to trigger GPEs via GPIO - what a convoluted mess that is that I can't make head nor tail of, and the 600/700 series PCH datasheet registers don't seem to align with what the ACPI _INI method does at all!
Hoping someone has some insight into how to actually get I2C from the PCH working - specifically for HID/trackpad really, and any insight into the GPIO wiring!
Re: I2C Controller Wierdness
OK.. I think my problem is the LPSS registers are NOT in the I2C device MMIO, they're in the PCR/PCH space somewhere.. so the i2c controller is still gated/clocked-off - I need to work out how to find where these private registers are.. It doesn't seem to be from pwrmbase or the sideband base ...
Re: I2C Controller Wierdness
This seems to be going down a rabbit hole of sideband access, P2SB controller, and hitting dead ends everywhere.
The p2sb controller is hidden - I can't unhide it as it's PCI config space 0:31:1 returns 1's.
ACPI has given me a sideband mmio range, but everything just reads back as zero from there, and I can't see any way to enable it.
I can't access Sideband then via mmio .. nor can I access it vie the sideband mailbox/message interface as that is in the same pci config space above.
But without that, it seems like I can't bring the LPSS out of reset - which means the i2c controllers never work... what moron on crack architected
this abomination???
The p2sb controller is hidden - I can't unhide it as it's PCI config space 0:31:1 returns 1's.
ACPI has given me a sideband mmio range, but everything just reads back as zero from there, and I can't see any way to enable it.
I can't access Sideband then via mmio .. nor can I access it vie the sideband mailbox/message interface as that is in the same pci config space above.
But without that, it seems like I can't bring the LPSS out of reset - which means the i2c controllers never work... what moron on crack architected
this abomination???
-
Octocontrabass
- Member

- Posts: 6245
- Joined: Mon Mar 25, 2013 7:01 pm
Re: I2C Controller Wierdness
You may find the External Design Specification more useful than the datasheet.
If you don't have access to the External Design Specification, share the _INI method and I can check to see if it makes sense.
Re: I2C Controller Wierdness
From ACPI I have an NVS region OperationRegion (PNVA, SystemMemory, PNVB, PNVL)
From which I have a 32bit value SBRG (Sideband register base)
Motherboard resources expose several base address CRS from this:
BAS0 = SBRG
BAS1 = (SBRG + 0x006C0000)
BAS2 = (SBRG + 0x006B0000)
BAS3 = (SBRG + 0x006F0000)
None of these are ever used in the ASL that I can see.
Given that the P2SB controller is completely locked down, I assumed that the firmware would have done what it needs to configure it, hidden it and then via ACPI exposes this sideband MMIO window for OS/drivers to use.
If we take the trackpad device from the ASL:
It's mapped to I2C controller 1, TPDM/TPDT etc are all variables from the same NVS region.
The PRM/datasheet says that the I2C controller won't respond until it's brought out of reset via the LPSS / private configuration registers which are accessed via the PCH - I'm assuming sideband. It lists offset 0x200 up:
It also states that these can be access via 0:31:1 SBREG_BAR + PortID + Offset .. however there are NO PortIDs given for serial io or i2c controllers!
I've tried probing through that MMIO window I have above from ACPI but every read there returns 0x0.
The sideband cmd/data messaging PCI config space ports are also inaccesible as the entire P2SB device returns 1's - so it seems like some sort of chicken and egg situation.
My plan was to get the i2c controller at least operational, then poll based HID/i2c .. then look at the GPIO stuff which is equally confusing as it doesn't gie me any indication which community it's in or which pin really.. there are a few other NVS values (GPDI specifically) - which is a 32bit value and looks like it encodes some of this info, but not enough to really understand how the GPIO is wired up, nor which GPE it might trigger.
I guess what I'm trying to understand at a high level here is what the expected flow/steps should be:
1. The I2C controller (PCI device) is D3, but has a valid BAR programmed.
2. Bringing it to D0 and enabling Memory Access/Bus Master still has it's MMIO range returning 1's - so it's gated.
3. This gating I believe is the LPSS reset/clock gating.
4. How do I access the LPSS private config registers for the i2c controller?
5. The P2SB controller is hidden/locked down - so I can't use the cmd/data interface - but I do have a base address provided by ACPI.
6. That base address seems to just give back 0's, but it could be that I don't have the right location within that MMIO window.
7. Do I need to do any magic to unhide and do anything with the p2sb - or should I just leave that alone and rely on the sideband MMIO provided by ACPI?
8. If I don't have a portID, how do I find the config register space in there for the given I2C controller to bring it out of reset/enable clocks to get MMIO range to respond?
From which I have a 32bit value SBRG (Sideband register base)
Motherboard resources expose several base address CRS from this:
BAS0 = SBRG
BAS1 = (SBRG + 0x006C0000)
BAS2 = (SBRG + 0x006B0000)
BAS3 = (SBRG + 0x006F0000)
None of these are ever used in the ASL that I can see.
Given that the P2SB controller is completely locked down, I assumed that the firmware would have done what it needs to configure it, hidden it and then via ACPI exposes this sideband MMIO window for OS/drivers to use.
If we take the trackpad device from the ASL:
Code: Select all
Scope (_SB.PC00.I2C1)
{
Name (I2CN, Zero)
Name (I2CX, Zero)
Method (_INI, 0, NotSerialized) // _INI: Initialize
{
I2CN = SDS1 /* \SDS1 */
I2CX = One
}
Device (TPD0)
{
Name (HID2, Zero)
Name (ITPN, "DELL0B3C")
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\\_SB.PC00.I2C1",
0x00, ResourceConsumer, _Y58, Exclusive,
)
})
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0000
}
})
Name (SBFI, ResourceTemplate ()
{
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, _Y59)
{
0x00000000,
}
})
CreateWordField (SBFB, \_SB.PC00.I2C1.TPD0._Y58._ADR, BADR) // _ADR: Address
CreateDWordField (SBFB, \_SB.PC00.I2C1.TPD0._Y58._SPE, SPED) // _SPE: Speed
CreateWordField (SBFG, 0x17, INT1)
CreateDWordField (SBFI, \_SB.PC00.I2C1.TPD0._Y59._INT, INT2) // _INT: Interrupts
Method (_INI, 0, NotSerialized) // _INI: Initialize
{
If (CondRefOf (TPHD)){}
If ((OSYS < 0x07DC))
{
SRXO (GPDI, One)
}
INT1 = GNUM (GPDI)
INT2 = INUM (GPDI)
If ((TPDM == Zero))
{
SHPO (GPDI, One)
}
If (CondRefOf (TPHD))
{
ITPN = ToString (TPHD, Ones)
}
HID2 = TPDH /* \TPDH */
BADR = TPDB /* \TPDB */
If ((TPDS == Zero))
{
SPED = 0x000186A0
}
If ((TPDS == One))
{
SPED = 0x00061A80
}
If ((TPDS == 0x02))
{
SPED = 0x000F4240
}
}
Method (_HID, 0, NotSerialized) // _HID: Hardware ID
{
Return (ITPN) /* \_SB_.PC00.I2C1.TPD0.ITPN */
}
Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID: Compatible ID
Name (_S0W, 0x03) // _S0W: S0 Device Wake State
Name (DRDY, Zero)
Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method
{
If ((DRDY == Zero))
{
If ((Arg0 == HIDG))
{
DRDY = One
EV13 (Zero, Zero)
}
}
If ((Arg0 == HIDG))
{
Return (HIDD (Arg0, Arg1, Arg2, Arg3, HID2))
}
If ((Arg0 == TP7G))
{
Return (TP7D (Arg0, Arg1, Arg2, Arg3, SBFB, SBFG))
}
Return (Buffer (One)
{
0x00 // .
})
}
Method (_STA, 0, NotSerialized) // _STA: Status
{
If (((TPDT != Zero) && (I2CN & One)))
{
Return (0x0F)
}
Return (Zero)
}
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
If ((OSYS < 0x07DC))
{
Return (SBFI) /* \_SB_.PC00.I2C1.TPD0.SBFI */
}
If ((TPDM == Zero))
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
}
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFI))
}
}
}
The PRM/datasheet says that the I2C controller won't respond until it's brought out of reset via the LPSS / private configuration registers which are accessed via the PCH - I'm assuming sideband. It lists offset 0x200 up:
Code: Select all
LPSS_RESETS EQU 0x04 ; Reset control
LPSS_ACTIVELTR EQU 0x10
LPSS_IDLELTR EQU 0x14
LPSS_TX_ACK_CNT EQU 0x18
LPSS_RX_BYTE_CNT EQU 0x1c
LPSS_INT_STATUS_TX_COMPLETE EQU 0x20
LPSS_TX_INT_CLEAR EQU 0x24
LPSS_SW_SCRATCH0 EQU 0x28
LPSS_SW_SCRATCH1 EQU 0x2c
LPSS_SW_SCRATCH2 EQU 0x30
LPSS_SW_SCRATCH3 EQU 0x34
LPSS_CLOCK_GATE EQU 0x38
LPSS_REMAP_ADDR_LO EQU 0x40
LPSS_REMAP_ADDR_HI EQU 0x44
LPSS_DEVICE_CONTROL EQU 0x4c
LPSS_CAPS EQU 0xfc
I've tried probing through that MMIO window I have above from ACPI but every read there returns 0x0.
The sideband cmd/data messaging PCI config space ports are also inaccesible as the entire P2SB device returns 1's - so it seems like some sort of chicken and egg situation.
My plan was to get the i2c controller at least operational, then poll based HID/i2c .. then look at the GPIO stuff which is equally confusing as it doesn't gie me any indication which community it's in or which pin really.. there are a few other NVS values (GPDI specifically) - which is a 32bit value and looks like it encodes some of this info, but not enough to really understand how the GPIO is wired up, nor which GPE it might trigger.
I guess what I'm trying to understand at a high level here is what the expected flow/steps should be:
1. The I2C controller (PCI device) is D3, but has a valid BAR programmed.
2. Bringing it to D0 and enabling Memory Access/Bus Master still has it's MMIO range returning 1's - so it's gated.
3. This gating I believe is the LPSS reset/clock gating.
4. How do I access the LPSS private config registers for the i2c controller?
5. The P2SB controller is hidden/locked down - so I can't use the cmd/data interface - but I do have a base address provided by ACPI.
6. That base address seems to just give back 0's, but it could be that I don't have the right location within that MMIO window.
7. Do I need to do any magic to unhide and do anything with the p2sb - or should I just leave that alone and rely on the sideband MMIO provided by ACPI?
8. If I don't have a portID, how do I find the config register space in there for the given I2C controller to bring it out of reset/enable clocks to get MMIO range to respond?
-
Octocontrabass
- Member

- Posts: 6245
- Joined: Mon Mar 25, 2013 7:01 pm
Re: I2C Controller Wierdness
Which part of the datasheet says that? None of the LPSS PCRs look like they're related to power management.
Those aren't PCRs, they're mapped through BAR0 like the other I2C registers.
The LPSS devices (UART, I2C, GSPI) share port ID 0xCB. If you do need to access their PCRs, they'd start at SREG_BAR + 0xCB0000.
Re: I2C Controller Wierdness
Ahh maybe that explains the extra common in the PCH datasheet it says
UART, , GSPI .. maybe a typo, but thanks for clarifying!
I've tried reading all over the SBREG MMIO space at various port IDs, I get a mix of all 0, or all 1, I've found a few isolated bytes that read back as something else. The fact that its not consistent ALL 0 or ALL 1 makes me feel like the decoding and MMIO window is "working" - but nothing in it is fully initialized, for example, from ASL we have a clock control block at an undocumented (at least to me) port id:
ICKP I read from NVS as 0xad, and SBRG is 0xfd000000 - these all read back as 0.
I'm starting to feel like I've missed something in the ASL that "kick starts" everything or initializes these motherboard resource areas, possibly relinquish some sort of SMI control over them... given the I2C controller is 100% definitely there and absolutely essential to post ACPI trackpad operation (I did have a PS/2 mouse driver already working - but as soon as I do ACPI handover it dies - so SMI emulation most likely - and the PS2M device in the ASL is probably just a stub.. or who knows what it's there for)
UART, , GSPI .. maybe a typo, but thanks for clarifying!
I've tried reading all over the SBREG MMIO space at various port IDs, I get a mix of all 0, or all 1, I've found a few isolated bytes that read back as something else. The fact that its not consistent ALL 0 or ALL 1 makes me feel like the decoding and MMIO window is "working" - but nothing in it is fully initialized, for example, from ASL we have a clock control block at an undocumented (at least to me) port id:
Code: Select all
Device (ICLK)
{
Name (_HID, EisaId ("PNP0C02") /* PNP Motherboard Resources */) // _HID: Hardware ID
Name (_UID, "ISCLK") // _UID: Unique ID
OperationRegion (CKOR, SystemMemory, (SBRG + ((ICKP << 0x10) + 0x8000)), 0x40)
Field (CKOR, AnyAcc, Lock, Preserve)
{
CLK0, 8,
Offset (0x0C),
CLK1, 8,
Offset (0x18),
CLK2, 8,
Offset (0x24),
CLK3, 8,
Offset (0x30),
CLK4, 8,
Offset (0x3C),
CLK5, 8
}
I'm starting to feel like I've missed something in the ASL that "kick starts" everything or initializes these motherboard resource areas, possibly relinquish some sort of SMI control over them... given the I2C controller is 100% definitely there and absolutely essential to post ACPI trackpad operation (I did have a PS/2 mouse driver already working - but as soon as I do ACPI handover it dies - so SMI emulation most likely - and the PS2M device in the ASL is probably just a stub.. or who knows what it's there for)
-
Octocontrabass
- Member

- Posts: 6245
- Joined: Mon Mar 25, 2013 7:01 pm
Re: I2C Controller Wierdness
Looks like I'm at a dead end here..
I've double/triple checked everything and it just refuses to respond.
I have exactly two I2C controller PCI devices:
8086:51e8 (Intel I2C Controller #0)
8086:51e9 (#1)
Both of them are D3, but do report having a valid BAR address - it looks like it's been programmed to somewhere by firmware.
If I transition them from D3 -> D0 via PCI PM capability, enable bus-master and memory access .. the whole MMIO range reads back as 0xffffffff's.
If I re-program the BARs and allocate my own MMIO space as part of that process, then the entire MMIO range reads back 0x0000000 - but does drop writes (ie write 0xa5a5a5a5 read back = 0).
I've gone top to bottom through the ASL looking for P0, ON, DSM, REG, INI functions at PCI, SB and ICxx levels .. they don't seem to do anything that would in anyway somehow bring these devices to life - I was only able to find some ASL that handles a transition to D3cold.
The PCR registers for them just have basic PCI level stuff (PCICFGCTRL) - I did double check them via SBRG + (0xcb << 16) + offsets given, 0x200, 0x204. Don't see any bits there like functional or BAR disable set.
I'm at a loss
- how the heck do you get these devices to function?
I've double/triple checked everything and it just refuses to respond.
I have exactly two I2C controller PCI devices:
8086:51e8 (Intel I2C Controller #0)
8086:51e9 (#1)
Both of them are D3, but do report having a valid BAR address - it looks like it's been programmed to somewhere by firmware.
If I transition them from D3 -> D0 via PCI PM capability, enable bus-master and memory access .. the whole MMIO range reads back as 0xffffffff's.
If I re-program the BARs and allocate my own MMIO space as part of that process, then the entire MMIO range reads back 0x0000000 - but does drop writes (ie write 0xa5a5a5a5 read back = 0).
I've gone top to bottom through the ASL looking for P0, ON, DSM, REG, INI functions at PCI, SB and ICxx levels .. they don't seem to do anything that would in anyway somehow bring these devices to life - I was only able to find some ASL that handles a transition to D3cold.
The PCR registers for them just have basic PCI level stuff (PCICFGCTRL) - I did double check them via SBRG + (0xcb << 16) + offsets given, 0x200, 0x204. Don't see any bits there like functional or BAR disable set.
I'm at a loss
Re: I2C Controller Wierdness
Finally got this working!
After all the deep dives into PCRs, Sideband and PCH config.. turns out it was a simple issue.
Before accessing the main I2C MMIO registers, you have to use the "private registers" - which I think are a mirror of what they originally had as LPSS.
On the 600/700 series chipset these start at MMIO offset 0x200. You use the registers here to bring the device out of reset, enable clocks etc.
The problem was 0x204 (SOFT RESETS). The manual and any revision I could find of it, only shows bit 2 (DMA reset), so I was writing 0x04 to it.
However, after reading the Linux i2c code - they write 0x07 (including bits 0 and 1). As soon as I did that.. things worked - so I can assume it's just a datasheet/PRM mistake - thanks Intel
After all the deep dives into PCRs, Sideband and PCH config.. turns out it was a simple issue.
Before accessing the main I2C MMIO registers, you have to use the "private registers" - which I think are a mirror of what they originally had as LPSS.
On the 600/700 series chipset these start at MMIO offset 0x200. You use the registers here to bring the device out of reset, enable clocks etc.
The problem was 0x204 (SOFT RESETS). The manual and any revision I could find of it, only shows bit 2 (DMA reset), so I was writing 0x04 to it.
However, after reading the Linux i2c code - they write 0x07 (including bits 0 and 1). As soon as I did that.. things worked - so I can assume it's just a datasheet/PRM mistake - thanks Intel
-
Octocontrabass
- Member

- Posts: 6245
- Joined: Mon Mar 25, 2013 7:01 pm
Re: I2C Controller Wierdness
You've just reminded me of something important. Intel didn't design the I2C controller, they licensed it from Synopsys. You can use datasheets for other devices that contain the same Synopsys design when you're writing your driver. One of those other datasheets might explain the two undocumented bits.
That might also help you when you write your GPIO driver, since that's probably also a Synopsys design.
That might also help you when you write your GPIO driver, since that's probably also a Synopsys design.
