1# GPIO toggling in ACPI AML for coreboot 2 3## Table of contents 4- Introduction 5- Platform Interface 6- Helper routines 7- Implementation details 8- Arguments and Local Variables Management 9 10## Introduction 11 12ACPI provides platform-independent interfaces enabling the operating 13system to perform power management for devices as well as the entire 14system. An operating system can simply call into Method()s implemented 15by the interface to request different power management operations. In 16order to be able to perform these operations, an interface might 17require toggling of GPIOs. e.g. a touchscreen device interface might 18require toggling of reset-gpio in order to take the device out of 19reset or to put it back into reset. 20 21Thus, any coreboot driver that implements such an ACPI interface might 22require the ability to toggle GPIOs. However, toggling of GPIO is not 23the same across different platforms and it will require the driver to 24depend upon platform to do the required work. This document presents a 25simple interface that can be used by any coreboot driver to generate 26ACPI AML code for reading or toggling platform GPIOs. 27 28## Platform Interface 29 30All platforms that use drivers requiring ACPI AML code for GPIO 31interactions need to be implement the following functions: 321. Return GPIO Rx value if it is acting as input 33 int acpigen_soc_read_rx_gpio(unsigned int gpio_num) 342. Return GPIO Tx value if it is acting as output 35 int acpigen_soc_get_tx_gpio(unsigned int gpio_num) 363. Set GPIO Tx value to 1 if it is acting as output 37 int acpigen_soc_set_tx_gpio(unsigned int gpio_num) 384. Set GPIO Tx value to 0 if it is acting as output 39 int acpigen_soc_clear_tx_gpio(unsigned int gpio_num) 40 41Each of the above functions takes as input gpio_num which is the gpio 42number that needs to be read or toggled and returns an integer which 43is: 441. Error = -1 452. Success = 0 46 47Above callback functions are chosen to be implemented in C rather than 48adding them as AML code callbacks for the following reasons: 491. It is easier to add error prints in C which will inform the 50 developer that these callbacks are missing. It restricts debugging 51 to coreboot logs. 522. GPIO conversion from number to register offset can be easily done 53 in C by reusing implemented functions rather than adding all the 54 logic to AML code or depending upon complicated macros to be added 55 to device-tree. 563. Allows GPIO AML methods to be present under any device scope and 57 gives SoC the flexibility to call them without any restrictions. 58 59## Helper routines 60 61In order to relieve drivers of the task of implementing the same code 62for enabling/disabling Tx GPIOs based on the GPIO polarity, helper 63routines are provided which implement this common code and can be used 64directly in the driver routines: 651. Enable Tx GPIO 66 int acpigen_enable_tx_gpio(struct acpi_gpio gpio) 672. Disable Tx GPIO 68 int acpigen_disable_tx_gpio(struct acpi_gpio gpio) 69 70Both the above functions take as input struct acpi_gpio type and 71return -1 on error and 0 on success. These helper routines end up 72calling the platform specific acpigen_soc_{set,clear}_tx_gpio 73functions internally. Thus, all the ACPI AML calling conventions for 74the platform functions apply to these helper functions as well. 75 763. Get Rx GPIO 77 int acpigen_get_rx_gpio(struct acpi_gpio gpio) 78 79This function takes as input, an struct acpi_gpio type and outputs 80AML code to read the *logical* value of a gpio (after taking its 81polarity into consideration), into the Local0 variable. It calls 82the platform specific acpigen_soc_read_rx_gpio() to actually read 83the raw Rx gpio value. 84 85## Implementation Details 86 87Platforms are restricted to using Local5, Local6 and Local7 variables 88only in implementations of the above functions. Any AML methods called 89by the above functions do not have any such restrictions on use of 90Local variables in AML code. Local0 is to be used for all get/read 91functions to return values. This means that the driver code should not 92make any assumptions about the values in Local5, Local6 and Local7 93variables. 94 95``` 96 **Function** **Operation** **Return** 97 acpigen_soc_read_rx_gpio Generate ACPI AML code to Error = -1 98 read value of Rx in Local0. Success = 0 99 acpigen_soc_get_tx_gpio Generate ACPI AML code to Error = -1 100 get value of Tx in Local0. Success = 0 101 acpigen_soc_set_tx_gpio Generate ACPI AML code to Error = -1 102 set Tx to 1. Success = 0 103 acpigen_soc_clear_tx_gpio Generate ACPI AML code to Error = -1 104 set Tx to 0. Success = 0 105``` 106 107Ideally, the operation column in the above table should use one or 108more functions implemented by the platform in AML code library (like 109gpiolib.asl). In the example below SPC0 and GPC0 need to be 110implemented by the SoC in AML code library and they can be used by 111acpi_soc_set_tx_gpio to read and set bit in the appropriate register 112for the GPIO. 113 114**acpigen_soc_set_tx_gpio** 115 116 uint64_t gpio_reg_offset = gpio_get_reg_offset(gpio_num); 117 118 /* Store (\_SB.GPC0(gpio_reg_offset, Local5) */ 119 acpigen_write_store(); 120 acpigen_emit_namestring(“\\_SB.GPC0”); 121 acpigen_write_integer(gpio_reg_offset); 122 acpigen_emit_byte(LOCAL5_OP); 123 124 125 /* Or (Local5, TX_BIT, Local5) */ 126 acpigen_write_or(LOCAL5_OP, TX_BIT, LOCAL5_OP); 127 128 /* \_SB.SPC0(gpio_reg_offset, LOCAL5) */ 129 acpigen_emit_namestring(“\\_SB.SPC0”); 130 acpigen_write_integer(gpio_reg_offset); 131 acpigen_emit_byte(LOCAL5_OP); 132 133 return 0; 134 135**acpigen_soc_get_tx_gpio** 136 137 uint64_t gpio_reg_offset = gpio_get_reg_offset(gpio_num); 138 139 140 /* Store (\_SB.GPC0(gpio_reg_offset, Local5) */ 141 acpigen_write_store(); 142 acpigen_emit_namestring(“\\_SB.GPC0”); 143 acpigen_write_integer(gpio_reg_offset); 144 acpigen_emit_byte(LOCAL5_OP); 145 146 147 /* 148 * If (And (Local5, TX_BIT)) Store (One, Local0) Else Store (Zero, 149 * Local0) 150 */ 151 acpigen_write_if_and(Local5, TX_BIT); 152 acpigen_write_store_args(ONE_OP, LOCAL0_OP); 153 acpigen_write_else(); 154 acpigen_write_store_args(ZERO_OP, LOCAL0_OP); 155 acpigen_pop_len(); 156 157 return 0; 158 159 160These are reference implementations and the platforms are free to 161implement these functions in any way they like. coreboot driver can 162then simply call into these functions to generate ACPI AML code to 163get/set/clear any GPIO. In order to decide whether GPIO operations are 164required, driver code can rely either on some config option or read 165device-tree to use any user-provided GPIOs. 166 167## Arguments and Local Variables Management 168 169Platform-defined functions can call methods using the same calling 170conventions provided by AML code. However, use of Local Variables is 171restricted to Local5, Local6 and Local7 unless they call into some 172other method. Called method can use any Local variables, Local0 - 173Local7. In case of functions expected to return back value to the 174caller, this value is expected to be returned in Local0. 175 176Driver code should not make any assumptions about the contents of 177Local5, Local6 and Local7 across callbacks to SoC code. If it makes a 178read or get call to SoC, the return value should be used from Local0 179on return. However, if it makes a set or clear call to SoC, the value 180in Local0 is undefined. 181