blob: 1413d9441d394a3c440f78c4d7fbf674df48038e [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
Aaron Durbin76c37002012-10-30 09:03:43 -05004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; version 2 of
8 * the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Aaron Durbin76c37002012-10-30 09:03:43 -050014 */
15
16#include <console/console.h>
17#include <delay.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020018#include <device/pci_ops.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050019#include <device/device.h>
20#include <device/pci.h>
Stefan Reinauer5605f1b2013-03-21 18:43:51 -070021#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050022#include "pch.h"
23
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010024#ifdef __SIMPLE_DEVICE__
25static pci_devfn_t pch_get_lpc_device(void)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080026{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080027 return PCI_DEV(0, 0x1f, 0);
Duncan Laurie5cc51c02013-03-07 14:06:43 -080028}
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010029#else
30static struct device *pch_get_lpc_device(void)
31{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030032 return pcidev_on_root(0x1f, 0);
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010033}
34#endif
Aaron Durbin76c37002012-10-30 09:03:43 -050035
36int pch_silicon_revision(void)
37{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080038 static int pch_revision_id = -1;
39
Aaron Durbin76c37002012-10-30 09:03:43 -050040 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080041 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
42 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050043 return pch_revision_id;
44}
45
Tristan Corrickd3f01b22018-12-06 22:46:58 +130046int pch_silicon_id(void)
47{
48 static int pch_id = -1;
49
50 if (pch_id < 0)
51 pch_id = pci_read_config16(pch_get_lpc_device(), PCI_DEVICE_ID);
52
53 return pch_id;
54}
55
Aaron Durbin76c37002012-10-30 09:03:43 -050056int pch_silicon_type(void)
57{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080058 static int pch_type = -1;
59
Aaron Durbin76c37002012-10-30 09:03:43 -050060 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080061 pch_type = pci_read_config8(pch_get_lpc_device(),
62 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050063 return pch_type;
64}
65
Duncan Laurie5cc51c02013-03-07 14:06:43 -080066int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050067{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080068 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050069}
70
Duncan Laurie1ad55642013-03-07 14:08:04 -080071u16 get_pmbase(void)
72{
73 static u16 pmbase;
74
75 if (!pmbase)
76 pmbase = pci_read_config16(pch_get_lpc_device(),
77 PMBASE) & 0xfffc;
78 return pmbase;
79}
80
81u16 get_gpiobase(void)
82{
83 static u16 gpiobase;
84
85 if (!gpiobase)
86 gpiobase = pci_read_config16(pch_get_lpc_device(),
87 GPIOBASE) & 0xfffc;
88 return gpiobase;
89}
90
Kyösti Mälkki21d6a272019-11-05 18:50:38 +020091#ifndef __SIMPLE_DEVICE__
Duncan Laurie5cc51c02013-03-07 14:06:43 -080092
Duncan Laurie98c40622013-05-21 16:37:40 -070093/* Put device in D3Hot Power State */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +020094static void pch_enable_d3hot(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -050095{
Duncan Laurie98c40622013-05-21 16:37:40 -070096 u32 reg32 = pci_read_config32(dev, PCH_PCS);
97 reg32 |= PCH_PCS_PS_D3HOT;
98 pci_write_config32(dev, PCH_PCS, reg32);
99}
100
Frans Hendrikse6bf51f2019-05-01 10:48:31 +0200101/* Set bit in function disable register to hide this device */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +0200102void pch_disable_devfn(struct device *dev)
Duncan Laurie98c40622013-05-21 16:37:40 -0700103{
104 switch (dev->path.pci.devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800105 case PCI_DEVFN(19, 0): /* Audio DSP */
106 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
107 break;
108 case PCI_DEVFN(20, 0): /* XHCI */
109 RCBA32_OR(FD, PCH_DISABLE_XHCI);
110 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800111 case PCI_DEVFN(21, 0): /* DMA */
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_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
114 break;
115 case PCI_DEVFN(21, 1): /* I2C0 */
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_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
118 break;
119 case PCI_DEVFN(21, 2): /* I2C1 */
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_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
122 break;
123 case PCI_DEVFN(21, 3): /* SPI0 */
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_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
126 break;
127 case PCI_DEVFN(21, 4): /* SPI1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700128 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800129 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
130 break;
131 case PCI_DEVFN(21, 5): /* UART0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700132 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800133 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
134 break;
135 case PCI_DEVFN(21, 6): /* UART1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700136 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800137 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
138 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500139 case PCI_DEVFN(22, 0): /* MEI #1 */
140 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
141 break;
142 case PCI_DEVFN(22, 1): /* MEI #2 */
143 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
144 break;
145 case PCI_DEVFN(22, 2): /* IDE-R */
146 RCBA32_OR(FD2, PCH_DISABLE_IDER);
147 break;
148 case PCI_DEVFN(22, 3): /* KT */
149 RCBA32_OR(FD2, PCH_DISABLE_KT);
150 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800151 case PCI_DEVFN(23, 0): /* SDIO */
Duncan Laurie98c40622013-05-21 16:37:40 -0700152 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800153 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
154 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500155 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
156 RCBA32_OR(BUC, PCH_DISABLE_GBE);
157 break;
158 case PCI_DEVFN(26, 0): /* EHCI #2 */
159 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
160 break;
161 case PCI_DEVFN(27, 0): /* HD Audio Controller */
162 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
163 break;
164 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
165 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
166 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
167 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
168 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
169 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
170 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
171 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700172 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(dev->path.pci.devfn)));
Aaron Durbin76c37002012-10-30 09:03:43 -0500173 break;
174 case PCI_DEVFN(29, 0): /* EHCI #1 */
175 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
176 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500177 case PCI_DEVFN(31, 0): /* LPC */
178 RCBA32_OR(FD, PCH_DISABLE_LPC);
179 break;
180 case PCI_DEVFN(31, 2): /* SATA #1 */
181 RCBA32_OR(FD, PCH_DISABLE_SATA1);
182 break;
183 case PCI_DEVFN(31, 3): /* SMBUS */
184 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
185 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800186 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500187 RCBA32_OR(FD, PCH_DISABLE_SATA2);
188 break;
189 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
190 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
191 break;
192 }
193}
194
195#define IOBP_RETRY 1000
196static inline int iobp_poll(void)
197{
Martin Rothff744bf2019-10-23 21:46:03 -0600198 unsigned int try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500199
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800200 for (try = IOBP_RETRY; try > 0; try--) {
201 u16 status = RCBA16(IOBPS);
202 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500203 return 1;
204 udelay(10);
205 }
206
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800207 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500208 return 0;
209}
210
Aaron Durbinc17aac32013-06-19 13:12:48 -0500211u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500212{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800213 u16 status;
214
215 if (!iobp_poll())
216 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500217
218 /* Set the address */
219 RCBA32(IOBPIRI) = address;
220
221 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800222 status = RCBA16(IOBPS);
223 status &= ~IOBPS_MASK;
224 status |= IOBPS_READ;
225 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500226
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800227 /* Undocumented magic */
228 RCBA16(IOBPU) = IOBPU_MAGIC;
229
230 /* Set ready bit */
231 status = RCBA16(IOBPS);
232 status |= IOBPS_READY;
233 RCBA16(IOBPS) = status;
234
Aaron Durbin76c37002012-10-30 09:03:43 -0500235 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800236 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500237
238 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800239 status = RCBA16(IOBPS);
240 if (status & IOBPS_TX_MASK) {
241 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
242 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500243 }
244
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800245 /* Read IOBP data */
246 return RCBA32(IOBPD);
247}
248
Aaron Durbinc17aac32013-06-19 13:12:48 -0500249void pch_iobp_write(u32 address, u32 data)
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800250{
251 u16 status;
Aaron Durbinc17aac32013-06-19 13:12:48 -0500252
253 if (!iobp_poll())
254 return;
255
256 /* Set the address */
257 RCBA32(IOBPIRI) = address;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800258
259 /* WRITE OPCODE */
260 status = RCBA16(IOBPS);
261 status &= ~IOBPS_MASK;
262 status |= IOBPS_WRITE;
263 RCBA16(IOBPS) = status;
264
Aaron Durbin76c37002012-10-30 09:03:43 -0500265 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800266
267 /* Undocumented magic */
268 RCBA16(IOBPU) = IOBPU_MAGIC;
269
270 /* Set ready bit */
271 status = RCBA16(IOBPS);
272 status |= IOBPS_READY;
273 RCBA16(IOBPS) = status;
274
Aaron Durbin76c37002012-10-30 09:03:43 -0500275 if (!iobp_poll())
276 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800277
278 /* Check for successful transaction */
279 status = RCBA16(IOBPS);
280 if (status & IOBPS_TX_MASK) {
281 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
282 return;
283 }
284
285 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500286}
287
Aaron Durbinc17aac32013-06-19 13:12:48 -0500288void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
289{
290 u32 data = pch_iobp_read(address);
291
292 /* Update the data */
293 data &= andvalue;
294 data |= orvalue;
295
296 pch_iobp_write(address, data);
297}
298
Elyes HAOUAS38f1d132018-09-17 08:44:18 +0200299void pch_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500300{
301 u32 reg32;
302
Aaron Durbinc0254e62013-06-20 01:20:30 -0500303 /* PCH PCIe Root Ports are handled in PCIe driver. */
Aaron Durbin76c37002012-10-30 09:03:43 -0500304 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500305 return;
Aaron Durbin76c37002012-10-30 09:03:43 -0500306
307 if (!dev->enabled) {
308 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
309
310 /* Ensure memory, io, and bus master are all disabled */
311 reg32 = pci_read_config32(dev, PCI_COMMAND);
312 reg32 &= ~(PCI_COMMAND_MASTER |
313 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
314 pci_write_config32(dev, PCI_COMMAND, reg32);
315
Aaron Durbin3fcd3562013-06-19 13:20:37 -0500316 /* Disable this device if possible */
317 pch_disable_devfn(dev);
Aaron Durbin76c37002012-10-30 09:03:43 -0500318 } else {
319 /* Enable SERR */
320 reg32 = pci_read_config32(dev, PCI_COMMAND);
321 reg32 |= PCI_COMMAND_SERR;
322 pci_write_config32(dev, PCI_COMMAND, reg32);
323 }
324}
325
326struct chip_operations southbridge_intel_lynxpoint_ops = {
327 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
328 .enable_dev = pch_enable,
329};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800330
Kyösti Mälkki21d6a272019-11-05 18:50:38 +0200331#endif /* __SIMPLE_DEVICE__ */