blob: 1a390cca42aa7e2a667a54d7c3181b994d7ee4dd [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
Duncan Laurie5cc51c02013-03-07 14:06:43 -080026static device_t pch_get_lpc_device(void)
27{
28#ifdef __SMM__
29 return PCI_DEV(0, 0x1f, 0);
30#else
31 return dev_find_slot(0, PCI_DEVFN(0x1f, 0));
32#endif
33}
Aaron Durbin76c37002012-10-30 09:03:43 -050034
35int pch_silicon_revision(void)
36{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080037 static int pch_revision_id = -1;
38
Aaron Durbin76c37002012-10-30 09:03:43 -050039 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080040 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
41 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050042 return pch_revision_id;
43}
44
45int pch_silicon_type(void)
46{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080047 static int pch_type = -1;
48
Aaron Durbin76c37002012-10-30 09:03:43 -050049 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080050 pch_type = pci_read_config8(pch_get_lpc_device(),
51 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050052 return pch_type;
53}
54
Duncan Laurie5cc51c02013-03-07 14:06:43 -080055int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050056{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080057 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050058}
59
Duncan Laurie1ad55642013-03-07 14:08:04 -080060u16 get_pmbase(void)
61{
62 static u16 pmbase;
63
64 if (!pmbase)
65 pmbase = pci_read_config16(pch_get_lpc_device(),
66 PMBASE) & 0xfffc;
67 return pmbase;
68}
69
70u16 get_gpiobase(void)
71{
72 static u16 gpiobase;
73
74 if (!gpiobase)
75 gpiobase = pci_read_config16(pch_get_lpc_device(),
76 GPIOBASE) & 0xfffc;
77 return gpiobase;
78}
79
Duncan Laurie5cc51c02013-03-07 14:06:43 -080080#ifndef __SMM__
81
Duncan Laurie98c40622013-05-21 16:37:40 -070082/* Put device in D3Hot Power State */
83static void pch_enable_d3hot(device_t dev)
Aaron Durbin76c37002012-10-30 09:03:43 -050084{
Duncan Laurie98c40622013-05-21 16:37:40 -070085 u32 reg32 = pci_read_config32(dev, PCH_PCS);
86 reg32 |= PCH_PCS_PS_D3HOT;
87 pci_write_config32(dev, PCH_PCS, reg32);
88}
89
90/* Set bit in Function Disble register to hide this device */
Aaron Durbin3fcd3562013-06-19 13:20:37 -050091void pch_disable_devfn(device_t dev)
Duncan Laurie98c40622013-05-21 16:37:40 -070092{
93 switch (dev->path.pci.devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -080094 case PCI_DEVFN(19, 0): /* Audio DSP */
95 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
96 break;
97 case PCI_DEVFN(20, 0): /* XHCI */
98 RCBA32_OR(FD, PCH_DISABLE_XHCI);
99 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800100 case PCI_DEVFN(21, 0): /* DMA */
Duncan Laurie98c40622013-05-21 16:37:40 -0700101 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800102 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
103 break;
104 case PCI_DEVFN(21, 1): /* I2C0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700105 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800106 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
107 break;
108 case PCI_DEVFN(21, 2): /* I2C1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700109 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800110 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
111 break;
112 case PCI_DEVFN(21, 3): /* SPI0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700113 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800114 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
115 break;
116 case PCI_DEVFN(21, 4): /* SPI1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700117 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800118 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
119 break;
120 case PCI_DEVFN(21, 5): /* UART0 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700121 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800122 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
123 break;
124 case PCI_DEVFN(21, 6): /* UART1 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700125 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800126 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
127 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500128 case PCI_DEVFN(22, 0): /* MEI #1 */
129 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
130 break;
131 case PCI_DEVFN(22, 1): /* MEI #2 */
132 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
133 break;
134 case PCI_DEVFN(22, 2): /* IDE-R */
135 RCBA32_OR(FD2, PCH_DISABLE_IDER);
136 break;
137 case PCI_DEVFN(22, 3): /* KT */
138 RCBA32_OR(FD2, PCH_DISABLE_KT);
139 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800140 case PCI_DEVFN(23, 0): /* SDIO */
Duncan Laurie98c40622013-05-21 16:37:40 -0700141 pch_enable_d3hot(dev);
Duncan Laurie71346c02013-01-10 13:20:40 -0800142 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
143 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500144 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
145 RCBA32_OR(BUC, PCH_DISABLE_GBE);
146 break;
147 case PCI_DEVFN(26, 0): /* EHCI #2 */
148 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
149 break;
150 case PCI_DEVFN(27, 0): /* HD Audio Controller */
151 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
152 break;
153 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
154 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
155 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
156 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
157 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
158 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
159 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
160 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
Duncan Laurie98c40622013-05-21 16:37:40 -0700161 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(dev->path.pci.devfn)));
Aaron Durbin76c37002012-10-30 09:03:43 -0500162 break;
163 case PCI_DEVFN(29, 0): /* EHCI #1 */
164 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
165 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500166 case PCI_DEVFN(31, 0): /* LPC */
167 RCBA32_OR(FD, PCH_DISABLE_LPC);
168 break;
169 case PCI_DEVFN(31, 2): /* SATA #1 */
170 RCBA32_OR(FD, PCH_DISABLE_SATA1);
171 break;
172 case PCI_DEVFN(31, 3): /* SMBUS */
173 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
174 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800175 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500176 RCBA32_OR(FD, PCH_DISABLE_SATA2);
177 break;
178 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
179 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
180 break;
181 }
182}
183
184#define IOBP_RETRY 1000
185static inline int iobp_poll(void)
186{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800187 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500188
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800189 for (try = IOBP_RETRY; try > 0; try--) {
190 u16 status = RCBA16(IOBPS);
191 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500192 return 1;
193 udelay(10);
194 }
195
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800196 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500197 return 0;
198}
199
Aaron Durbinc17aac32013-06-19 13:12:48 -0500200u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500201{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800202 u16 status;
203
204 if (!iobp_poll())
205 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500206
207 /* Set the address */
208 RCBA32(IOBPIRI) = address;
209
210 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800211 status = RCBA16(IOBPS);
212 status &= ~IOBPS_MASK;
213 status |= IOBPS_READ;
214 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500215
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800216 /* Undocumented magic */
217 RCBA16(IOBPU) = IOBPU_MAGIC;
218
219 /* Set ready bit */
220 status = RCBA16(IOBPS);
221 status |= IOBPS_READY;
222 RCBA16(IOBPS) = status;
223
Aaron Durbin76c37002012-10-30 09:03:43 -0500224 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800225 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500226
227 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800228 status = RCBA16(IOBPS);
229 if (status & IOBPS_TX_MASK) {
230 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
231 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500232 }
233
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800234 /* Read IOBP data */
235 return RCBA32(IOBPD);
236}
237
Aaron Durbinc17aac32013-06-19 13:12:48 -0500238void pch_iobp_write(u32 address, u32 data)
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800239{
240 u16 status;
Aaron Durbinc17aac32013-06-19 13:12:48 -0500241
242 if (!iobp_poll())
243 return;
244
245 /* Set the address */
246 RCBA32(IOBPIRI) = address;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800247
248 /* WRITE OPCODE */
249 status = RCBA16(IOBPS);
250 status &= ~IOBPS_MASK;
251 status |= IOBPS_WRITE;
252 RCBA16(IOBPS) = status;
253
Aaron Durbin76c37002012-10-30 09:03:43 -0500254 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800255
256 /* Undocumented magic */
257 RCBA16(IOBPU) = IOBPU_MAGIC;
258
259 /* Set ready bit */
260 status = RCBA16(IOBPS);
261 status |= IOBPS_READY;
262 RCBA16(IOBPS) = status;
263
Aaron Durbin76c37002012-10-30 09:03:43 -0500264 if (!iobp_poll())
265 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800266
267 /* Check for successful transaction */
268 status = RCBA16(IOBPS);
269 if (status & IOBPS_TX_MASK) {
270 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
271 return;
272 }
273
274 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500275}
276
Aaron Durbinc17aac32013-06-19 13:12:48 -0500277void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
278{
279 u32 data = pch_iobp_read(address);
280
281 /* Update the data */
282 data &= andvalue;
283 data |= orvalue;
284
285 pch_iobp_write(address, data);
286}
287
Aaron Durbin76c37002012-10-30 09:03:43 -0500288void pch_enable(device_t dev)
289{
290 u32 reg32;
291
Aaron Durbinc0254e62013-06-20 01:20:30 -0500292 /* PCH PCIe Root Ports are handled in PCIe driver. */
Aaron Durbin76c37002012-10-30 09:03:43 -0500293 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500294 return;
Aaron Durbin76c37002012-10-30 09:03:43 -0500295
296 if (!dev->enabled) {
297 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
298
299 /* Ensure memory, io, and bus master are all disabled */
300 reg32 = pci_read_config32(dev, PCI_COMMAND);
301 reg32 &= ~(PCI_COMMAND_MASTER |
302 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
303 pci_write_config32(dev, PCI_COMMAND, reg32);
304
Aaron Durbin3fcd3562013-06-19 13:20:37 -0500305 /* Disable this device if possible */
306 pch_disable_devfn(dev);
Aaron Durbin76c37002012-10-30 09:03:43 -0500307 } else {
308 /* Enable SERR */
309 reg32 = pci_read_config32(dev, PCI_COMMAND);
310 reg32 |= PCI_COMMAND_SERR;
311 pci_write_config32(dev, PCI_COMMAND, reg32);
312 }
313}
314
315struct chip_operations southbridge_intel_lynxpoint_ops = {
316 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
317 .enable_dev = pch_enable,
318};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800319
320#endif /* __SMM__ */