blob: a5f0eaf0b2d06581a385e3715aa4dfb4822cdca8 [file] [log] [blame]
Angel Ponsae593872020-04-04 18:50:57 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Marshall Dawson251d3052019-05-02 17:27:57 -06002
3#include <device/mmio.h>
4#include <device/device.h>
5#include <console/console.h>
Aaron Durbine05f4dc2020-08-17 16:22:09 -06006#include <elog.h>
Marshall Dawson251d3052019-05-02 17:27:57 -06007#include <gpio.h>
8#include <amdblocks/acpimmio.h>
Kyösti Mälkki8d119fc2020-06-30 22:40:09 +03009#include <amdblocks/gpio_banks.h>
Felix Helda5a52952020-12-01 18:14:01 +010010#include <amdblocks/smi.h>
Marshall Dawson251d3052019-05-02 17:27:57 -060011#include <soc/gpio.h>
12#include <soc/smi.h>
13#include <assert.h>
Aaron Durbine05f4dc2020-08-17 16:22:09 -060014#include <string.h>
Marshall Dawson251d3052019-05-02 17:27:57 -060015
16static int get_gpio_gevent(uint8_t gpio, const struct soc_amd_event *table,
17 size_t items)
18{
19 int i;
20
21 for (i = 0; i < items; i++) {
22 if ((table + i)->gpio == gpio)
23 return (int)(table + i)->event;
24 }
25 return -1;
26}
27
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070028static void program_smi(uint32_t flags, int gevent_num)
Marshall Dawson251d3052019-05-02 17:27:57 -060029{
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070030 uint8_t level;
Marshall Dawson251d3052019-05-02 17:27:57 -060031
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070032 if (!is_gpio_event_level_triggered(flags)) {
33 printk(BIOS_ERR, "ERROR: %s - Only level trigger allowed for SMI!\n", __func__);
Julius Werner3e034b62020-07-29 17:39:21 -070034 BUG();
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070035 return;
36 }
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030037
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070038 if (is_gpio_event_active_high(flags))
39 level = SMI_SCI_LVL_HIGH;
40 else
41 level = SMI_SCI_LVL_LOW;
42
43 configure_gevent_smi(gevent_num, SMI_MODE_SMI, level);
Marshall Dawson251d3052019-05-02 17:27:57 -060044}
45
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030046struct sci_trigger_regs {
47 uint32_t mask;
48 uint32_t polarity;
49 uint32_t level;
50};
Marshall Dawson251d3052019-05-02 17:27:57 -060051
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030052/*
53 * For each general purpose event, GPE, the choice of edge/level triggered
54 * event is represented as a single bit in SMI_SCI_LEVEL register.
55 *
56 * In a similar fashion, polarity (rising/falling, hi/lo) of each GPE is
57 * represented as a single bit in SMI_SCI_TRIG register.
58 */
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070059static void fill_sci_trigger(uint32_t flags, int gpe, struct sci_trigger_regs *regs)
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030060{
61 uint32_t mask = 1 << gpe;
62
63 regs->mask |= mask;
64
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070065 if (is_gpio_event_level_triggered(flags))
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030066 regs->level |= mask;
67 else
68 regs->level &= ~mask;
69
Furquan Shaikhaf8123c2020-06-26 18:55:17 -070070 if (is_gpio_event_active_high(flags))
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +030071 regs->polarity |= mask;
72 else
73 regs->polarity &= ~mask;
74}
75
76/* TODO: See configure_scimap() implementations. */
77static void set_sci_trigger(const struct sci_trigger_regs *regs)
78{
79 uint32_t value;
80
81 value = smi_read32(SMI_SCI_TRIG);
82 value &= ~regs->mask;
83 value |= regs->polarity;
84 smi_write32(SMI_SCI_TRIG, value);
85
86 value = smi_read32(SMI_SCI_LEVEL);
87 value &= ~regs->mask;
88 value |= regs->level;
89 smi_write32(SMI_SCI_LEVEL, value);
Marshall Dawson251d3052019-05-02 17:27:57 -060090}
91
92uintptr_t gpio_get_address(gpio_t gpio_num)
93{
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +030094 return (uintptr_t)gpio_ctrl_ptr(gpio_num);
95}
Marshall Dawson251d3052019-05-02 17:27:57 -060096
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +030097static void __gpio_update32(gpio_t gpio_num, uint32_t mask, uint32_t or)
98{
99 uint32_t reg;
Marshall Dawson251d3052019-05-02 17:27:57 -0600100
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300101 reg = gpio_read32(gpio_num);
102 reg &= mask;
103 reg |= or;
104 gpio_write32(gpio_num, reg);
105}
106
Furquan Shaikh05726e82020-06-30 10:35:27 -0700107/* Set specified bits of a register to match those of ctrl. */
108static void __gpio_setbits32(gpio_t gpio_num, uint32_t mask, uint32_t ctrl)
109{
110 __gpio_update32(gpio_num, ~mask, ctrl & mask);
111}
112
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300113static void __gpio_and32(gpio_t gpio_num, uint32_t mask)
114{
115 __gpio_update32(gpio_num, mask, 0);
116}
117
118static void __gpio_or32(gpio_t gpio_num, uint32_t or)
119{
120 __gpio_update32(gpio_num, -1UL, or);
Marshall Dawson251d3052019-05-02 17:27:57 -0600121}
122
Kyösti Mälkki419c6902020-06-22 08:06:52 +0300123static void master_switch_clr(uint32_t mask)
124{
125 const uint8_t master_reg = GPIO_MASTER_SWITCH / sizeof(uint32_t);
126 __gpio_and32(master_reg, ~mask);
127}
128
129static void master_switch_set(uint32_t or)
130{
131 const uint8_t master_reg = GPIO_MASTER_SWITCH / sizeof(uint32_t);
132 __gpio_or32(master_reg, or);
133}
134
Marshall Dawson251d3052019-05-02 17:27:57 -0600135int gpio_get(gpio_t gpio_num)
136{
137 uint32_t reg;
Marshall Dawson251d3052019-05-02 17:27:57 -0600138
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300139 reg = gpio_read32(gpio_num);
Marshall Dawson251d3052019-05-02 17:27:57 -0600140 return !!(reg & GPIO_PIN_STS);
141}
142
143void gpio_set(gpio_t gpio_num, int value)
144{
Furquan Shaikh05726e82020-06-30 10:35:27 -0700145 __gpio_setbits32(gpio_num, GPIO_OUTPUT_VALUE, value ? GPIO_OUTPUT_VALUE : 0);
Marshall Dawson251d3052019-05-02 17:27:57 -0600146}
147
148void gpio_input_pulldown(gpio_t gpio_num)
149{
Furquan Shaikh05726e82020-06-30 10:35:27 -0700150 __gpio_setbits32(gpio_num, GPIO_PULL_MASK, GPIO_PULLDOWN_ENABLE);
Marshall Dawson251d3052019-05-02 17:27:57 -0600151}
152
153void gpio_input_pullup(gpio_t gpio_num)
154{
Furquan Shaikh05726e82020-06-30 10:35:27 -0700155 __gpio_setbits32(gpio_num, GPIO_PULL_MASK, GPIO_PULLUP_ENABLE);
Marshall Dawson251d3052019-05-02 17:27:57 -0600156}
157
158void gpio_input(gpio_t gpio_num)
159{
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300160 __gpio_and32(gpio_num, ~GPIO_OUTPUT_ENABLE);
Marshall Dawson251d3052019-05-02 17:27:57 -0600161}
162
163void gpio_output(gpio_t gpio_num, int value)
164{
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300165 __gpio_or32(gpio_num, GPIO_OUTPUT_ENABLE);
Marshall Dawson251d3052019-05-02 17:27:57 -0600166 gpio_set(gpio_num, value);
167}
168
169const char *gpio_acpi_path(gpio_t gpio)
170{
171 return "\\_SB.GPIO";
172}
173
174uint16_t gpio_acpi_pin(gpio_t gpio)
175{
176 return gpio;
177}
178
179__weak void soc_gpio_hook(uint8_t gpio, uint8_t mux) {}
180
181void program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size)
182{
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +0300183 uint32_t control, control_flags;
Marshall Dawson251d3052019-05-02 17:27:57 -0600184 uint8_t mux, index, gpio;
185 int gevent_num;
186 const struct soc_amd_event *gev_tbl;
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +0300187 struct sci_trigger_regs sci_trigger_cfg = { 0 };
Marshall Dawson251d3052019-05-02 17:27:57 -0600188 size_t gev_items;
Martin Roth137f8612020-06-23 22:15:33 -0600189 const bool can_set_smi_flags = !(CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK) &&
190 ENV_SEPARATE_VERSTAGE);
Martin Roth3190ba82020-11-05 11:20:19 -0700191 if (!gpio_list_ptr || !size)
192 return;
Marshall Dawson251d3052019-05-02 17:27:57 -0600193
Marshall Dawson251d3052019-05-02 17:27:57 -0600194 /*
195 * Disable blocking wake/interrupt status generation while updating
196 * debounce registers. Otherwise when a debounce register is updated
197 * the whole GPIO controller will zero out all interrupt enable status
198 * bits while the delay happens. This could cause us to drop the bits
199 * due to the read-modify-write that happens on each register.
200 *
201 * Additionally disable interrupt generation so we don't get any
202 * spurious interrupts while updating the registers.
203 */
Kyösti Mälkki419c6902020-06-22 08:06:52 +0300204 master_switch_clr(GPIO_MASK_STS_EN | GPIO_INTERRUPT_EN);
Marshall Dawson251d3052019-05-02 17:27:57 -0600205
Martin Roth137f8612020-06-23 22:15:33 -0600206 if (can_set_smi_flags)
207 soc_get_gpio_event_table(&gev_tbl, &gev_items);
Marshall Dawson251d3052019-05-02 17:27:57 -0600208
209 for (index = 0; index < size; index++) {
210 gpio = gpio_list_ptr[index].gpio;
211 mux = gpio_list_ptr[index].function;
212 control = gpio_list_ptr[index].control;
213 control_flags = gpio_list_ptr[index].flags;
214
215 iomux_write8(gpio, mux & AMD_GPIO_MUX_MASK);
216 iomux_read8(gpio); /* Flush posted write */
217
218 soc_gpio_hook(gpio, mux);
Furquan Shaikh84b96532020-06-27 16:38:44 -0700219
Furquan Shaikh10185862020-06-29 13:39:21 -0700220 __gpio_setbits32(gpio, PAD_CFG_MASK, control);
Josie Nordrum70823a02020-08-20 08:50:22 -0700221 /* Clear interrupt and wake status (write 1-to-clear bits) */
222 __gpio_or32(gpio, GPIO_INT_STATUS | GPIO_WAKE_STATUS);
Furquan Shaikh10185862020-06-29 13:39:21 -0700223 if (control_flags == 0)
224 continue;
Marshall Dawson251d3052019-05-02 17:27:57 -0600225
Martin Roth137f8612020-06-23 22:15:33 -0600226 /* Can't set SMI flags from PSP */
227 if (!can_set_smi_flags)
228 continue;
229
Furquan Shaikh10185862020-06-29 13:39:21 -0700230 gevent_num = get_gpio_gevent(gpio, gev_tbl, gev_items);
231 if (gevent_num < 0) {
232 printk(BIOS_WARNING, "Warning: GPIO pin %d has no associated gevent!\n",
233 gpio);
234 continue;
235 }
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +0300236
Furquan Shaikh10185862020-06-29 13:39:21 -0700237 if (control_flags & GPIO_FLAG_SMI) {
238 program_smi(control_flags, gevent_num);
239 } else if (control_flags & GPIO_FLAG_SCI) {
240 fill_sci_trigger(control_flags, gevent_num, &sci_trigger_cfg);
241 soc_route_sci(gevent_num);
Marshall Dawson251d3052019-05-02 17:27:57 -0600242 }
243 }
244
245 /*
246 * Re-enable interrupt status generation.
247 *
248 * We leave MASK_STATUS disabled because the kernel may reconfigure the
249 * debounce registers while the drivers load. This will cause interrupts
250 * to be missed during boot.
251 */
Kyösti Mälkki419c6902020-06-22 08:06:52 +0300252 master_switch_set(GPIO_INTERRUPT_EN);
Marshall Dawson251d3052019-05-02 17:27:57 -0600253
Kyösti Mälkkic4f5e4e2020-06-22 12:03:51 +0300254 /* Set all SCI trigger polarity (high/low) and level (edge/level). */
Martin Roth137f8612020-06-23 22:15:33 -0600255 if (can_set_smi_flags)
256 set_sci_trigger(&sci_trigger_cfg);
Marshall Dawson251d3052019-05-02 17:27:57 -0600257}
258
259int gpio_interrupt_status(gpio_t gpio)
260{
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300261 uint32_t reg = gpio_read32(gpio);
Marshall Dawson251d3052019-05-02 17:27:57 -0600262
263 if (reg & GPIO_INT_STATUS) {
264 /* Clear interrupt status, preserve wake status */
265 reg &= ~GPIO_WAKE_STATUS;
Kyösti Mälkki39bd46f2020-06-18 19:18:21 +0300266 gpio_write32(gpio, reg);
Marshall Dawson251d3052019-05-02 17:27:57 -0600267 return 1;
268 }
269
270 return 0;
271}
Peichao Wang712311f2020-04-18 08:25:53 +0800272
273/*
274 * This function checks to see if there is an override config present for the
275 * provided pad_config. If no override config is present, then the input config
276 * is returned. Else, it returns the override config.
277 */
278static const struct soc_amd_gpio *gpio_get_config(const struct soc_amd_gpio *c,
279 const struct soc_amd_gpio *override_cfg_table,
280 size_t num)
281{
282 size_t i;
283 if (override_cfg_table == NULL)
284 return c;
285 for (i = 0; i < num; i++) {
286 if (c->gpio == override_cfg_table[i].gpio)
287 return override_cfg_table + i;
288 }
289 return c;
290}
291void gpio_configure_pads_with_override(const struct soc_amd_gpio *base_cfg,
292 size_t base_num_pads,
293 const struct soc_amd_gpio *override_cfg,
294 size_t override_num_pads)
295{
296 size_t i;
297 const struct soc_amd_gpio *c;
298
299 for (i = 0; i < base_num_pads; i++) {
300 c = gpio_get_config(base_cfg + i, override_cfg,
301 override_num_pads);
302 program_gpios(c, 1);
303 }
304}
Aaron Durbine05f4dc2020-08-17 16:22:09 -0600305
306static void check_and_add_wake_gpio(int begin, int end, struct gpio_wake_state *state)
307{
308 int i;
309 uint32_t reg;
310
311 for (i = begin; i < end; i++) {
312 reg = gpio_read32(i);
313 if (!(reg & GPIO_WAKE_STATUS))
314 continue;
315 printk(BIOS_INFO, "GPIO %d woke system.\n", i);
316 if (state->num_valid_wake_gpios >= ARRAY_SIZE(state->wake_gpios))
317 continue;
318 state->wake_gpios[state->num_valid_wake_gpios++] = i;
319 }
320}
321
322static void check_gpios(uint32_t wake_stat, int bit_limit, int gpio_base,
323 struct gpio_wake_state *state)
324{
325 int i;
326 int begin;
327 int end;
328
329 for (i = 0; i < bit_limit; i++) {
330 if (!(wake_stat & BIT(i)))
331 continue;
332 begin = gpio_base + i * 4;
333 end = begin + 4;
334 /* There is no gpio 63. */
335 if (begin == 60)
336 end = 63;
337 check_and_add_wake_gpio(begin, end, state);
338 }
339}
340
341void gpio_fill_wake_state(struct gpio_wake_state *state)
342{
343 /* Turn the wake registers into "gpio" index to conform to existing API. */
344 const uint8_t stat0 = GPIO_WAKE_STAT_0 / sizeof(uint32_t);
345 const uint8_t stat1 = GPIO_WAKE_STAT_1 / sizeof(uint32_t);
346 const uint8_t control_switch = GPIO_MASTER_SWITCH / sizeof(uint32_t);
347
348 /* Register fields and gpio availability need to be confirmed on other chipsets. */
349 if (!CONFIG(SOC_AMD_PICASSO))
350 dead_code();
351
352 memset(state, 0, sizeof(*state));
353
354 state->control_switch = gpio_read32(control_switch);
355 state->wake_stat[0] = gpio_read32(stat0);
356 state->wake_stat[1] = gpio_read32(stat1);
357
358 printk(BIOS_INFO, "GPIO Control Switch: 0x%08x, Wake Stat 0: 0x%08x, Wake Stat 1: 0x%08x\n",
359 state->control_switch, state->wake_stat[0], state->wake_stat[1]);
360
361 check_gpios(state->wake_stat[0], 32, 0, state);
362 check_gpios(state->wake_stat[1], 14, 128, state);
363}
364
365void gpio_add_events(const struct gpio_wake_state *state)
366{
367 int i;
368 int end;
369
370 end = MIN(state->num_valid_wake_gpios, ARRAY_SIZE(state->wake_gpios));
371 for (i = 0; i < end; i++)
372 elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, state->wake_gpios[i]);
373}