blob: 1fb6d7ad5443afda5d23bf34e1d419a2470ac637 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
Duncan Laurie5cc51c02013-03-07 14:06:43 -08005 * Copyright 2013 Google Inc.
Aaron Durbin76c37002012-10-30 09:03:43 -05006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Aaron Durbin76c37002012-10-30 09:03:43 -050016 */
17
18#include <console/console.h>
19#include <delay.h>
Duncan Laurie5cc51c02013-03-07 14:06:43 -080020#include <arch/io.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050021#include <device/device.h>
22#include <device/pci.h>
Stefan Reinauer5605f1b2013-03-21 18:43:51 -070023#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050024#include "pch.h"
25
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010026#ifdef __SIMPLE_DEVICE__
27static pci_devfn_t pch_get_lpc_device(void)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080028{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080029 return PCI_DEV(0, 0x1f, 0);
Duncan Laurie5cc51c02013-03-07 14:06:43 -080030}
Elyes HAOUAS1dcd8db2018-12-05 10:59:42 +010031#else
32static struct device *pch_get_lpc_device(void)
33{
34 return dev_find_slot(0, PCI_DEVFN(0x1f, 0));
35}
36#endif
Aaron Durbin76c37002012-10-30 09:03:43 -050037
38int pch_silicon_revision(void)
39{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080040 static int pch_revision_id = -1;
41
Aaron Durbin76c37002012-10-30 09:03:43 -050042 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080043 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
44 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050045 return pch_revision_id;
46}
47
Tristan Corrickd3f01b22018-12-06 22:46:58 +130048int pch_silicon_id(void)
49{
50 static int pch_id = -1;
51
52 if (pch_id < 0)
53 pch_id = pci_read_config16(pch_get_lpc_device(), PCI_DEVICE_ID);
54
55 return pch_id;
56}
57
Aaron Durbin76c37002012-10-30 09:03:43 -050058int pch_silicon_type(void)
59{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080060 static int pch_type = -1;
61
Aaron Durbin76c37002012-10-30 09:03:43 -050062 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080063 pch_type = pci_read_config8(pch_get_lpc_device(),
64 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050065 return pch_type;
66}
67
Duncan Laurie5cc51c02013-03-07 14:06:43 -080068int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050069{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080070 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050071}
72
Duncan Laurie1ad55642013-03-07 14:08:04 -080073u16 get_pmbase(void)
74{
75 static u16 pmbase;
76
77 if (!pmbase)
78 pmbase = pci_read_config16(pch_get_lpc_device(),
79 PMBASE) & 0xfffc;
80 return pmbase;
81}
82
83u16 get_gpiobase(void)
84{
85 static u16 gpiobase;
86
87 if (!gpiobase)
88 gpiobase = pci_read_config16(pch_get_lpc_device(),
89 GPIOBASE) & 0xfffc;
90 return gpiobase;
91}
92
Duncan Laurie5cc51c02013-03-07 14:06:43 -080093#ifndef __SMM__
94
Duncan Laurie98c40622013-05-21 16:37:40 -070095/* Put device in D3Hot Power State */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +020096static void pch_enable_d3hot(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -050097{
Duncan Laurie98c40622013-05-21 16:37:40 -070098 u32 reg32 = pci_read_config32(dev, PCH_PCS);
99 reg32 |= PCH_PCS_PS_D3HOT;
100 pci_write_config32(dev, PCH_PCS, reg32);
101}
102
103/* Set bit in Function Disble register to hide this device */
Elyes HAOUAS38f1d132018-09-17 08:44:18 +0200104void pch_disable_devfn(struct device *dev)
Duncan Laurie98c40622013-05-21 16:37:40 -0700105{
106 switch (dev->path.pci.devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800107 case PCI_DEVFN(19, 0): /* Audio DSP */
108 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
109 break;
110 case PCI_DEVFN(20, 0): /* XHCI */
111 RCBA32_OR(FD, PCH_DISABLE_XHCI);
112 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800113 case PCI_DEVFN(21, 0): /* DMA */
Duncan Laurie98c40622013-05-21 16:37:40 -0700114 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800115 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
116 break;
117 case PCI_DEVFN(21, 1): /* I2C0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700118 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800119 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
120 break;
121 case PCI_DEVFN(21, 2): /* I2C1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700122 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800123 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
124 break;
125 case PCI_DEVFN(21, 3): /* SPI0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700126 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800127 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
128 break;
129 case PCI_DEVFN(21, 4): /* SPI1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700130 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800131 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
132 break;
133 case PCI_DEVFN(21, 5): /* UART0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700134 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800135 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
136 break;
137 case PCI_DEVFN(21, 6): /* UART1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700138 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800139 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
140 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500141 case PCI_DEVFN(22, 0): /* MEI #1 */
142 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
143 break;
144 case PCI_DEVFN(22, 1): /* MEI #2 */
145 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
146 break;
147 case PCI_DEVFN(22, 2): /* IDE-R */
148 RCBA32_OR(FD2, PCH_DISABLE_IDER);
149 break;
150 case PCI_DEVFN(22, 3): /* KT */
151 RCBA32_OR(FD2, PCH_DISABLE_KT);
152 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800153 case PCI_DEVFN(23, 0): /* SDIO */
Duncan Laurie98c40622013-05-21 16:37:40 -0700154 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800155 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
156 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500157 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
158 RCBA32_OR(BUC, PCH_DISABLE_GBE);
159 break;
160 case PCI_DEVFN(26, 0): /* EHCI #2 */
161 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
162 break;
163 case PCI_DEVFN(27, 0): /* HD Audio Controller */
164 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
165 break;
166 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
167 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
168 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
169 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
170 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
171 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
172 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
173 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700174 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(dev->path.pci.devfn)));
Aaron Durbin76c37002012-10-30 09:03:43 -0500175 break;
176 case PCI_DEVFN(29, 0): /* EHCI #1 */
177 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
178 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500179 case PCI_DEVFN(31, 0): /* LPC */
180 RCBA32_OR(FD, PCH_DISABLE_LPC);
181 break;
182 case PCI_DEVFN(31, 2): /* SATA #1 */
183 RCBA32_OR(FD, PCH_DISABLE_SATA1);
184 break;
185 case PCI_DEVFN(31, 3): /* SMBUS */
186 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
187 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800188 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500189 RCBA32_OR(FD, PCH_DISABLE_SATA2);
190 break;
191 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
192 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
193 break;
194 }
195}
196
197#define IOBP_RETRY 1000
198static inline int iobp_poll(void)
199{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800200 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500201
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800202 for (try = IOBP_RETRY; try > 0; try--) {
203 u16 status = RCBA16(IOBPS);
204 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500205 return 1;
206 udelay(10);
207 }
208
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800209 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500210 return 0;
211}
212
Aaron Durbinc17aac32013-06-19 13:12:48 -0500213u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500214{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800215 u16 status;
216
217 if (!iobp_poll())
218 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500219
220 /* Set the address */
221 RCBA32(IOBPIRI) = address;
222
223 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800224 status = RCBA16(IOBPS);
225 status &= ~IOBPS_MASK;
226 status |= IOBPS_READ;
227 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500228
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800229 /* Undocumented magic */
230 RCBA16(IOBPU) = IOBPU_MAGIC;
231
232 /* Set ready bit */
233 status = RCBA16(IOBPS);
234 status |= IOBPS_READY;
235 RCBA16(IOBPS) = status;
236
Aaron Durbin76c37002012-10-30 09:03:43 -0500237 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800238 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500239
240 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800241 status = RCBA16(IOBPS);
242 if (status & IOBPS_TX_MASK) {
243 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
244 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500245 }
246
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800247 /* Read IOBP data */
248 return RCBA32(IOBPD);
249}
250
Aaron Durbinc17aac32013-06-19 13:12:48 -0500251void pch_iobp_write(u32 address, u32 data)
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800252{
253 u16 status;
Aaron Durbinc17aac32013-06-19 13:12:48 -0500254
255 if (!iobp_poll())
256 return;
257
258 /* Set the address */
259 RCBA32(IOBPIRI) = address;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800260
261 /* WRITE OPCODE */
262 status = RCBA16(IOBPS);
263 status &= ~IOBPS_MASK;
264 status |= IOBPS_WRITE;
265 RCBA16(IOBPS) = status;
266
Aaron Durbin76c37002012-10-30 09:03:43 -0500267 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800268
269 /* Undocumented magic */
270 RCBA16(IOBPU) = IOBPU_MAGIC;
271
272 /* Set ready bit */
273 status = RCBA16(IOBPS);
274 status |= IOBPS_READY;
275 RCBA16(IOBPS) = status;
276
Aaron Durbin76c37002012-10-30 09:03:43 -0500277 if (!iobp_poll())
278 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800279
280 /* Check for successful transaction */
281 status = RCBA16(IOBPS);
282 if (status & IOBPS_TX_MASK) {
283 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
284 return;
285 }
286
287 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500288}
289
Aaron Durbinc17aac32013-06-19 13:12:48 -0500290void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
291{
292 u32 data = pch_iobp_read(address);
293
294 /* Update the data */
295 data &= andvalue;
296 data |= orvalue;
297
298 pch_iobp_write(address, data);
299}
300
Elyes HAOUAS38f1d132018-09-17 08:44:18 +0200301void pch_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500302{
303 u32 reg32;
304
Aaron Durbinc0254e62013-06-20 01:20:30 -0500305 /* PCH PCIe Root Ports are handled in PCIe driver. */
Aaron Durbin76c37002012-10-30 09:03:43 -0500306 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500307 return;
Aaron Durbin76c37002012-10-30 09:03:43 -0500308
309 if (!dev->enabled) {
310 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
311
312 /* Ensure memory, io, and bus master are all disabled */
313 reg32 = pci_read_config32(dev, PCI_COMMAND);
314 reg32 &= ~(PCI_COMMAND_MASTER |
315 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
316 pci_write_config32(dev, PCI_COMMAND, reg32);
317
Aaron Durbin3fcd3562013-06-19 13:20:37 -0500318 /* Disable this device if possible */
319 pch_disable_devfn(dev);
Aaron Durbin76c37002012-10-30 09:03:43 -0500320 } else {
321 /* Enable SERR */
322 reg32 = pci_read_config32(dev, PCI_COMMAND);
323 reg32 |= PCI_COMMAND_SERR;
324 pci_write_config32(dev, PCI_COMMAND, reg32);
325 }
326}
327
328struct chip_operations southbridge_intel_lynxpoint_ops = {
329 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
330 .enable_dev = pch_enable,
331};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800332
333#endif /* __SMM__ */