17fe19072SChangbin Du.. SPDX-License-Identifier: GPL-2.0 27fe19072SChangbin Du 37fe19072SChangbin Du============= 47fe19072SChangbin DuSSDT Overlays 57fe19072SChangbin Du============= 67fe19072SChangbin Du 77fe19072SChangbin DuIn order to support ACPI open-ended hardware configurations (e.g. development 87fe19072SChangbin Duboards) we need a way to augment the ACPI configuration provided by the firmware 97fe19072SChangbin Duimage. A common example is connecting sensors on I2C / SPI buses on development 107fe19072SChangbin Duboards. 117fe19072SChangbin Du 127fe19072SChangbin DuAlthough this can be accomplished by creating a kernel platform driver or 137fe19072SChangbin Durecompiling the firmware image with updated ACPI tables, neither is practical: 147fe19072SChangbin Duthe former proliferates board specific kernel code while the latter requires 157fe19072SChangbin Duaccess to firmware tools which are often not publicly available. 167fe19072SChangbin Du 177fe19072SChangbin DuBecause ACPI supports external references in AML code a more practical 187fe19072SChangbin Duway to augment firmware ACPI configuration is by dynamically loading 197fe19072SChangbin Duuser defined SSDT tables that contain the board specific information. 207fe19072SChangbin Du 217fe19072SChangbin DuFor example, to enumerate a Bosch BMA222E accelerometer on the I2C bus of the 227fe19072SChangbin DuMinnowboard MAX development board exposed via the LSE connector [1], the 237fe19072SChangbin Dufollowing ASL code can be used:: 247fe19072SChangbin Du 257fe19072SChangbin Du DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003) 267fe19072SChangbin Du { 277fe19072SChangbin Du External (\_SB.I2C6, DeviceObj) 287fe19072SChangbin Du 297fe19072SChangbin Du Scope (\_SB.I2C6) 307fe19072SChangbin Du { 317fe19072SChangbin Du Device (STAC) 327fe19072SChangbin Du { 337fe19072SChangbin Du Name (_ADR, Zero) 347fe19072SChangbin Du Name (_HID, "BMA222E") 357fe19072SChangbin Du 367fe19072SChangbin Du Method (_CRS, 0, Serialized) 377fe19072SChangbin Du { 387fe19072SChangbin Du Name (RBUF, ResourceTemplate () 397fe19072SChangbin Du { 407fe19072SChangbin Du I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80, 417fe19072SChangbin Du AddressingMode7Bit, "\\_SB.I2C6", 0x00, 427fe19072SChangbin Du ResourceConsumer, ,) 437fe19072SChangbin Du GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000, 447fe19072SChangbin Du "\\_SB.GPO2", 0x00, ResourceConsumer, , ) 457fe19072SChangbin Du { // Pin list 467fe19072SChangbin Du 0 477fe19072SChangbin Du } 487fe19072SChangbin Du }) 497fe19072SChangbin Du Return (RBUF) 507fe19072SChangbin Du } 517fe19072SChangbin Du } 527fe19072SChangbin Du } 537fe19072SChangbin Du } 547fe19072SChangbin Du 557fe19072SChangbin Duwhich can then be compiled to AML binary format:: 567fe19072SChangbin Du 577fe19072SChangbin Du $ iasl minnowmax.asl 587fe19072SChangbin Du 597fe19072SChangbin Du Intel ACPI Component Architecture 607fe19072SChangbin Du ASL Optimizing Compiler version 20140214-64 [Mar 29 2014] 617fe19072SChangbin Du Copyright (c) 2000 - 2014 Intel Corporation 627fe19072SChangbin Du 637fe19072SChangbin Du ASL Input: minnomax.asl - 30 lines, 614 bytes, 7 keywords 647fe19072SChangbin Du AML Output: minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes 657fe19072SChangbin Du 66*dd9a41bcSFlavio Suligoi[1] https://www.elinux.org/Minnowboard:MinnowMax#Low_Speed_Expansion_.28Top.29 677fe19072SChangbin Du 687fe19072SChangbin DuThe resulting AML code can then be loaded by the kernel using one of the methods 697fe19072SChangbin Dubelow. 707fe19072SChangbin Du 717fe19072SChangbin DuLoading ACPI SSDTs from initrd 727fe19072SChangbin Du============================== 737fe19072SChangbin Du 747fe19072SChangbin DuThis option allows loading of user defined SSDTs from initrd and it is useful 757fe19072SChangbin Duwhen the system does not support EFI or when there is not enough EFI storage. 767fe19072SChangbin Du 777fe19072SChangbin DuIt works in a similar way with initrd based ACPI tables override/upgrade: SSDT 787fe19072SChangbin Duaml code must be placed in the first, uncompressed, initrd under the 797fe19072SChangbin Du"kernel/firmware/acpi" path. Multiple files can be used and this will translate 807fe19072SChangbin Duin loading multiple tables. Only SSDT and OEM tables are allowed. See 817fe19072SChangbin Duinitrd_table_override.txt for more details. 827fe19072SChangbin Du 837fe19072SChangbin DuHere is an example:: 847fe19072SChangbin Du 857fe19072SChangbin Du # Add the raw ACPI tables to an uncompressed cpio archive. 867fe19072SChangbin Du # They must be put into a /kernel/firmware/acpi directory inside the 877fe19072SChangbin Du # cpio archive. 887fe19072SChangbin Du # The uncompressed cpio archive must be the first. 897fe19072SChangbin Du # Other, typically compressed cpio archives, must be 907fe19072SChangbin Du # concatenated on top of the uncompressed one. 917fe19072SChangbin Du mkdir -p kernel/firmware/acpi 927fe19072SChangbin Du cp ssdt.aml kernel/firmware/acpi 937fe19072SChangbin Du 947fe19072SChangbin Du # Create the uncompressed cpio archive and concatenate the original initrd 957fe19072SChangbin Du # on top: 967fe19072SChangbin Du find kernel | cpio -H newc --create > /boot/instrumented_initrd 977fe19072SChangbin Du cat /boot/initrd >>/boot/instrumented_initrd 987fe19072SChangbin Du 997fe19072SChangbin DuLoading ACPI SSDTs from EFI variables 1007fe19072SChangbin Du===================================== 1017fe19072SChangbin Du 1027fe19072SChangbin DuThis is the preferred method, when EFI is supported on the platform, because it 1037fe19072SChangbin Duallows a persistent, OS independent way of storing the user defined SSDTs. There 1047fe19072SChangbin Duis also work underway to implement EFI support for loading user defined SSDTs 1057fe19072SChangbin Duand using this method will make it easier to convert to the EFI loading 1067fe19072SChangbin Dumechanism when that will arrive. 1077fe19072SChangbin Du 1087fe19072SChangbin DuIn order to load SSDTs from an EFI variable the efivar_ssdt kernel command line 1097fe19072SChangbin Duparameter can be used. The argument for the option is the variable name to 1107fe19072SChangbin Duuse. If there are multiple variables with the same name but with different 1117fe19072SChangbin Duvendor GUIDs, all of them will be loaded. 1127fe19072SChangbin Du 1137fe19072SChangbin DuIn order to store the AML code in an EFI variable the efivarfs filesystem can be 1147fe19072SChangbin Duused. It is enabled and mounted by default in /sys/firmware/efi/efivars in all 1157fe19072SChangbin Durecent distribution. 1167fe19072SChangbin Du 1177fe19072SChangbin DuCreating a new file in /sys/firmware/efi/efivars will automatically create a new 1187fe19072SChangbin DuEFI variable. Updating a file in /sys/firmware/efi/efivars will update the EFI 1197fe19072SChangbin Duvariable. Please note that the file name needs to be specially formatted as 1207fe19072SChangbin Du"Name-GUID" and that the first 4 bytes in the file (little-endian format) 1217fe19072SChangbin Durepresent the attributes of the EFI variable (see EFI_VARIABLE_MASK in 1227fe19072SChangbin Duinclude/linux/efi.h). Writing to the file must also be done with one write 1237fe19072SChangbin Duoperation. 1247fe19072SChangbin Du 1257fe19072SChangbin DuFor example, you can use the following bash script to create/update an EFI 1267fe19072SChangbin Duvariable with the content from a given file:: 1277fe19072SChangbin Du 1287fe19072SChangbin Du #!/bin/sh -e 1297fe19072SChangbin Du 1307fe19072SChangbin Du while ! [ -z "$1" ]; do 1317fe19072SChangbin Du case "$1" in 1327fe19072SChangbin Du "-f") filename="$2"; shift;; 1337fe19072SChangbin Du "-g") guid="$2"; shift;; 1347fe19072SChangbin Du *) name="$1";; 1357fe19072SChangbin Du esac 1367fe19072SChangbin Du shift 1377fe19072SChangbin Du done 1387fe19072SChangbin Du 1397fe19072SChangbin Du usage() 1407fe19072SChangbin Du { 1417fe19072SChangbin Du echo "Syntax: ${0##*/} -f filename [ -g guid ] name" 1427fe19072SChangbin Du exit 1 1437fe19072SChangbin Du } 1447fe19072SChangbin Du 1457fe19072SChangbin Du [ -n "$name" -a -f "$filename" ] || usage 1467fe19072SChangbin Du 1477fe19072SChangbin Du EFIVARFS="/sys/firmware/efi/efivars" 1487fe19072SChangbin Du 1497fe19072SChangbin Du [ -d "$EFIVARFS" ] || exit 2 1507fe19072SChangbin Du 1517fe19072SChangbin Du if stat -tf $EFIVARFS | grep -q -v de5e81e4; then 1527fe19072SChangbin Du mount -t efivarfs none $EFIVARFS 1537fe19072SChangbin Du fi 1547fe19072SChangbin Du 1557fe19072SChangbin Du # try to pick up an existing GUID 1567fe19072SChangbin Du [ -n "$guid" ] || guid=$(find "$EFIVARFS" -name "$name-*" | head -n1 | cut -f2- -d-) 1577fe19072SChangbin Du 1587fe19072SChangbin Du # use a randomly generated GUID 1597fe19072SChangbin Du [ -n "$guid" ] || guid="$(cat /proc/sys/kernel/random/uuid)" 1607fe19072SChangbin Du 1617fe19072SChangbin Du # efivarfs expects all of the data in one write 1627fe19072SChangbin Du tmp=$(mktemp) 1637fe19072SChangbin Du /bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp 1647fe19072SChangbin Du dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp) 1657fe19072SChangbin Du rm $tmp 1667fe19072SChangbin Du 1677fe19072SChangbin DuLoading ACPI SSDTs from configfs 1687fe19072SChangbin Du================================ 1697fe19072SChangbin Du 1707fe19072SChangbin DuThis option allows loading of user defined SSDTs from userspace via the configfs 1717fe19072SChangbin Duinterface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be 1727fe19072SChangbin Dumounted. In the following examples, we assume that configfs has been mounted in 1737fe19072SChangbin Du/config. 1747fe19072SChangbin Du 1757fe19072SChangbin DuNew tables can be loading by creating new directories in /config/acpi/table/ and 1767fe19072SChangbin Duwriting the SSDT aml code in the aml attribute:: 1777fe19072SChangbin Du 1787fe19072SChangbin Du cd /config/acpi/table 1797fe19072SChangbin Du mkdir my_ssdt 1807fe19072SChangbin Du cat ~/ssdt.aml > my_ssdt/aml 181