Skip to content

SmbusIntelSkylakeIMC: Support all addresses, remove special case hand…#62

Merged
namazso merged 1 commit into
namazso:mainfrom
CalcProgrammer1:main
Jun 22, 2026
Merged

SmbusIntelSkylakeIMC: Support all addresses, remove special case hand…#62
namazso merged 1 commit into
namazso:mainfrom
CalcProgrammer1:main

Conversation

@CalcProgrammer1

@CalcProgrammer1 CalcProgrammer1 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Edit: The scope of this PR changed as I worked it, so here's a full summary of what is changed. This PR is ready to merge.

  • The initial controller only supported accessing SPD and temperature sensor addresses, now it can access all addresses
  • Special handling for SPD and temperature sensor addresses has been removed now that it can just access arbitrary addresses
  • After reviewing the closest datasheet @Blacktempel could find to the actual hardware, it does not appear that SMBus Quick or Block operations are properly supportable on this implementation. The existing block operations were actually performing a loop of repeated byte operations, which is not a compatible replacement on many devices. It is best to just omit these unsupported operations entirely rather than exposing to userspace something that isn't accurate.
  • The operations that I have implemented (read/write byte, byte data, and word data) have all been verified with an oscilloscope to be performing the correct operations.
  • Leaving the ioctl argument sizes the same even though block operations are not supported so this module remains drop-in compatible with the other SMBus drivers in this repo.

Original description:
Based on the investigations I am working on in the comments of #60, I have removed a lot of the SPD special-case handling in this SMBus driver and instead opened up the range of allowed addresses to cover the full I2C address range. This has been successful in my testing with OpenRGB, though still limited by the limited supported operations. Namely, I can still bank switch the SPD by peforming a read operation on either 0x36 or 0x37 before dumping the SPD address. There seems to be some extra addresses being picked up by my I2C detection probes still and I'm not sure why, so consider this still WIP until I unmark Draft.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

It also seems slot and opcode are really just the address and handling of them can be combined.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

Removed opcode and slot because this is just taking the address, splitting it into two fields, and recombining those fields when generating the command word. The command word looks like 0x2008AACC where AA is address and CC is command.

@CalcProgrammer1 CalcProgrammer1 force-pushed the main branch 3 times, most recently from 0bcb729 to 13a8537 Compare June 12, 2026 07:27
@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

I think SMB_PNTR_SEL (bit 18) is how we achieve byte/word access instead of byte data/word data access. It selects between "pointer based access" and "random access". Apparently pointer based access is where you write the register address with a write and then perform separate reads which auto-increment the pointer and random access is where you send the address with each operation, corresponding to the behavior of the BYTE/WORD/BYTE_DATA/WORD_DATA operations.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

There is also SMB_DIS_WRT (bit 28) that disables writes if set. I think we need to clear this during write operations as the default command word (0x20080000) has this bit set.

I have some spare dummy modules around here somewhere and one of them that I ripped the casing off of. I had plans at one point to probe out the I2C pins on it and solder wires so that I could use it as a debug probe. I will try to get that working soon so I can see if we're actually performing write operations on the bus as intended.

@Blacktempel

Copy link
Copy Markdown
Contributor

I have tried your version 0bcb729, with a few further adjustments, for my WinRing0/Linux implementation for that SMBus and QUICK seems to work for me so far.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

I just assembled my debug probe RAM stick, will do some experiments soon. I need to get to bed.

PXL_20260612_083301695

@CalcProgrammer1

CalcProgrammer1 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Operations:

i2c_smbus_read_byte: Works
NewFile0

i2c_smbus_read_byte_data: Works
NewFile1

i2c_smbus_read_word_data: Works
NewFile4

i2c_smbus_write_quick: Does not work

i2c_smbus_write_byte: Works
NewFile2

i2c_smbus_write_byte_data: Works
NewFile3

i2c_smbus_write_word_data: Works
NewFile5

I still need to confirm the order of the bytes in word mode.

@Blacktempel

Copy link
Copy Markdown
Contributor

i2c_smbus_write_quick: Does not work

Could you please add quick ?
That works for me, based on your most recent master (8f9cc88):

