Felix Held | 4a8cd72 | 2020-04-18 22:26:39 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Martin Roth | c515898 | 2018-05-26 18:42:05 -0600 | [diff] [blame] | 2 | |
| 3 | /* |
| 4 | * SMM utilities used in both SMM and normal mode |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 5 | */ |
| 6 | |
| 7 | #include <console/console.h> |
Arthur Heymans | 3428027 | 2020-09-29 11:51:34 +0200 | [diff] [blame] | 8 | #include <cpu/x86/smm.h> |
Marshall Dawson | eecb794 | 2017-09-28 17:32:30 -0600 | [diff] [blame] | 9 | #include <soc/southbridge.h> |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 10 | #include <soc/smi.h> |
Marshall Dawson | 69486ca | 2019-05-02 12:03:45 -0600 | [diff] [blame] | 11 | #include <amdblocks/acpimmio.h> |
Felix Held | a5a5295 | 2020-12-01 18:14:01 +0100 | [diff] [blame^] | 12 | #include <amdblocks/smi.h> |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 13 | |
Marshall Dawson | a05fdcb | 2017-09-27 15:01:37 -0600 | [diff] [blame] | 14 | void configure_smi(uint8_t smi_num, uint8_t mode) |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 15 | { |
| 16 | uint8_t reg32_offset, bit_offset; |
| 17 | uint32_t reg32; |
| 18 | |
Marshall Dawson | 9db0a2d | 2017-09-22 15:35:32 -0600 | [diff] [blame] | 19 | if (smi_num >= NUMBER_SMITYPES) { |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 20 | printk(BIOS_WARNING, "BUG: Invalid SMI: %u\n", smi_num); |
| 21 | return; |
| 22 | } |
| 23 | |
| 24 | /* 16 sources per register, 2 bits per source; registers are 4 bytes */ |
| 25 | reg32_offset = (smi_num / 16) * 4; |
| 26 | bit_offset = (smi_num % 16) * 2; |
| 27 | |
| 28 | reg32 = smi_read32(SMI_REG_CONTROL0 + reg32_offset); |
| 29 | reg32 &= ~(0x3 << (bit_offset)); |
| 30 | reg32 |= (mode & 0x3) << bit_offset; |
| 31 | smi_write32(SMI_REG_CONTROL0 + reg32_offset, reg32); |
| 32 | } |
| 33 | |
| 34 | /** |
| 35 | * Configure generation of interrupts for given GEVENT pin |
| 36 | * |
| 37 | * @param gevent The GEVENT pin number. Valid values are 0 thru 23 |
| 38 | * @param mode The type of event this pin should generate. Note that only |
| 39 | * SMI_MODE_SMI generates an SMI. SMI_MODE_DISABLE disables events. |
Marc Jones | e8e72bd | 2017-10-04 22:12:31 -0600 | [diff] [blame] | 40 | * @param level SMI__SCI_LVL_LOW or SMI_SCI_LVL_HIGH |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 41 | */ |
Marc Jones | dfeb1c4 | 2017-08-07 19:08:24 -0600 | [diff] [blame] | 42 | void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level) |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 43 | { |
| 44 | uint32_t reg32; |
| 45 | /* GEVENT pins range from [0:23] */ |
Marc Jones | e8e72bd | 2017-10-04 22:12:31 -0600 | [diff] [blame] | 46 | if (gevent >= SMI_GEVENTS) { |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 47 | printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent); |
| 48 | return; |
| 49 | } |
| 50 | |
| 51 | /* SMI0 source is GEVENT0 and so on */ |
| 52 | configure_smi(gevent, mode); |
| 53 | |
| 54 | /* And set set the trigger level */ |
| 55 | reg32 = smi_read32(SMI_REG_SMITRIG0); |
| 56 | reg32 &= ~(1 << gevent); |
| 57 | reg32 |= (level & 0x1) << gevent; |
| 58 | smi_write32(SMI_REG_SMITRIG0, reg32); |
| 59 | } |
| 60 | |
Marc Jones | e8e72bd | 2017-10-04 22:12:31 -0600 | [diff] [blame] | 61 | /** |
| 62 | * Configure generation of SCIs. |
| 63 | */ |
| 64 | void configure_scimap(const struct sci_source *sci) |
| 65 | { |
| 66 | uint32_t reg32; |
| 67 | |
| 68 | /* GEVENT pins range */ |
| 69 | if (sci->scimap >= SCIMAPS) { |
| 70 | printk(BIOS_WARNING, "BUG: Invalid SCIMAP: %u\n", |
| 71 | sci->scimap); |
| 72 | return; |
| 73 | } |
| 74 | |
| 75 | /* GPEs range from [0:31] */ |
| 76 | if (sci->gpe >= SCI_GPES) { |
| 77 | printk(BIOS_WARNING, "BUG: Invalid SCI GPE: %u\n", sci->gpe); |
| 78 | return; |
| 79 | } |
| 80 | |
| 81 | printk(BIOS_DEBUG, "SCIMAP %u maps to GPE %u (active %s, %s trigger)\n", |
| 82 | sci->scimap, sci->gpe, |
| 83 | (!!sci->direction) ? "high" : "low", |
| 84 | (!!sci->level) ? "level" : "edge"); |
| 85 | |
| 86 | /* Map Gevent to SCI GPE# */ |
| 87 | smi_write8(SMI_SCI_MAP(sci->scimap), sci->gpe); |
| 88 | |
| 89 | /* Set the trigger direction (high/low) */ |
| 90 | reg32 = smi_read32(SMI_SCI_TRIG); |
| 91 | reg32 &= ~(1 << sci->gpe); |
| 92 | reg32 |= !!sci->direction << sci->gpe; |
| 93 | smi_write32(SMI_SCI_TRIG, reg32); |
| 94 | |
| 95 | /* Set the trigger level (edge/level) */ |
| 96 | reg32 = smi_read32(SMI_SCI_LEVEL); |
| 97 | reg32 &= ~(1 << sci->gpe); |
| 98 | reg32 |= !!sci->level << sci->gpe; |
| 99 | smi_write32(SMI_SCI_LEVEL, reg32); |
| 100 | } |
| 101 | |
| 102 | void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes) |
| 103 | { |
| 104 | size_t i; |
| 105 | |
| 106 | for (i = 0; i < num_gpes; i++) |
| 107 | configure_scimap(scis + i); |
| 108 | } |
| 109 | |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 110 | /** Disable events from given GEVENT pin */ |
Marc Jones | dfeb1c4 | 2017-08-07 19:08:24 -0600 | [diff] [blame] | 111 | void disable_gevent_smi(uint8_t gevent) |
Marc Jones | 2448484 | 2017-05-04 21:17:45 -0600 | [diff] [blame] | 112 | { |
| 113 | /* GEVENT pins range from [0:23] */ |
| 114 | if (gevent > 23) { |
| 115 | printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent); |
| 116 | return; |
| 117 | } |
| 118 | |
| 119 | /* SMI0 source is GEVENT0 and so on */ |
| 120 | configure_smi(gevent, SMI_MODE_DISABLE); |
| 121 | } |
| 122 | |
Marshall Dawson | 66e62da | 2017-09-27 13:32:38 -0600 | [diff] [blame] | 123 | uint16_t pm_acpi_smi_cmd_port(void) |
| 124 | { |
| 125 | return pm_read16(PM_ACPI_SMI_CMD); |
| 126 | } |