blob: b8060a22dd36699a7f519c38344c0b4909164318 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Aaron Durbin76c37002012-10-30 09:03:43 -05003
4#include <console/console.h>
5#include <delay.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05007#include <device/device.h>
8#include <device/pci.h>
Stefan Reinauer5605f1b2013-03-21 18:43:51 -07009#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050010#include "pch.h"
11
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010012#ifdef __SIMPLE_DEVICE__
13static pci_devfn_t pch_get_lpc_device(void)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080014{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080015 return PCI_DEV(0, 0x1f, 0);
Duncan Laurie5cc51c02013-03-07 14:06:43 -080016}
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010017#else
18static struct device *pch_get_lpc_device(void)
19{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030020 return pcidev_on_root(0x1f, 0);
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010021}
22#endif
Aaron Durbin76c37002012-10-30 09:03:43 -050023
24int pch_silicon_revision(void)
25{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080026 static int pch_revision_id = -1;
27
Aaron Durbin76c37002012-10-30 09:03:43 -050028 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080029 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
30 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050031 return pch_revision_id;
32}
33
Tristan Corrickd3f01b22018-12-06 22:46:58 +130034int pch_silicon_id(void)
35{
36 static int pch_id = -1;
37
38 if (pch_id < 0)
39 pch_id = pci_read_config16(pch_get_lpc_device(), PCI_DEVICE_ID);
40
41 return pch_id;
42}
43
Aaron Durbin76c37002012-10-30 09:03:43 -050044int pch_silicon_type(void)
45{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080046 static int pch_type = -1;
47
Aaron Durbin76c37002012-10-30 09:03:43 -050048 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080049 pch_type = pci_read_config8(pch_get_lpc_device(),
50 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050051 return pch_type;
52}
53
Duncan Laurie5cc51c02013-03-07 14:06:43 -080054int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050055{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080056 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050057}
58
Duncan Laurie1ad55642013-03-07 14:08:04 -080059u16 get_pmbase(void)
60{
61 static u16 pmbase;
62
63 if (!pmbase)
64 pmbase = pci_read_config16(pch_get_lpc_device(),
65 PMBASE) & 0xfffc;
66 return pmbase;
67}
68
69u16 get_gpiobase(void)
70{
71 static u16 gpiobase;
72
73 if (!gpiobase)
74 gpiobase = pci_read_config16(pch_get_lpc_device(),
75 GPIOBASE) & 0xfffc;
76 return gpiobase;
77}
78
Kyösti Mälkki21d6a272019-11-05 18:50:38 +020079#ifndef __SIMPLE_DEVICE__
Duncan Laurie5cc51c02013-03-07 14:06:43 -080080
Duncan Laurie98c40622013-05-21 16:37:40 -070081/* Put device in D3Hot Power State */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +020082static void pch_enable_d3hot(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -050083{
Duncan Laurie98c40622013-05-21 16:37:40 -070084 u32 reg32 = pci_read_config32(dev, PCH_PCS);
85 reg32 |= PCH_PCS_PS_D3HOT;
86 pci_write_config32(dev, PCH_PCS, reg32);
87}
88
Frans Hendrikse6bf51f2019-05-01 10:48:31 +020089/* Set bit in function disable register to hide this device */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +020090void pch_disable_devfn(struct device *dev)
Duncan Laurie98c40622013-05-21 16:37:40 -070091{
92 switch (dev->path.pci.devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -080093 case PCI_DEVFN(19, 0): /* Audio DSP */
94 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
95 break;
96 case PCI_DEVFN(20, 0): /* XHCI */
97 RCBA32_OR(FD, PCH_DISABLE_XHCI);
98 break;
Duncan Laurie71346c02013-01-10 13:20:40 -080099 case PCI_DEVFN(21, 0): /* DMA */
Duncan Laurie98c40622013-05-21 16:37:40 -0700100 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800101 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
102 break;
103 case PCI_DEVFN(21, 1): /* I2C0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700104 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800105 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
106 break;
107 case PCI_DEVFN(21, 2): /* I2C1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700108 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800109 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
110 break;
111 case PCI_DEVFN(21, 3): /* SPI0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700112 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800113 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
114 break;
115 case PCI_DEVFN(21, 4): /* SPI1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700116 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800117 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
118 break;
119 case PCI_DEVFN(21, 5): /* UART0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700120 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800121 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
122 break;
123 case PCI_DEVFN(21, 6): /* UART1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700124 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800125 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
126 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500127 case PCI_DEVFN(22, 0): /* MEI #1 */
128 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
129 break;
130 case PCI_DEVFN(22, 1): /* MEI #2 */
131 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
132 break;
133 case PCI_DEVFN(22, 2): /* IDE-R */
134 RCBA32_OR(FD2, PCH_DISABLE_IDER);
135 break;
136 case PCI_DEVFN(22, 3): /* KT */
137 RCBA32_OR(FD2, PCH_DISABLE_KT);
138 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800139 case PCI_DEVFN(23, 0): /* SDIO */
Duncan Laurie98c40622013-05-21 16:37:40 -0700140 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800141 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
142 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500143 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
144 RCBA32_OR(BUC, PCH_DISABLE_GBE);
145 break;
146 case PCI_DEVFN(26, 0): /* EHCI #2 */
147 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
148 break;
149 case PCI_DEVFN(27, 0): /* HD Audio Controller */
150 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
151 break;
152 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
153 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
154 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
155 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
156 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
157 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
158 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
159 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700160 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(dev->path.pci.devfn)));
Aaron Durbin76c37002012-10-30 09:03:43 -0500161 break;
162 case PCI_DEVFN(29, 0): /* EHCI #1 */
163 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
164 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500165 case PCI_DEVFN(31, 0): /* LPC */
166 RCBA32_OR(FD, PCH_DISABLE_LPC);
167 break;
168 case PCI_DEVFN(31, 2): /* SATA #1 */
169 RCBA32_OR(FD, PCH_DISABLE_SATA1);
170 break;
171 case PCI_DEVFN(31, 3): /* SMBUS */
172 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
173 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800174 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500175 RCBA32_OR(FD, PCH_DISABLE_SATA2);
176 break;
177 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
178 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
179 break;
180 }
181}
182
183#define IOBP_RETRY 1000
184static inline int iobp_poll(void)
185{
Martin Rothff744bf2019-10-23 21:46:03 -0600186 unsigned int try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500187
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800188 for (try = IOBP_RETRY; try > 0; try--) {
189 u16 status = RCBA16(IOBPS);
190 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500191 return 1;
192 udelay(10);
193 }
194
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800195 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500196 return 0;
197}
198
Aaron Durbinc17aac32013-06-19 13:12:48 -0500199u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500200{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800201 u16 status;
202
203 if (!iobp_poll())
204 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500205
206 /* Set the address */
207 RCBA32(IOBPIRI) = address;
208
209 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800210 status = RCBA16(IOBPS);
211 status &= ~IOBPS_MASK;
212 status |= IOBPS_READ;
213 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500214
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800215 /* Undocumented magic */
216 RCBA16(IOBPU) = IOBPU_MAGIC;
217
218 /* Set ready bit */
219 status = RCBA16(IOBPS);
220 status |= IOBPS_READY;
221 RCBA16(IOBPS) = status;
222
Aaron Durbin76c37002012-10-30 09:03:43 -0500223 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800224 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500225
226 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800227 status = RCBA16(IOBPS);
228 if (status & IOBPS_TX_MASK) {
229 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
230 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500231 }
232
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800233 /* Read IOBP data */
234 return RCBA32(IOBPD);
235}
236
Aaron Durbinc17aac32013-06-19 13:12:48 -0500237void pch_iobp_write(u32 address, u32 data)
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800238{
239 u16 status;
Aaron Durbinc17aac32013-06-19 13:12:48 -0500240
241 if (!iobp_poll())
242 return;
243
244 /* Set the address */
245 RCBA32(IOBPIRI) = address;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800246
247 /* WRITE OPCODE */
248 status = RCBA16(IOBPS);
249 status &= ~IOBPS_MASK;
250 status |= IOBPS_WRITE;
251 RCBA16(IOBPS) = status;
252
Aaron Durbin76c37002012-10-30 09:03:43 -0500253 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800254
255 /* Undocumented magic */
256 RCBA16(IOBPU) = IOBPU_MAGIC;
257
258 /* Set ready bit */
259 status = RCBA16(IOBPS);
260 status |= IOBPS_READY;
261 RCBA16(IOBPS) = status;
262
Aaron Durbin76c37002012-10-30 09:03:43 -0500263 if (!iobp_poll())
264 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800265
266 /* Check for successful transaction */
267 status = RCBA16(IOBPS);
268 if (status & IOBPS_TX_MASK) {
269 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
270 return;
271 }
272
273 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500274}
275
Aaron Durbinc17aac32013-06-19 13:12:48 -0500276void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
277{
278 u32 data = pch_iobp_read(address);
279
280 /* Update the data */
281 data &= andvalue;
282 data |= orvalue;
283
284 pch_iobp_write(address, data);
285}
286
Elyes HAOUAS38f1d132018-09-17 08:44:18 +0200287void pch_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500288{
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200289 u16 reg16;
Aaron Durbin76c37002012-10-30 09:03:43 -0500290
Aaron Durbinc0254e62013-06-20 01:20:30 -0500291 /* PCH PCIe Root Ports are handled in PCIe driver. */
Aaron Durbin76c37002012-10-30 09:03:43 -0500292 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500293 return;
Aaron Durbin76c37002012-10-30 09:03:43 -0500294
295 if (!dev->enabled) {
296 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
297
298 /* Ensure memory, io, and bus master are all disabled */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200299 reg16 = pci_read_config16(dev, PCI_COMMAND);
300 reg16 &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
301 pci_write_config16(dev, PCI_COMMAND, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500302
Aaron Durbin3fcd3562013-06-19 13:20:37 -0500303 /* Disable this device if possible */
304 pch_disable_devfn(dev);
Aaron Durbin76c37002012-10-30 09:03:43 -0500305 } else {
306 /* Enable SERR */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200307 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
Aaron Durbin76c37002012-10-30 09:03:43 -0500308 }
309}
310
311struct chip_operations southbridge_intel_lynxpoint_ops = {
312 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
313 .enable_dev = pch_enable,
314};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800315
Kyösti Mälkki21d6a272019-11-05 18:50:38 +0200316#endif /* __SIMPLE_DEVICE__ */