diff --git a/SmbusIntelSkylakeIMC.p b/SmbusIntelSkylakeIMC.p
index 923aad1..48f4059 100644
--- a/SmbusIntelSkylakeIMC.p
+++ b/SmbusIntelSkylakeIMC.p
@@ -228,7 +228,8 @@ bool:WaitTransferComplete(expectedDoneBit, &lastStatus)
 
 NTSTATUS:ImcAccess(command, read_write, addr, hstcmd, &value)
 {
-    if (hstcmd != I2C_SMBUS_BYTE
+    if (hstcmd != I2C_SMBUS_QUICK
+     && hstcmd != I2C_SMBUS_BYTE
      && hstcmd != I2C_SMBUS_BYTE_DATA
      && hstcmd != I2C_SMBUS_WORD_DATA)
     {
@@ -271,17 +272,20 @@ NTSTATUS:ImcAccess(command, read_write, addr, hstcmd, &value)
 
         if (read_write == I2C_SMBUS_WRITE)
         {
-            new writeData = value & 0xFF;
-
-            if (hstcmd == I2C_SMBUS_WORD_DATA)
+            if (hstcmd != I2C_SMBUS_QUICK)
             {
-                writeData = ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8);
-            }
+                new writeData = value & 0xFF;
 
-            status = pci_config_write_dword(pci_address[0], pci_address[1], pci_address[2], DAT_REG, writeData << 16);
-            if (!NT_SUCCESS(status))
-            {
-                return status;
+                if (hstcmd == I2C_SMBUS_WORD_DATA)
+                {
+                    writeData = ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8);
+                }
+
+                status = pci_config_write_dword(pci_address[0], pci_address[1], pci_address[2], DAT_REG, writeData << 16);
+                if (!NT_SUCCESS(status))
+                {
+                    return status;
+                }
             }
 
             cmd |= WRITE_OPERATION;
@@ -297,7 +301,7 @@ NTSTATUS:ImcAccess(command, read_write, addr, hstcmd, &value)
         new expectedDoneBit = read_write == I2C_SMBUS_WRITE ? STS_WRITE_DONE : STS_READ_DONE;
         if (WaitTransferComplete(expectedDoneBit, lastStatus))
         {
-            if (read_write == I2C_SMBUS_WRITE)
+            if (read_write == I2C_SMBUS_WRITE || hstcmd == I2C_SMBUS_QUICK)
             {
                 pci_config_write_dword(pci_address[0], pci_address[1], pci_address[2], CMD_REG, oldCommand);
                 return STATUS_SUCCESS;
@@ -336,6 +340,7 @@ NTSTATUS:ImcAccess(command, read_write, addr, hstcmd, &value)
 /// SMBus transfer.
 ///
 /// Performs a transfer of data over the SMBus using the specified command.
+/// I2C_SMBUS_QUICK (0)
 /// I2C_SMBUS_BYTE_DATA (2)
 /// I2C_SMBUS_WORD_DATA (3)
 /// I2C_SMBUS_BLOCK_DATA (5)

Detection:

Mode MODE_QUICK:
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00           -- -- -- -- -- -- -- -- -- -- -- -- -- 
10  -- -- -- -- -- -- -- -- 18 -- 1A -- -- -- -- -- 
20  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30  -- -- -- -- -- -- 36 37 -- -- -- -- -- -- -- -- 
40  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70  -- -- -- -- -- -- -- 77                         

Quick write for thermal sensors is helpful for me (18, 1A).

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

Doesn't that just treat quick as a read byte operation? IIRC I thought quick was only supposed to send the Address+RW byte and then check if it was ACKed or not. Looking at the registers in the document you sent me there does not seem to be a way to instruct it to not send any following data.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

Oh, the write value is initialized to zero in the top level function. That's why none of my writes were working probably. It was always writing zero for the value. I confirmed the waveform sequences look right but the data itself wasn't working. I thought it might have been something on OpenRGB's side but looks like not. I will look into this more tonight.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

This was the problem, fixing the value = 0 to value = in[4] for the data input now OpenRGB can successfully detect my ENE DRAM modules, read the version string, and control the built-in effects. However, direct mode (software control of the individual LEDs) uses SMBus block writes. I see you tried to implement block accesses but you're doing them as a series of individual read/write operations rather than as a proper block operation. I don't think this works. I don't see a way to do proper block operations in the datasheet, so maybe it's best to just return a not supported error on these (along with quick) and have the application revert to a non-block operation if possible.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

Was able to control direct mode by replacing block operations with a loop of byte operations. I'm going to try to add a block workaround in my generic PawnIO SMBus module so that block operations get converted into repeated byte operations. I think it is best for the PawnIO module itself to only expose what the hardware is properly capable of and return NOT_SUPPORTED for anything it doesn't actually support.

@Blacktempel

Copy link
Copy Markdown
Contributor

Yes I think block operations are not supported by default.
I wanted to have it easy and just add it into the SMBus module so there wouldn't have to be too many changes on top of it.


I've re-checked the document now.
I suppose we could leave out block & quick.

@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

More confirmation that block operations are not supported. I installed Corsair iCue because the Corsair RGB RAM modules typically use a single block operation to send an LED frame in direct mode so I wanted to see if they were doing something we're not. I used my debug probe to get bus captures and iCue is using a different access protocol than it normally does. It seems to be doing a series of word writes to a different address range, so it seems Corsair implemented a workaround for doing these block transfers without actual block operations.

@CalcProgrammer1 CalcProgrammer1 changed the title [Draft] SmbusIntelSkylakeIMC: Support all addresses, remove special case hand… SmbusIntelSkylakeIMC: Support all addresses, remove special case hand… Jun 14, 2026
@CalcProgrammer1 CalcProgrammer1 force-pushed the main branch 2 times, most recently from 3c3e7a2 to 345dac0 Compare June 14, 2026 21:56
Comment thread SmbusIntelSkylakeIMC.p Outdated
Comment thread SmbusIntelSkylakeIMC.p Outdated
Comment thread SmbusIntelSkylakeIMC.p
@CalcProgrammer1

Copy link
Copy Markdown
Contributor Author

@namazso Do you have any review comments on this? I would be very grateful if this made it into a signed release within the next week or so, as I want to do an OpenRGB 1.0rc3 release candidate build and get this work into it.

@namazso namazso merged commit 3d4035e into namazso:main Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants