162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci=============
462306a36Sopenharmony_ciSSDT Overlays
562306a36Sopenharmony_ci=============
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciIn order to support ACPI open-ended hardware configurations (e.g. development
862306a36Sopenharmony_ciboards) we need a way to augment the ACPI configuration provided by the firmware
962306a36Sopenharmony_ciimage. A common example is connecting sensors on I2C / SPI buses on development
1062306a36Sopenharmony_ciboards.
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciAlthough this can be accomplished by creating a kernel platform driver or
1362306a36Sopenharmony_cirecompiling the firmware image with updated ACPI tables, neither is practical:
1462306a36Sopenharmony_cithe former proliferates board specific kernel code while the latter requires
1562306a36Sopenharmony_ciaccess to firmware tools which are often not publicly available.
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciBecause ACPI supports external references in AML code a more practical
1862306a36Sopenharmony_ciway to augment firmware ACPI configuration is by dynamically loading
1962306a36Sopenharmony_ciuser defined SSDT tables that contain the board specific information.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciFor example, to enumerate a Bosch BMA222E accelerometer on the I2C bus of the
2262306a36Sopenharmony_ciMinnowboard MAX development board exposed via the LSE connector [1], the
2362306a36Sopenharmony_cifollowing ASL code can be used::
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci    DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003)
2662306a36Sopenharmony_ci    {
2762306a36Sopenharmony_ci        External (\_SB.I2C6, DeviceObj)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci        Scope (\_SB.I2C6)
3062306a36Sopenharmony_ci        {
3162306a36Sopenharmony_ci            Device (STAC)
3262306a36Sopenharmony_ci            {
3362306a36Sopenharmony_ci                Name (_HID, "BMA222E")
3462306a36Sopenharmony_ci                Name (RBUF, ResourceTemplate ()
3562306a36Sopenharmony_ci                {
3662306a36Sopenharmony_ci                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
3762306a36Sopenharmony_ci                                AddressingMode7Bit, "\\_SB.I2C6", 0x00,
3862306a36Sopenharmony_ci                                ResourceConsumer, ,)
3962306a36Sopenharmony_ci                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
4062306a36Sopenharmony_ci                            "\\_SB.GPO2", 0x00, ResourceConsumer, , )
4162306a36Sopenharmony_ci                    { // Pin list
4262306a36Sopenharmony_ci                        0
4362306a36Sopenharmony_ci                    }
4462306a36Sopenharmony_ci                })
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci                Method (_CRS, 0, Serialized)
4762306a36Sopenharmony_ci                {
4862306a36Sopenharmony_ci                    Return (RBUF)
4962306a36Sopenharmony_ci                }
5062306a36Sopenharmony_ci            }
5162306a36Sopenharmony_ci        }
5262306a36Sopenharmony_ci    }
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciwhich can then be compiled to AML binary format::
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci    $ iasl minnowmax.asl
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci    Intel ACPI Component Architecture
5962306a36Sopenharmony_ci    ASL Optimizing Compiler version 20140214-64 [Mar 29 2014]
6062306a36Sopenharmony_ci    Copyright (c) 2000 - 2014 Intel Corporation
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci    ASL Input:     minnomax.asl - 30 lines, 614 bytes, 7 keywords
6362306a36Sopenharmony_ci    AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci[1] https://www.elinux.org/Minnowboard:MinnowMax#Low_Speed_Expansion_.28Top.29
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciThe resulting AML code can then be loaded by the kernel using one of the methods
6862306a36Sopenharmony_cibelow.
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciLoading ACPI SSDTs from initrd
7162306a36Sopenharmony_ci==============================
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciThis option allows loading of user defined SSDTs from initrd and it is useful
7462306a36Sopenharmony_ciwhen the system does not support EFI or when there is not enough EFI storage.
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciIt works in a similar way with initrd based ACPI tables override/upgrade: SSDT
7762306a36Sopenharmony_ciAML code must be placed in the first, uncompressed, initrd under the
7862306a36Sopenharmony_ci"kernel/firmware/acpi" path. Multiple files can be used and this will translate
7962306a36Sopenharmony_ciin loading multiple tables. Only SSDT and OEM tables are allowed. See
8062306a36Sopenharmony_ciinitrd_table_override.txt for more details.
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ciHere is an example::
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci    # Add the raw ACPI tables to an uncompressed cpio archive.
8562306a36Sopenharmony_ci    # They must be put into a /kernel/firmware/acpi directory inside the
8662306a36Sopenharmony_ci    # cpio archive.
8762306a36Sopenharmony_ci    # The uncompressed cpio archive must be the first.
8862306a36Sopenharmony_ci    # Other, typically compressed cpio archives, must be
8962306a36Sopenharmony_ci    # concatenated on top of the uncompressed one.
9062306a36Sopenharmony_ci    mkdir -p kernel/firmware/acpi
9162306a36Sopenharmony_ci    cp ssdt.aml kernel/firmware/acpi
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci    # Create the uncompressed cpio archive and concatenate the original initrd
9462306a36Sopenharmony_ci    # on top:
9562306a36Sopenharmony_ci    find kernel | cpio -H newc --create > /boot/instrumented_initrd
9662306a36Sopenharmony_ci    cat /boot/initrd >>/boot/instrumented_initrd
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciLoading ACPI SSDTs from EFI variables
9962306a36Sopenharmony_ci=====================================
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciThis is the preferred method, when EFI is supported on the platform, because it
10262306a36Sopenharmony_ciallows a persistent, OS independent way of storing the user defined SSDTs. There
10362306a36Sopenharmony_ciis also work underway to implement EFI support for loading user defined SSDTs
10462306a36Sopenharmony_ciand using this method will make it easier to convert to the EFI loading
10562306a36Sopenharmony_cimechanism when that will arrive. To enable it, the
10662306a36Sopenharmony_ciCONFIG_EFI_CUSTOM_SSDT_OVERLAYS should be chosen to y.
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciIn order to load SSDTs from an EFI variable the ``"efivar_ssdt=..."`` kernel
10962306a36Sopenharmony_cicommand line parameter can be used (the name has a limitation of 16 characters).
11062306a36Sopenharmony_ciThe argument for the option is the variable name to use. If there are multiple
11162306a36Sopenharmony_civariables with the same name but with different vendor GUIDs, all of them will
11262306a36Sopenharmony_cibe loaded.
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciIn order to store the AML code in an EFI variable the efivarfs filesystem can be
11562306a36Sopenharmony_ciused. It is enabled and mounted by default in /sys/firmware/efi/efivars in all
11662306a36Sopenharmony_cirecent distribution.
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciCreating a new file in /sys/firmware/efi/efivars will automatically create a new
11962306a36Sopenharmony_ciEFI variable. Updating a file in /sys/firmware/efi/efivars will update the EFI
12062306a36Sopenharmony_civariable. Please note that the file name needs to be specially formatted as
12162306a36Sopenharmony_ci"Name-GUID" and that the first 4 bytes in the file (little-endian format)
12262306a36Sopenharmony_cirepresent the attributes of the EFI variable (see EFI_VARIABLE_MASK in
12362306a36Sopenharmony_ciinclude/linux/efi.h). Writing to the file must also be done with one write
12462306a36Sopenharmony_cioperation.
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciFor example, you can use the following bash script to create/update an EFI
12762306a36Sopenharmony_civariable with the content from a given file::
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci    #!/bin/sh -e
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci    while [ -n "$1" ]; do
13262306a36Sopenharmony_ci            case "$1" in
13362306a36Sopenharmony_ci            "-f") filename="$2"; shift;;
13462306a36Sopenharmony_ci            "-g") guid="$2"; shift;;
13562306a36Sopenharmony_ci            *) name="$1";;
13662306a36Sopenharmony_ci            esac
13762306a36Sopenharmony_ci            shift
13862306a36Sopenharmony_ci    done
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci    usage()
14162306a36Sopenharmony_ci    {
14262306a36Sopenharmony_ci            echo "Syntax: ${0##*/} -f filename [ -g guid ] name"
14362306a36Sopenharmony_ci            exit 1
14462306a36Sopenharmony_ci    }
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci    [ -n "$name" -a -f "$filename" ] || usage
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    EFIVARFS="/sys/firmware/efi/efivars"
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci    [ -d "$EFIVARFS" ] || exit 2
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci    if stat -tf $EFIVARFS | grep -q -v de5e81e4; then
15362306a36Sopenharmony_ci            mount -t efivarfs none $EFIVARFS
15462306a36Sopenharmony_ci    fi
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci    # try to pick up an existing GUID
15762306a36Sopenharmony_ci    [ -n "$guid" ] || guid=$(find "$EFIVARFS" -name "$name-*" | head -n1 | cut -f2- -d-)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci    # use a randomly generated GUID
16062306a36Sopenharmony_ci    [ -n "$guid" ] || guid="$(cat /proc/sys/kernel/random/uuid)"
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci    # efivarfs expects all of the data in one write
16362306a36Sopenharmony_ci    tmp=$(mktemp)
16462306a36Sopenharmony_ci    /bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp
16562306a36Sopenharmony_ci    dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp)
16662306a36Sopenharmony_ci    rm $tmp
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciLoading ACPI SSDTs from configfs
16962306a36Sopenharmony_ci================================
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciThis option allows loading of user defined SSDTs from user space via the configfs
17262306a36Sopenharmony_ciinterface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be
17362306a36Sopenharmony_cimounted. In the following examples, we assume that configfs has been mounted in
17462306a36Sopenharmony_ci/sys/kernel/config.
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciNew tables can be loading by creating new directories in /sys/kernel/config/acpi/table
17762306a36Sopenharmony_ciand writing the SSDT AML code in the aml attribute::
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci    cd /sys/kernel/config/acpi/table
18062306a36Sopenharmony_ci    mkdir my_ssdt
18162306a36Sopenharmony_ci    cat ~/ssdt.aml > my_ssdt/aml
182