Angel Pons | ae59387 | 2020-04-04 18:50:57 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 2 | |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 3 | #include <acpi/acpi_pm.h> |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 4 | #include <device/mmio.h> |
| 5 | #include <device/device.h> |
| 6 | #include <console/console.h> |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 7 | #include <elog.h> |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 8 | #include <gpio.h> |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 9 | #include <amdblocks/acpi.h> |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 10 | #include <amdblocks/acpimmio.h> |
Felix Held | dea4e0f | 2021-09-22 20:05:53 +0200 | [diff] [blame] | 11 | #include <amdblocks/gpio.h> |
Felix Held | a5a5295 | 2020-12-01 18:14:01 +0100 | [diff] [blame] | 12 | #include <amdblocks/smi.h> |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 13 | #include <soc/gpio.h> |
| 14 | #include <soc/smi.h> |
| 15 | #include <assert.h> |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 16 | #include <string.h> |
Felix Held | 16ae682 | 2021-09-20 21:15:13 +0200 | [diff] [blame] | 17 | #include <types.h> |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 18 | |
Felix Held | 8b76000 | 2021-08-05 16:12:01 +0200 | [diff] [blame] | 19 | /* |
| 20 | * acpimmio_gpio0, acpimmio_remote_gpio and acpimmio_iomux are defined in |
| 21 | * soc/amd/common/block/acpimmio/mmio_util.c and declared as extern variables/constants in |
| 22 | * amdblocks/acpimmio.h which is included in this file. |
| 23 | */ |
| 24 | |
Felix Held | f5658cf | 2021-08-03 03:15:27 +0200 | [diff] [blame] | 25 | /* MMIO access of new-style GPIO bank configuration registers */ |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 26 | static inline void *gpio_ctrl_ptr(gpio_t gpio_num) |
Felix Held | f5658cf | 2021-08-03 03:15:27 +0200 | [diff] [blame] | 27 | { |
Felix Held | b4fe8c5 | 2021-07-28 21:24:40 +0200 | [diff] [blame] | 28 | if (SOC_GPIO_TOTAL_PINS < AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER || |
| 29 | /* Verstage on PSP would need to map acpimmio_remote_gpio */ |
| 30 | (CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK) && ENV_SEPARATE_VERSTAGE) || |
| 31 | gpio_num < AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER) |
| 32 | return acpimmio_gpio0 + gpio_num * sizeof(uint32_t); |
| 33 | else |
| 34 | return acpimmio_remote_gpio + |
| 35 | (gpio_num - AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER) * sizeof(uint32_t); |
Felix Held | f5658cf | 2021-08-03 03:15:27 +0200 | [diff] [blame] | 36 | } |
| 37 | |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 38 | static inline uint32_t gpio_read32(gpio_t gpio_num) |
Felix Held | f5658cf | 2021-08-03 03:15:27 +0200 | [diff] [blame] | 39 | { |
| 40 | return read32(gpio_ctrl_ptr(gpio_num)); |
| 41 | } |
| 42 | |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 43 | static inline void gpio_write32(gpio_t gpio_num, uint32_t value) |
Felix Held | f5658cf | 2021-08-03 03:15:27 +0200 | [diff] [blame] | 44 | { |
| 45 | write32(gpio_ctrl_ptr(gpio_num), value); |
| 46 | } |
| 47 | |
Felix Held | aa9ad05 | 2021-08-04 01:57:38 +0200 | [diff] [blame] | 48 | static inline void *gpio_mux_ptr(gpio_t gpio_num) |
Felix Held | 85e733f | 2021-08-03 18:42:04 +0200 | [diff] [blame] | 49 | { |
Felix Held | b4fe8c5 | 2021-07-28 21:24:40 +0200 | [diff] [blame] | 50 | if (SOC_GPIO_TOTAL_PINS < AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER || |
| 51 | /* Verstage on PSP would need to map acpimmio_remote_gpio */ |
| 52 | (CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK) && ENV_SEPARATE_VERSTAGE) || |
| 53 | gpio_num < AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER) |
| 54 | return acpimmio_iomux + gpio_num; |
| 55 | else |
| 56 | return acpimmio_remote_gpio + AMD_GPIO_REMOTE_GPIO_MUX_OFFSET + |
| 57 | (gpio_num - AMD_GPIO_FIRST_REMOTE_GPIO_NUMBER); |
Felix Held | 85e733f | 2021-08-03 18:42:04 +0200 | [diff] [blame] | 58 | } |
| 59 | |
Felix Held | b7f0563 | 2021-08-05 15:52:46 +0200 | [diff] [blame] | 60 | static uint8_t get_gpio_mux(gpio_t gpio_num) |
Felix Held | 85e733f | 2021-08-03 18:42:04 +0200 | [diff] [blame] | 61 | { |
Felix Held | aa9ad05 | 2021-08-04 01:57:38 +0200 | [diff] [blame] | 62 | return read8(gpio_mux_ptr(gpio_num)); |
| 63 | } |
| 64 | |
Felix Held | b7f0563 | 2021-08-05 15:52:46 +0200 | [diff] [blame] | 65 | static void set_gpio_mux(gpio_t gpio_num, uint8_t function) |
Felix Held | aa9ad05 | 2021-08-04 01:57:38 +0200 | [diff] [blame] | 66 | { |
Felix Held | b7f0563 | 2021-08-05 15:52:46 +0200 | [diff] [blame] | 67 | write8(gpio_mux_ptr(gpio_num), function & AMD_GPIO_MUX_MASK); |
| 68 | get_gpio_mux(gpio_num); /* Flush posted write */ |
Felix Held | ad38ac01 | 2021-08-03 15:53:36 +0200 | [diff] [blame] | 69 | } |
| 70 | |
Felix Held | 298150d | 2021-07-28 17:36:46 +0200 | [diff] [blame] | 71 | static int get_gpio_gevent(gpio_t gpio, const struct soc_amd_event *table, |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 72 | size_t items) |
| 73 | { |
Felix Held | 75196bf | 2021-07-30 03:09:25 +0200 | [diff] [blame] | 74 | size_t i; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 75 | |
| 76 | for (i = 0; i < items; i++) { |
| 77 | if ((table + i)->gpio == gpio) |
| 78 | return (int)(table + i)->event; |
| 79 | } |
| 80 | return -1; |
| 81 | } |
| 82 | |
Felix Held | f80e6d6 | 2021-07-30 03:26:15 +0200 | [diff] [blame] | 83 | static void program_smi(uint32_t flags, unsigned int gevent_num) |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 84 | { |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 85 | uint8_t level; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 86 | |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 87 | if (!is_gpio_event_level_triggered(flags)) { |
| 88 | printk(BIOS_ERR, "ERROR: %s - Only level trigger allowed for SMI!\n", __func__); |
Julius Werner | 3e034b6 | 2020-07-29 17:39:21 -0700 | [diff] [blame] | 89 | BUG(); |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 90 | return; |
| 91 | } |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 92 | |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 93 | if (is_gpio_event_active_high(flags)) |
| 94 | level = SMI_SCI_LVL_HIGH; |
| 95 | else |
| 96 | level = SMI_SCI_LVL_LOW; |
| 97 | |
| 98 | configure_gevent_smi(gevent_num, SMI_MODE_SMI, level); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 99 | } |
| 100 | |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 101 | /* |
| 102 | * For each general purpose event, GPE, the choice of edge/level triggered |
| 103 | * event is represented as a single bit in SMI_SCI_LEVEL register. |
| 104 | * |
| 105 | * In a similar fashion, polarity (rising/falling, hi/lo) of each GPE is |
| 106 | * represented as a single bit in SMI_SCI_TRIG register. |
| 107 | */ |
Felix Held | f80e6d6 | 2021-07-30 03:26:15 +0200 | [diff] [blame] | 108 | static void program_sci(uint32_t flags, unsigned int gevent_num) |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 109 | { |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 110 | struct sci_source sci; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 111 | |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 112 | sci.scimap = gevent_num; |
| 113 | sci.gpe = gevent_num; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 114 | |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 115 | if (is_gpio_event_level_triggered(flags)) |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 116 | sci.level = SMI_SCI_LVL; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 117 | else |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 118 | sci.level = SMI_SCI_EDG; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 119 | |
Furquan Shaikh | af8123c | 2020-06-26 18:55:17 -0700 | [diff] [blame] | 120 | if (is_gpio_event_active_high(flags)) |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 121 | sci.direction = SMI_SCI_LVL_HIGH; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 122 | else |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 123 | sci.direction = SMI_SCI_LVL_LOW; |
Kyösti Mälkki | c4f5e4e | 2020-06-22 12:03:51 +0300 | [diff] [blame] | 124 | |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 125 | configure_scimap(&sci); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 126 | } |
| 127 | |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 128 | static void gpio_update32(gpio_t gpio_num, uint32_t mask, uint32_t or) |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 129 | { |
| 130 | uint32_t reg; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 131 | |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 132 | reg = gpio_read32(gpio_num); |
| 133 | reg &= mask; |
| 134 | reg |= or; |
| 135 | gpio_write32(gpio_num, reg); |
| 136 | } |
| 137 | |
Furquan Shaikh | 05726e8 | 2020-06-30 10:35:27 -0700 | [diff] [blame] | 138 | /* Set specified bits of a register to match those of ctrl. */ |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 139 | static void gpio_setbits32(gpio_t gpio_num, uint32_t mask, uint32_t ctrl) |
Furquan Shaikh | 05726e8 | 2020-06-30 10:35:27 -0700 | [diff] [blame] | 140 | { |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 141 | gpio_update32(gpio_num, ~mask, ctrl & mask); |
Furquan Shaikh | 05726e8 | 2020-06-30 10:35:27 -0700 | [diff] [blame] | 142 | } |
| 143 | |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 144 | static void gpio_and32(gpio_t gpio_num, uint32_t mask) |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 145 | { |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 146 | gpio_update32(gpio_num, mask, 0); |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 147 | } |
| 148 | |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 149 | static void gpio_or32(gpio_t gpio_num, uint32_t or) |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 150 | { |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 151 | gpio_update32(gpio_num, -1UL, or); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 152 | } |
| 153 | |
Kyösti Mälkki | 419c690 | 2020-06-22 08:06:52 +0300 | [diff] [blame] | 154 | static void master_switch_clr(uint32_t mask) |
| 155 | { |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 156 | const gpio_t master_reg = GPIO_MASTER_SWITCH / sizeof(uint32_t); |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 157 | gpio_and32(master_reg, ~mask); |
Kyösti Mälkki | 419c690 | 2020-06-22 08:06:52 +0300 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | static void master_switch_set(uint32_t or) |
| 161 | { |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 162 | const gpio_t master_reg = GPIO_MASTER_SWITCH / sizeof(uint32_t); |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 163 | gpio_or32(master_reg, or); |
Kyösti Mälkki | 419c690 | 2020-06-22 08:06:52 +0300 | [diff] [blame] | 164 | } |
| 165 | |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 166 | int gpio_get(gpio_t gpio_num) |
| 167 | { |
| 168 | uint32_t reg; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 169 | |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 170 | reg = gpio_read32(gpio_num); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 171 | return !!(reg & GPIO_PIN_STS); |
| 172 | } |
| 173 | |
| 174 | void gpio_set(gpio_t gpio_num, int value) |
| 175 | { |
Kyösti Mälkki | 4135395 | 2020-06-22 18:50:55 +0300 | [diff] [blame] | 176 | gpio_setbits32(gpio_num, GPIO_OUTPUT_VALUE, value ? GPIO_OUTPUT_VALUE : 0); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | void gpio_input_pulldown(gpio_t gpio_num) |
| 180 | { |
Felix Held | a1f254b | 2021-01-05 00:36:51 +0100 | [diff] [blame] | 181 | gpio_setbits32(gpio_num, GPIO_PULL_MASK | GPIO_OUTPUT_ENABLE, GPIO_PULLDOWN_ENABLE); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | void gpio_input_pullup(gpio_t gpio_num) |
| 185 | { |
Felix Held | a1f254b | 2021-01-05 00:36:51 +0100 | [diff] [blame] | 186 | gpio_setbits32(gpio_num, GPIO_PULL_MASK | GPIO_OUTPUT_ENABLE, GPIO_PULLUP_ENABLE); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | void gpio_input(gpio_t gpio_num) |
| 190 | { |
Felix Held | dec00dd | 2021-01-05 00:32:25 +0100 | [diff] [blame] | 191 | gpio_and32(gpio_num, ~(GPIO_PULL_MASK | GPIO_OUTPUT_ENABLE)); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | void gpio_output(gpio_t gpio_num, int value) |
| 195 | { |
Felix Held | 15dd9b8 | 2021-01-05 00:17:56 +0100 | [diff] [blame] | 196 | /* set GPIO output value before setting the direction to output to avoid glitches */ |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 197 | gpio_set(gpio_num, value); |
Felix Held | 15dd9b8 | 2021-01-05 00:17:56 +0100 | [diff] [blame] | 198 | gpio_or32(gpio_num, GPIO_OUTPUT_ENABLE); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | const char *gpio_acpi_path(gpio_t gpio) |
| 202 | { |
| 203 | return "\\_SB.GPIO"; |
| 204 | } |
| 205 | |
| 206 | uint16_t gpio_acpi_pin(gpio_t gpio) |
| 207 | { |
| 208 | return gpio; |
| 209 | } |
| 210 | |
Felix Held | 35cee38 | 2021-08-03 02:55:34 +0200 | [diff] [blame] | 211 | void gpio_save_pin_registers(gpio_t gpio, struct soc_amd_gpio_register_save *save) |
| 212 | { |
Felix Held | 029a4a0 | 2021-08-03 03:36:53 +0200 | [diff] [blame] | 213 | save->mux_value = get_gpio_mux(gpio); |
Felix Held | 35cee38 | 2021-08-03 02:55:34 +0200 | [diff] [blame] | 214 | save->control_value = gpio_read32(gpio); |
| 215 | } |
| 216 | |
| 217 | void gpio_restore_pin_registers(gpio_t gpio, struct soc_amd_gpio_register_save *save) |
| 218 | { |
| 219 | set_gpio_mux(gpio, save->mux_value); |
| 220 | gpio_write32(gpio, save->control_value); |
| 221 | gpio_read32(gpio); /* Flush posted write */ |
| 222 | } |
| 223 | |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 224 | static void set_single_gpio(const struct soc_amd_gpio *g) |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 225 | { |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 226 | static const struct soc_amd_event *gev_tbl; |
| 227 | static size_t gev_items; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 228 | int gevent_num; |
Felix Held | 4b02769 | 2021-08-03 20:09:54 +0200 | [diff] [blame] | 229 | const bool can_set_smi_flags = !((CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK) && |
| 230 | ENV_SEPARATE_VERSTAGE) || |
| 231 | CONFIG(SOC_AMD_COMMON_BLOCK_BANKED_GPIOS_NON_SOC_CODEBASE)); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 232 | |
Felix Held | 21813c3 | 2021-07-28 20:30:17 +0200 | [diff] [blame] | 233 | set_gpio_mux(g->gpio, g->function); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 234 | |
Kyösti Mälkki | 0589e3c | 2020-06-22 13:35:35 +0300 | [diff] [blame] | 235 | gpio_setbits32(g->gpio, PAD_CFG_MASK, g->control); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 236 | /* Clear interrupt and wake status (write 1-to-clear bits) */ |
Kyösti Mälkki | 0589e3c | 2020-06-22 13:35:35 +0300 | [diff] [blame] | 237 | gpio_or32(g->gpio, GPIO_INT_STATUS | GPIO_WAKE_STATUS); |
| 238 | if (g->flags == 0) |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 239 | return; |
| 240 | |
| 241 | /* Can't set SMI flags from PSP */ |
| 242 | if (!can_set_smi_flags) |
| 243 | return; |
| 244 | |
| 245 | if (gev_tbl == NULL) |
| 246 | soc_get_gpio_event_table(&gev_tbl, &gev_items); |
| 247 | |
Kyösti Mälkki | 0589e3c | 2020-06-22 13:35:35 +0300 | [diff] [blame] | 248 | gevent_num = get_gpio_gevent(g->gpio, gev_tbl, gev_items); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 249 | if (gevent_num < 0) { |
| 250 | printk(BIOS_WARNING, "Warning: GPIO pin %d has no associated gevent!\n", |
Kyösti Mälkki | 0589e3c | 2020-06-22 13:35:35 +0300 | [diff] [blame] | 251 | g->gpio); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 252 | return; |
| 253 | } |
| 254 | |
Kyösti Mälkki | 0589e3c | 2020-06-22 13:35:35 +0300 | [diff] [blame] | 255 | if (g->flags & GPIO_FLAG_SMI) { |
| 256 | program_smi(g->flags, gevent_num); |
| 257 | } else if (g->flags & GPIO_FLAG_SCI) { |
Kyösti Mälkki | 31d49ec | 2020-07-02 20:46:25 +0300 | [diff] [blame] | 258 | program_sci(g->flags, gevent_num); |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 259 | } |
| 260 | } |
| 261 | |
Felix Held | f7f1f16 | 2021-09-20 21:12:22 +0200 | [diff] [blame] | 262 | void gpio_configure_pads_with_override(const struct soc_amd_gpio *base_cfg, |
| 263 | size_t base_num_pads, |
| 264 | const struct soc_amd_gpio *override_cfg, |
| 265 | size_t override_num_pads) |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 266 | { |
Felix Held | f7f1f16 | 2021-09-20 21:12:22 +0200 | [diff] [blame] | 267 | const struct soc_amd_gpio *c; |
| 268 | size_t i, j; |
Kyösti Mälkki | ff730fe | 2020-07-01 01:43:55 +0300 | [diff] [blame] | 269 | |
Felix Held | f7f1f16 | 2021-09-20 21:12:22 +0200 | [diff] [blame] | 270 | if (!base_cfg || !base_num_pads) |
Martin Roth | 3190ba8 | 2020-11-05 11:20:19 -0700 | [diff] [blame] | 271 | return; |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 272 | |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 273 | /* |
| 274 | * Disable blocking wake/interrupt status generation while updating |
| 275 | * debounce registers. Otherwise when a debounce register is updated |
| 276 | * the whole GPIO controller will zero out all interrupt enable status |
| 277 | * bits while the delay happens. This could cause us to drop the bits |
| 278 | * due to the read-modify-write that happens on each register. |
| 279 | * |
| 280 | * Additionally disable interrupt generation so we don't get any |
| 281 | * spurious interrupts while updating the registers. |
| 282 | */ |
Kyösti Mälkki | 419c690 | 2020-06-22 08:06:52 +0300 | [diff] [blame] | 283 | master_switch_clr(GPIO_MASK_STS_EN | GPIO_INTERRUPT_EN); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 284 | |
Felix Held | f7f1f16 | 2021-09-20 21:12:22 +0200 | [diff] [blame] | 285 | for (i = 0; i < base_num_pads; i++) { |
| 286 | c = &base_cfg[i]; |
| 287 | /* Check if override exist for GPIO from the base configuration */ |
| 288 | for (j = 0; override_cfg && j < override_num_pads; j++) { |
| 289 | if (c->gpio == override_cfg[j].gpio) { |
| 290 | c = &override_cfg[j]; |
| 291 | break; |
| 292 | } |
| 293 | } |
| 294 | set_single_gpio(c); |
| 295 | } |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 296 | |
| 297 | /* |
| 298 | * Re-enable interrupt status generation. |
| 299 | * |
| 300 | * We leave MASK_STATUS disabled because the kernel may reconfigure the |
| 301 | * debounce registers while the drivers load. This will cause interrupts |
| 302 | * to be missed during boot. |
| 303 | */ |
Kyösti Mälkki | 419c690 | 2020-06-22 08:06:52 +0300 | [diff] [blame] | 304 | master_switch_set(GPIO_INTERRUPT_EN); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 305 | } |
| 306 | |
Felix Held | 7011fa1 | 2021-09-22 16:36:12 +0200 | [diff] [blame] | 307 | void gpio_configure_pads(const struct soc_amd_gpio *gpio_list_ptr, size_t size) |
Felix Held | f7f1f16 | 2021-09-20 21:12:22 +0200 | [diff] [blame] | 308 | { |
| 309 | gpio_configure_pads_with_override(gpio_list_ptr, size, NULL, 0); |
| 310 | } |
| 311 | |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 312 | int gpio_interrupt_status(gpio_t gpio) |
| 313 | { |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 314 | uint32_t reg = gpio_read32(gpio); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 315 | |
| 316 | if (reg & GPIO_INT_STATUS) { |
| 317 | /* Clear interrupt status, preserve wake status */ |
| 318 | reg &= ~GPIO_WAKE_STATUS; |
Kyösti Mälkki | 39bd46f | 2020-06-18 19:18:21 +0300 | [diff] [blame] | 319 | gpio_write32(gpio, reg); |
Marshall Dawson | 251d305 | 2019-05-02 17:27:57 -0600 | [diff] [blame] | 320 | return 1; |
| 321 | } |
| 322 | |
| 323 | return 0; |
| 324 | } |
Peichao Wang | 712311f | 2020-04-18 08:25:53 +0800 | [diff] [blame] | 325 | |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 326 | static void check_and_add_wake_gpio(gpio_t begin, gpio_t end, struct gpio_wake_state *state) |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 327 | { |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 328 | gpio_t i; |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 329 | uint32_t reg; |
| 330 | |
| 331 | for (i = begin; i < end; i++) { |
| 332 | reg = gpio_read32(i); |
| 333 | if (!(reg & GPIO_WAKE_STATUS)) |
| 334 | continue; |
| 335 | printk(BIOS_INFO, "GPIO %d woke system.\n", i); |
| 336 | if (state->num_valid_wake_gpios >= ARRAY_SIZE(state->wake_gpios)) |
| 337 | continue; |
| 338 | state->wake_gpios[state->num_valid_wake_gpios++] = i; |
| 339 | } |
| 340 | } |
| 341 | |
Felix Held | afa750b | 2021-07-30 03:07:42 +0200 | [diff] [blame] | 342 | static void check_gpios(uint32_t wake_stat, unsigned int bit_limit, gpio_t gpio_base, |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 343 | struct gpio_wake_state *state) |
| 344 | { |
Felix Held | afa750b | 2021-07-30 03:07:42 +0200 | [diff] [blame] | 345 | unsigned int i; |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 346 | gpio_t begin; |
| 347 | gpio_t end; |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 348 | |
| 349 | for (i = 0; i < bit_limit; i++) { |
| 350 | if (!(wake_stat & BIT(i))) |
| 351 | continue; |
Felix Held | b93a9a2 | 2021-07-30 02:58:19 +0200 | [diff] [blame] | 352 | /* Each wake status register bit is for 4 GPIOs that then will be checked */ |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 353 | begin = gpio_base + i * 4; |
| 354 | end = begin + 4; |
| 355 | /* There is no gpio 63. */ |
| 356 | if (begin == 60) |
| 357 | end = 63; |
| 358 | check_and_add_wake_gpio(begin, end, state); |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | void gpio_fill_wake_state(struct gpio_wake_state *state) |
| 363 | { |
| 364 | /* Turn the wake registers into "gpio" index to conform to existing API. */ |
Felix Held | d0911e9 | 2021-07-30 03:04:54 +0200 | [diff] [blame] | 365 | const gpio_t stat0 = GPIO_WAKE_STAT_0 / sizeof(uint32_t); |
| 366 | const gpio_t stat1 = GPIO_WAKE_STAT_1 / sizeof(uint32_t); |
| 367 | const gpio_t control_switch = GPIO_MASTER_SWITCH / sizeof(uint32_t); |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 368 | |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 369 | memset(state, 0, sizeof(*state)); |
| 370 | |
| 371 | state->control_switch = gpio_read32(control_switch); |
| 372 | state->wake_stat[0] = gpio_read32(stat0); |
| 373 | state->wake_stat[1] = gpio_read32(stat1); |
| 374 | |
| 375 | printk(BIOS_INFO, "GPIO Control Switch: 0x%08x, Wake Stat 0: 0x%08x, Wake Stat 1: 0x%08x\n", |
| 376 | state->control_switch, state->wake_stat[0], state->wake_stat[1]); |
| 377 | |
| 378 | check_gpios(state->wake_stat[0], 32, 0, state); |
| 379 | check_gpios(state->wake_stat[1], 14, 128, state); |
| 380 | } |
| 381 | |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 382 | void gpio_add_events(void) |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 383 | { |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 384 | const struct chipset_power_state *ps; |
| 385 | const struct gpio_wake_state *state; |
Felix Held | afa750b | 2021-07-30 03:07:42 +0200 | [diff] [blame] | 386 | unsigned int i; |
| 387 | unsigned int end; |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 388 | |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 389 | if (acpi_pm_state_for_elog(&ps) < 0) |
| 390 | return; |
| 391 | state = &ps->gpio_state; |
| 392 | |
Aaron Durbin | e05f4dc | 2020-08-17 16:22:09 -0600 | [diff] [blame] | 393 | end = MIN(state->num_valid_wake_gpios, ARRAY_SIZE(state->wake_gpios)); |
| 394 | for (i = 0; i < end; i++) |
| 395 | elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, state->wake_gpios[i]); |
| 396 | } |