0

I am new to UEFI and I am attempting to talk to an i2c bus on an Up eXtreme board. I have tried following people trying similar things with USB online but gBS->LocateHandleBuffer does not seem to find the i2c bus. I am led to assume that since i2c behaves differently to USB I may not be able to take the same approach with it, but I have no way of confirming my suspicions.

At this point any tips/pointers would be appreciated.

EFI_STATUS
EFIAPI
UefiMain(
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE* SystemTable
)
{
    EFI_STATUS Status;
    EFI_HANDLE* HandleBuffer = NULL;
    UINTN      HandleCount = 17;

    Print(L"HandleCount:    %x\n", HandleCount);
    Print(L"HandleBuffer:   %x\n", HandleBuffer);
    UINTN* freq = (UINTN*)23;
    EFI_I2C_DEVICE* i2cDescriptor;
    EFI_I2C_ENUMERATE_PROTOCOL* enumerateI2c;
    Status = gBS->LocateHandleBuffer(ByProtocol,
        &gEfiI2cEnumerateProtocolGuid,
        NULL,
        &HandleCount,
        &HandleBuffer);
    if (EFI_ERROR(Status)) {
        Print(L"ERROR: LocateHandleBuffer.\n");
        Print(L"Status: %x\n", (int)Status);
        Print(L"HandleCount:    %x\n", HandleCount);
        Print(L"HandleBuffer:   %x\n", HandleBuffer);
        return Status;
    }

    for (UINT8 Index = 0; Index < HandleCount; Index++) {
        Status = gBS->HandleProtocol(HandleBuffer[Index],
            &gEfiI2cEnumerateProtocolGuid,
            (VOID**)&enumerateI2c);
        if (EFI_ERROR(Status)) {
            Print(L"ERROR: HandleProtocol.\n");
            Print(L"Status: %x\n", (int)Status);
            Print(L"HandleCount:    %x\n", HandleCount);
            Print(L"HandleBuffer:   %x\n", HandleBuffer);
            FreePool(HandleBuffer);
            return Status;
        }
        Status = enumerateI2c->Enumerate(enumerateI2c, &i2cDescriptor);
        Print(L"Starting to enumerate\n");
        if (EFI_ERROR(Status)) {
            Print(L"ERROR: Enumerate.\n");
            Print(L"Status: %x\n", (int)Status);
            Print(L"HandleCount:    %x\n", HandleCount);
            Print(L"HandleBuffer:   %x\n", HandleBuffer);
            FreePool(HandleBuffer);
            return Status;
        }
        Print(L"Enumeration complete\nGetting Bus frequency\n");
        Status = enumerateI2c->GetBusFrequency(enumerateI2c, i2cDescriptor->I2cBusConfiguration, freq);

        if (EFI_ERROR(Status)) {
            Print(L"ERROR: GetBusFrequency.\n");
            Print(L"Status: %x\n", (int)Status);
            FreePool(HandleBuffer);
            return Status;
        }
        Print(L"Found Frequency:\n");
        Print(L"%d\n", (CHAR16*)freq);
    }
    FreePool(HandleBuffer);
    return EFI_SUCCESS;
}
0andriy
  • 4,183
  • 1
  • 24
  • 37
silkyskate
  • 11
  • 2
  • Are you sure that the UP board has builtin uefi i2c support? – MiSimon Jun 29 '22 at 11:18
  • @MiSimon That is entirely possible since I do not know where to check. – silkyskate Jun 29 '22 at 16:01
  • Since there is an open source uefi for your board, i checked the [edk2-plattform](https://github.com/tianocore/edk2-platforms/tree/master/Platform/Intel/WhiskeylakeOpenBoardPkg/UpXtreme) repository and found no entry for an i2c driver. You can use the [UEFITool](https://github.com/LongSoft/UEFITool) and check if your [firmware binary](https://downloads.up-community.org/categories/up-xtreme-uefi-bios/) contains an i2c driver. – MiSimon Jun 30 '22 at 06:10
  • I took a look, and I did not find an instance of an I2c driver, but the up extreme does have an I2c bus. I'm wondering if this means I have to write my own driver or if I am able to use I2cDxe from MdePkg to interact with the I2c Bus @MiSimon. – silkyskate Jun 30 '22 at 16:48
  • I think the I2C drivers from the MdeModulePkg will not work. You need a low level I2C driver for your specific hardware. Writing such a driver is a challenging task. – MiSimon Jun 30 '22 at 19:53
  • It's a shame I'm not experienced enough to write one. Do you see any way to still complete my objective? @MiSimon – silkyskate Jun 30 '22 at 20:16
  • You can use a different board or use linux or windows on your board. – MiSimon Jul 01 '22 at 06:26
  • Have you looked at `.../MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c`? – fpmurphy Jul 01 '22 at 16:14
  • Yes, not noticed that. I am new to UEFI but am I correct to assume I2cHost.c lets me create a handle and hopefully interact with the I2c Bus? Also, if so, how do I use the functions in that file? Would I just include I2cDxe.h? @fpmurphy – silkyskate Jul 01 '22 at 16:47
  • @silkyskate `I2cHost.c` is just a skeleton of a driver for the I2C bus -not a full driver. It is missing a lot of functionality. I strongly suggest you read the UEFI Driver Writers Guide before you go another further. – fpmurphy Jul 02 '22 at 10:26
  • @fpmurphy Very interesting. Thank you for your help – silkyskate Jul 05 '22 at 16:23
  • @silkyskate. A final thought. SMBus, which was developed by Intel, is more or less a proper derivative of the I2C bus. EDK2 contains a fuller implementation of SMBus than I2C. You might be able to repurpose some of the existing SMBus code for your I2C driver. – fpmurphy Jul 05 '22 at 17:53
  • @fpmurphy, no, this is wrong direction. The SMBus controller on the Intel boards is usually covered by i801 IP which is quite different to the Synopsys DesignWare I2C IP that is used for General Purpose I2C communications (so called LPSS, i.e. Low-Power SubSystem). The Linux kernel has drivers for all of them, I believe one can find an EDK-II module for Synopsys hardware, but not 100% sure. – 0andriy Jul 10 '22 at 20:11

1 Answers1

0

not all UEFI features and drivers are supported on each UEFI firmware. try to run the app on different hardwares, and see if they support the protocol.

sadly if the protocol does not exists, you have two options:

  1. to implement the low level api.
  2. find someone who has done what is written in 1.
lior
  • 16
  • 6
  • When you say implement the low level api do you mean write a driver and load it into firmware through the UEFI shell? – silkyskate Sep 16 '22 at 15:35
  • that could be possible, but remember that any type of driver (including DXE and PEI) loaded from UEFI shell, has much less privileges than a signed driver stored in the firmware (if you have an after market system and not a development one). Make sure that the ENTIRE low level api needed can be accessed before implementing the whole driver – lior Sep 17 '22 at 14:29