blob: 53bd090b6cca653418c2c82d527f698e3d25d31c [file] [log] [blame]
Angel Ponsae593872020-04-04 18:50:57 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Marshall Dawson6ab5ed32019-05-29 09:24:18 -06002
Raul E Rangel314c7162020-05-01 14:04:08 -06003#include <assert.h>
Marshall Dawson6ab5ed32019-05-29 09:24:18 -06004#include <stdint.h>
5#include <device/device.h>
6#include <device/pci_ops.h>
7#include <device/pci_def.h>
Furquan Shaikh6d288022020-05-11 16:35:08 -07008#include <amdblocks/acpimmio.h>
Marshall Dawson6ab5ed32019-05-29 09:24:18 -06009#include <amdblocks/lpc.h>
10#include <soc/iomap.h>
Raul E Rangel466edb52021-02-09 11:24:13 -070011#include <soc/lpc.h>
Marshall Dawson6ab5ed32019-05-29 09:24:18 -060012#include <soc/southbridge.h>
13
14/* The LPC-ISA bridge is always at D14F3 */
15#if !defined(__SIMPLE_DEVICE__)
Marshall Dawson6ab5ed32019-05-29 09:24:18 -060016#define _LPCB_DEV pcidev_on_root(0x14, 0x3)
17#else
18#define _LPCB_DEV PCI_DEV(0, 0x14, 0x3)
19#endif
20
21/*
22 * Structure to simplify code obtaining the total of used wide IO
23 * registers and the size assigned to each.
24 */
25static const struct wide_io_ioport_and_bits {
26 uint32_t enable;
27 uint16_t port;
28 uint8_t alt;
29} wio_io_en[] = {
30 {
31 .enable = LPC_WIDEIO0_ENABLE,
32 .port = LPC_WIDEIO_GENERIC_PORT,
33 .alt = LPC_ALT_WIDEIO0_ENABLE
34 },
35 {
36 .enable = LPC_WIDEIO1_ENABLE,
37 .port = LPC_WIDEIO1_GENERIC_PORT,
38 .alt = LPC_ALT_WIDEIO1_ENABLE
39 },
40 {
41 .enable = LPC_WIDEIO2_ENABLE,
42 .port = LPC_WIDEIO2_GENERIC_PORT,
43 .alt = LPC_ALT_WIDEIO2_ENABLE
44 }
45};
46
47/**
48 * @brief Find the size of a particular wide IO
49 *
50 * @param index = index of desired wide IO
51 *
52 * @return size of desired wide IO
53 */
54uint16_t lpc_wideio_size(int index)
55{
56 uint32_t enable_register;
57 uint16_t size = 0;
58 uint8_t alternate_register;
59
60 if (index >= ARRAY_SIZE(wio_io_en))
61 return size;
62 enable_register = pci_read_config32(_LPCB_DEV,
63 LPC_IO_OR_MEM_DECODE_ENABLE);
64 alternate_register = pci_read_config8(_LPCB_DEV,
65 LPC_ALT_WIDEIO_RANGE_ENABLE);
66 if (enable_register & wio_io_en[index].enable)
67 size = (alternate_register & wio_io_en[index].alt) ?
68 16 : 512;
69 return size;
70}
71
72/**
73 * @brief Identify if any LPC wide IO is covering the IO range
74 *
75 * @param start = start of IO range
76 * @param size = size of IO range
77 *
78 * @return Index of wide IO covering the range or error
79 */
80int lpc_find_wideio_range(uint16_t start, uint16_t size)
81{
82 int i, index = WIDEIO_RANGE_ERROR;
83 uint16_t end, current_size, start_wideio, end_wideio;
84
85 end = start + size;
86 for (i = 0; i < ARRAY_SIZE(wio_io_en); i++) {
87 current_size = lpc_wideio_size(i);
88 if (current_size == 0)
89 continue;
90 start_wideio = pci_read_config16(_LPCB_DEV,
91 wio_io_en[i].port);
92 end_wideio = start_wideio + current_size;
93 if ((start >= start_wideio) && (end <= end_wideio)) {
94 index = i;
95 break;
96 }
97 }
98 return index;
99}
100
101/**
102 * @brief Program a LPC wide IO to support an IO range
103 *
104 * @param start = start of range to be routed through wide IO
105 * @param size = size of range to be routed through wide IO
106 *
107 * @return Index of wide IO register used or error
108 */
109int lpc_set_wideio_range(uint16_t start, uint16_t size)
110{
111 int i, index = WIDEIO_RANGE_ERROR;
112 uint32_t enable_register;
113 uint8_t alternate_register;
114
115 enable_register = pci_read_config32(_LPCB_DEV,
116 LPC_IO_OR_MEM_DECODE_ENABLE);
117 alternate_register = pci_read_config8(_LPCB_DEV,
118 LPC_ALT_WIDEIO_RANGE_ENABLE);
119 for (i = 0; i < ARRAY_SIZE(wio_io_en); i++) {
120 if (enable_register & wio_io_en[i].enable)
121 continue;
122 index = i;
123 pci_write_config16(_LPCB_DEV, wio_io_en[i].port, start);
124 enable_register |= wio_io_en[i].enable;
125 pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE,
126 enable_register);
127 if (size <= 16)
128 alternate_register |= wio_io_en[i].alt;
129 else
130 alternate_register &= ~wio_io_en[i].alt;
131 pci_write_config8(_LPCB_DEV,
132 LPC_ALT_WIDEIO_RANGE_ENABLE,
133 alternate_register);
134 break;
135 }
136 return index;
137}
138
139void lpc_enable_port80(void)
140{
Felix Heldf6205d32021-11-25 19:53:37 +0100141 uint32_t tmp;
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600142
Felix Heldf6205d32021-11-25 19:53:37 +0100143 tmp = pci_read_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE);
144 tmp |= DECODE_IO_PORT_ENABLE4;
145 pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, tmp);
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600146}
147
Marshall Dawsonf6dbf4a2019-09-04 11:32:25 -0600148void lpc_enable_sio_decode(const bool addr)
149{
150 uint32_t decodes;
151 uint32_t enable;
152
153 decodes = pci_read_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE);
154 enable = addr == LPC_SELECT_SIO_2E2F ?
155 DECODE_SIO_ENABLE : DECODE_ALTERNATE_SIO_ENABLE;
156 decodes |= enable;
157 pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, decodes);
158}
159
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600160void lpc_enable_decode(uint32_t decodes)
161{
162 pci_write_config32(_LPCB_DEV, LPC_IO_PORT_DECODE_ENABLE, decodes);
163}
164
Marshall Dawsonba2533f2019-09-04 11:00:06 -0600165/*
166 * Clear all decoding to the LPC bus and erase any range registers associated
167 * with the enable bits.
168 */
169void lpc_disable_decodes(void)
170{
171 uint32_t reg;
172
173 lpc_enable_decode(0);
174 reg = pci_read_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE);
175 reg &= LPC_SYNC_TIMEOUT_COUNT_MASK | LPC_SYNC_TIMEOUT_COUNT_ENABLE;
176 pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg);
Furquan Shaikhca892fe2020-05-09 14:46:09 -0700177 pci_write_config32(_LPCB_DEV, LPC_IO_PORT_DECODE_ENABLE, 0);
Marshall Dawsonba2533f2019-09-04 11:00:06 -0600178
179 /* D14F3x48 enables ranges configured in additional registers */
180 pci_write_config32(_LPCB_DEV, LPC_MEM_PORT1, 0);
181 pci_write_config32(_LPCB_DEV, LPC_MEM_PORT0, 0);
182 pci_write_config32(_LPCB_DEV, LPC_WIDEIO2_GENERIC_PORT, 0);
183}
184
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600185uintptr_t lpc_spibase(void)
186{
187 u32 base, enables;
188
189 /* Make sure the base address is predictable */
Felix Held697fa742022-03-03 20:54:38 +0100190 base = pci_read_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER);
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600191 enables = base & SPI_PRESERVE_BITS;
192 base &= ~(SPI_PRESERVE_BITS | SPI_BASE_RESERVED);
193
194 if (!base) {
195 base = SPI_BASE_ADDRESS;
Felix Held697fa742022-03-03 20:54:38 +0100196 pci_write_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER,
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600197 base | enables | SPI_ROM_ENABLE);
198 /* PCI_COMMAND_MEMORY is read-only and enabled. */
199 }
200 return base;
201}
202
203/*
204 * Enable FCH to decode TPM associated Memory and IO regions
205 *
206 * Enable decoding of TPM cycles defined in TPM 1.2 spec
207 * Enable decoding of legacy TPM addresses: IO addresses 0x7f-
208 * 0x7e and 0xef-0xee.
209 * This function should be called if TPM is connected in any way to the FCH and
210 * conforms to the regions decoded.
211 * Absent any other routing configuration the TPM cycles will be claimed by the
212 * LPC bus
213 */
214void lpc_tpm_decode(void)
215{
216 u32 value;
217
218 value = pci_read_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE);
219 value |= TPM_12_EN | TPM_LEGACY_EN;
220 pci_write_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE, value);
221}
222
223/*
224 * Enable FCH to decode TPM associated Memory and IO regions to SPI
225 *
226 * This should be used if TPM is connected to SPI bus.
227 * Assumes SPI address space is already configured via a call to lpc_spibase().
228 */
229void lpc_tpm_decode_spi(void)
230{
231 /* Enable TPM decoding to FCH */
232 lpc_tpm_decode();
233
234 /* Route TPM accesses to SPI */
235 u32 spibase = pci_read_config32(_LPCB_DEV,
Felix Held697fa742022-03-03 20:54:38 +0100236 SPI_BASE_ADDRESS_REGISTER);
237 pci_write_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER, spibase
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600238 | ROUTE_TPM_2_SPI);
239}
240
241/*
242 * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF.
243 *
244 * Hardware should enable LPC ROM by pin straps. This function does not
245 * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations.
246 *
247 * The southbridge power-on default is to map 512K ROM space.
248 *
249 */
250void lpc_enable_rom(void)
251{
252 u8 reg8;
253
254 /*
255 * Decode variable LPC ROM address ranges 1 and 2.
256 * Bits 3-4 are not defined in any publicly available datasheet
257 */
258 reg8 = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE);
259 reg8 |= (1 << 3) | (1 << 4);
260 pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg8);
261
262 /*
263 * LPC ROM address range 1:
264 * Enable LPC ROM range mirroring start at 0x000e(0000).
265 */
266 pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_START, 0x000e);
267
268 /* Enable LPC ROM range mirroring end at 0x000f(ffff). */
269 pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_END, 0x000f);
270
271 /*
272 * LPC ROM address range 2:
273 *
274 * Enable LPC ROM range start at:
275 * 0xfff8(0000): 512KB
276 * 0xfff0(0000): 1MB
277 * 0xffe0(0000): 2MB
278 * 0xffc0(0000): 4MB
279 */
280 pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_START, 0x10000
281 - (CONFIG_COREBOOT_ROMSIZE_KB >> 6));
282
283 /* Enable LPC ROM range end at 0xffff(ffff). */
284 pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_END, 0xffff);
285}
286
287void lpc_enable_spi_prefetch(void)
288{
289 uint32_t dword;
290
291 dword = pci_read_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL);
292 dword |= SPI_FROM_HOST_PREFETCH_EN | SPI_FROM_USB_PREFETCH_EN;
293 pci_write_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, dword);
294}
295
Raul E Rangel314c7162020-05-01 14:04:08 -0600296void lpc_disable_spi_rom_sharing(void)
297{
298 u8 byte;
299
300 if (!CONFIG(PROVIDES_ROM_SHARING))
301 dead_code();
302
303 byte = pci_read_config8(_LPCB_DEV, LPC_PCI_CONTROL);
304 byte &= ~VW_ROM_SHARING_EN;
305 byte &= ~EXT_ROM_SHARING_EN;
306 pci_write_config8(_LPCB_DEV, LPC_PCI_CONTROL, byte);
307}
308
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600309uintptr_t lpc_get_spibase(void)
310{
311 u32 base;
312
Felix Held697fa742022-03-03 20:54:38 +0100313 base = pci_read_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER);
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600314 base = ALIGN_DOWN(base, SPI_BASE_ALIGNMENT);
315 return (uintptr_t)base;
316}
317
Furquan Shaikhd82c7d22020-05-09 17:18:48 -0700318void lpc_set_spibase(uint32_t base)
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600319{
Furquan Shaikhd82c7d22020-05-09 17:18:48 -0700320 uint32_t reg32;
321
Felix Held697fa742022-03-03 20:54:38 +0100322 reg32 = pci_read_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER);
Furquan Shaikhd82c7d22020-05-09 17:18:48 -0700323
324 reg32 &= SPI_BASE_ALIGNMENT - 1; /* preserve only reserved, enables */
325 reg32 |= ALIGN_DOWN(base, SPI_BASE_ALIGNMENT);
326
Felix Held697fa742022-03-03 20:54:38 +0100327 pci_write_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER, reg32);
Furquan Shaikhd82c7d22020-05-09 17:18:48 -0700328}
329
330void lpc_enable_spi_rom(uint32_t enable)
331{
332 uint32_t reg32;
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600333
334 /* only two types of CS# enables are allowed */
335 enable &= SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE;
336
Felix Held697fa742022-03-03 20:54:38 +0100337 reg32 = pci_read_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER);
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600338
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600339 reg32 &= ~(SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE);
340 reg32 |= enable;
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600341
Felix Held697fa742022-03-03 20:54:38 +0100342 pci_write_config32(_LPCB_DEV, SPI_BASE_ADDRESS_REGISTER, reg32);
Marshall Dawson6ab5ed32019-05-29 09:24:18 -0600343}
Furquan Shaikh6d288022020-05-11 16:35:08 -0700344
345static void lpc_enable_controller(void)
346{
347 u8 byte;
348
349 /* Enable LPC controller */
350 byte = pm_io_read8(PM_LPC_GATING);
351 byte |= PM_LPC_ENABLE;
352 pm_io_write8(PM_LPC_GATING, byte);
353}
354
355void lpc_early_init(void)
356{
357 lpc_enable_controller();
358 lpc_disable_decodes();
359 lpc_set_spibase(SPI_BASE_ADDRESS);
360}