ACPI: Adding Devices Without Kernel Recompilation

    As it turns out, far few are aware of the existence of an overlay mode in ACPICA and their support in Linux. I want to fill this gap with the example of adding I2C slaves to the system without recompiling.

    Initial conditions


    Let's say at startup

    i2cdetect -y -r 0

    we have the following picture:

    I2cdetect output
         0 1 2 3 4 5 6 7 8 9 abcdef
    00: - - - - - - - - - - - - - 
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
    thirty: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
    40: - - - - - - - - - - - - - - - - - 
    50: - - - 53 - - - 57 - - - - - - - - 
    60: - - - - - - - - - - - - - - - - - 
    70: - - - - - - - -                         
    


    where the ADXL345 accelerometer is detected at address 0x53, and the 24c128 memory EEPROM chip is located at address 0x57. Descriptions of these devices are not available in ACPI, namely in the DSDT table .

    Add ADXL345 Accelerometer


    All we need to know here is the address at which the device responds, its IDs supported by the driver, the frequency of the bus on which it should work. Please note that the frequency of the I2C bus on the driver side is often set to the minimum that is supported by all slave devices on this bus!

    Oh yes, there was a time when the IIO subsystem did not exist, and the ADXL345 driver already existed. So, we are using a new one that is available through the IIO subsystem.

    Total

    • Address: 0x53
    • Bus Frequency: 400kHz
    • Link to master (controller) device: \ _SB.PCI0.I2C1
    • ID: adi, adxl345

    It should be noted that we use a special identifier here, which is intended for systems with OF . As a layer in ACPI, a special identifier PRP0001 was added , which ensures compatibility with drivers written earlier for OF.

    We translate the received information into ASL :

    ASL Code for ADXL345 Accelerometer
    DefinitionBlock ("adxl345.aml", "SSDT", 5, "", "ADXL345", 1)
    {
        External (_SB_.PCI0.I2C1, DeviceObj)
        Scope (\_SB.PCI0.I2C1)
        {
            Device (ACL0) {
                Name (_HID, "PRP0001")
                Name (_DDN, "Analog Devices ADXL345 3-axis accelerometer")
                Name (_CRS, ResourceTemplate () {
                    I2cSerialBusV2 (
                        0x0053,              // I2C Slave Address
                        ControllerInitiated,
                        400000,              // Bus speed
                        AddressingMode7Bit,
                        "\\_SB.PCI0.I2C1",   // Link to ACPI I2C host controller
                        0
                    )
                })
                Name (_DSD, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package () { "compatible", "adi,adxl345" },
                    }
                })
            }
        }
    }
    


    Add EEPROM 24c128


    As in the previous case, we obtain the necessary information about the device and its driver:

    • Address: 0x57
    • Bus Frequency: 400kHz
    • Link to master (controller) device: \ _SB.PCI0.I2C1
    • ID number: INT3499
    • Volume: 1024
    • Page Size: 32

    ASL code for EEPROM 24c128
    DefinitionBlock ("at24.aml", "SSDT", 5, "", "AT24", 1)
    {
        External (_SB_.PCI0.I2C1, DeviceObj)
        Scope (\_SB.PCI0.I2C1)
        {
            Device (EEP0) {
                Name (_HID, "INT3499")
                Name (_DDN, "Atmel AT24 compatible EEPROM")
                Name (_CRS, ResourceTemplate () {
                    I2cSerialBusV2 (
                        0x0057,              // I2C Slave Address
                        ControllerInitiated,
                        400000,              // Bus speed
                        AddressingMode7Bit,
                        "\\_SB.PCI0.I2C1",   // Link to ACPI I2C host controller
                        0
                    )
                })
                Name (_DSD, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package () { "size", 1024 },
                        Package () { "pagesize", 32 },
                    }
                })
            }
        }
    }
    


    Notice the difference with the previous option. It uses the ACPI ID directly, which is allocated in the space controlled by Intel, thanks to the Intel Galileo platform. The second difference, we pass additional device parameters in the form of key-value strings.

    Possible initialization options


    What now to do with all this? The algorithm is simple. First, you need to compile the resulting files into ASL bytecode. Achieved by calling a command

    iasl adxl345.asl

    and by analogy for EEPROM. Secondly, choose a way to initialize the newly made table. There are actually three of them: 1) joining initramfs, 2) loading on the working system via ConfigFS, 3) loading the table from the EFI variable. Consider the first two of them below.

    Joining initramfs

    We will not do anything with the initramfs archive itself , however, it is recommended that you save the original somewhere aside.

    
    # Добавляем ACPI таблицы в некомпрессированный cpio архив.
    # Они обязаны находится в подкаталоге /kernel/firmware/acpi внутри архива.
    # Некомпрессированные архивы должны идти первыми в цепочке.
    mkdir -p kernel/firmware/acpi
    cp adxl345.aml kernel/firmware/acpi
    cp at24.aml kernel/firmware/acpi
    # Создаём архив и цепочкой к нему присоединяем оригинальный initramfs:
    find kernel | cpio -H newc --create > /boot/instrumented_initramfs-vX.Y
    cat /boot/initramfs-vX.Y >> /boot/instrumented_initramfs-vX.Y
    

    After this procedure, you can replace the old archive with a new one and restart the computer.
    Something like this should appear in the dmesg output:

    [    0.000000] ACPI: Table Upgrade: install [SSDT-      - ADXL345]
    [    0.000000] ACPI: SSDT 0x000000003F4FF5C4 0000A6 (v05       ADXL345   00000001 INTL 20170303)
    

    Note that the kernel only supports a chain of up to 64 such archives.

    Download via ConfigFS

    This feature is available when the kernel is compiled with the CONFIG_ACPI_CONFIGFS option and ConfigFS is mounted. Assuming it is mounted in the / sys / kernel / config subdirectory , the following example shows how to load a table.

    
    cd /sys/kernel/config/acpi/table
    mkdir adxl345
    cat ~/adxl354.aml > adxl345/aml
    

    Conclusion


    Although ASL requires more brackets than analogs, it nevertheless provides no less opportunities to describe devices. So, there are a number of examples in the meta-acpi project , where in particular you can find descriptions of LEDs and buttons connected to GPIO lines, memory chips, and even a description of the Adafruit 2.8 " module - TFT display with a touch screen!

    Also popular now: