blob: 7feed3461099ac539eae9955a3a0410cf9854398 [file] [log] [blame]
Patrick Georgie72a8a32012-11-06 11:05:09 +01001/*
2 * This file is part of the coreboot project.
3 *
Patrick Georgie72a8a32012-11-06 11:05:09 +01004 *
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.
Patrick Georgie72a8a32012-11-06 11:05:09 +010014 */
15
Patrick Georgie72a8a32012-11-06 11:05:09 +010016#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020017#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +010018#include <device/device.h>
19#include <device/pci.h>
20#include <console/console.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030021#include "chip.h"
Patrick Georgie72a8a32012-11-06 11:05:09 +010022#include "i82801ix.h"
23
24typedef struct southbridge_intel_i82801ix_config config_t;
25
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020026static void i82801ix_enable_device(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010027{
28 u32 reg32;
29
30 /* Enable SERR */
31 reg32 = pci_read_config32(dev, PCI_COMMAND);
32 reg32 |= PCI_COMMAND_SERR;
33 pci_write_config32(dev, PCI_COMMAND, reg32);
34}
35
36static void i82801ix_early_settings(const config_t *const info)
37{
38 /* Program FERR# as processor break event indicator. */
Stefan Taunercea31ea2018-08-11 18:45:28 +020039 RCBA32(GCS) |= (1 << 6);
40 /* BIOS must program...
41 * NB: other CIRs are handled in i82801ix_dmi_setup(). */
42 RCBA32(RCBA_CIR8) = (RCBA32(RCBA_CIR8) & ~(0x3 << 0)) | (0x2 << 0);
43 RCBA32(RCBA_FD) |= (1 << 0);
44 RCBA32(RCBA_CIR9) = (RCBA32(RCBA_CIR9) & ~(0x3 << 26)) | (0x2 << 26);
45 RCBA32(RCBA_CIR7) = (RCBA32(RCBA_CIR7) & ~(0xf << 16)) | (0x5 << 16);
46 RCBA32(RCBA_CIR13) = (RCBA32(RCBA_CIR13) & ~(0xf << 16)) | (0x5 << 16);
Stefan Tauner97c80892018-08-15 08:06:13 +020047 /* RCBA32(RCBA_CIR5) |= (1 << 0); cf. Specification Update */
Stefan Taunercea31ea2018-08-11 18:45:28 +020048 RCBA32(RCBA_CIR10) |= (3 << 16);
Patrick Georgie72a8a32012-11-06 11:05:09 +010049}
50
51static void i82801ix_pcie_init(const config_t *const info)
52{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020053 struct device *pciePort[6];
Patrick Georgie72a8a32012-11-06 11:05:09 +010054 int i, slot_number = 1; /* Reserve slot number 0 for nb's PEG. */
55 u32 reg32;
56
57 /* PCIe - BIOS must program... */
58 for (i = 0; i < 6; ++i) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030059 pciePort[i] = pcidev_on_root(0x1c, i);
Patrick Georgie72a8a32012-11-06 11:05:09 +010060 if (!pciePort[i]) {
61 printk(BIOS_EMERG, "PCIe port 00:1c.%x", i);
62 die(" is not listed in devicetree.\n");
63 }
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030064 reg32 = pci_read_config32(pciePort[i], 0x300);
65 pci_write_config32(pciePort[i], 0x300, reg32 | (1 << 21));
66 pci_write_config8(pciePort[i], 0x324, 0x40);
Patrick Georgie72a8a32012-11-06 11:05:09 +010067 }
68
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030069 if (LPC_IS_MOBILE(pcidev_on_root(0x1f, 0))) {
Patrick Georgie72a8a32012-11-06 11:05:09 +010070 for (i = 0; i < 6; ++i) {
71 if (pciePort[i]->enabled) {
72 reg32 = pci_read_config32(pciePort[i], 0xe8);
73 reg32 |= 1;
74 pci_write_config32(pciePort[i], 0xe8, reg32);
75 }
76 }
77 }
78
79 for (i = 5; (i >= 0) && !pciePort[i]->enabled; --i) {
80 /* Only for the top disabled ports. */
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030081 reg32 = pci_read_config32(pciePort[i], 0x300);
Patrick Georgie72a8a32012-11-06 11:05:09 +010082 reg32 |= 0x3 << 16;
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030083 pci_write_config32(pciePort[i], 0x300, reg32);
Patrick Georgie72a8a32012-11-06 11:05:09 +010084 }
85
86 /* Set slot implemented, slot number and slot power limits. */
87 for (i = 0; i < 6; ++i) {
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020088 struct device *const dev = pciePort[i];
Patrick Georgie72a8a32012-11-06 11:05:09 +010089 u32 xcap = pci_read_config32(dev, D28Fx_XCAP);
90 if (info->pcie_slot_implemented & (1 << i))
91 xcap |= PCI_EXP_FLAGS_SLOT;
92 else
93 xcap &= ~PCI_EXP_FLAGS_SLOT;
94 pci_write_config32(dev, D28Fx_XCAP, xcap);
95
96 if (info->pcie_slot_implemented & (1 << i)) {
97 u32 slcap = pci_read_config32(dev, D28Fx_SLCAP);
98 slcap &= ~(0x1fff << 19);
99 slcap |= (slot_number++ << 19);
100 slcap &= ~(0x0003 << 16);
101 slcap |= (info->pcie_power_limits[i].scale << 16);
102 slcap &= ~(0x00ff << 7);
103 slcap |= (info->pcie_power_limits[i].value << 7);
104 pci_write_config32(dev, D28Fx_SLCAP, slcap);
105 }
106 }
107
108 /* Lock R/WO ASPM support bits. */
109 for (i = 0; i < 6; ++i) {
110 reg32 = pci_read_config32(pciePort[i], 0x4c);
111 pci_write_config32(pciePort[i], 0x4c, reg32);
112 }
113}
114
115static void i82801ix_ehci_init(void)
116{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300117 struct device *const pciEHCI1 = pcidev_on_root(0x1d, 7);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100118 if (!pciEHCI1)
119 die("EHCI controller (00:1d.7) not listed in devicetree.\n");
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300120 struct device *const pciEHCI2 = pcidev_on_root(0x1a, 7);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100121 if (!pciEHCI2)
122 die("EHCI controller (00:1a.7) not listed in devicetree.\n");
123
124 u32 reg32;
125
126 /* TODO: Maybe we have to save and
127 restore these settings across S3. */
128 reg32 = pci_read_config32(pciEHCI1, 0xfc);
129 pci_write_config32(pciEHCI1, 0xfc, (reg32 & ~(3 << 2)) |
130 (1 << 29) | (1 << 17) | (2 << 2));
131 reg32 = pci_read_config32(pciEHCI2, 0xfc);
132 pci_write_config32(pciEHCI2, 0xfc, (reg32 & ~(3 << 2)) |
133 (1 << 29) | (1 << 17) | (2 << 2));
134}
135
Martin Rothff744bf2019-10-23 21:46:03 -0600136static int i82801ix_function_disabled(const unsigned int devfn)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100137{
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300138 struct device *const dev = pcidev_path_on_root(devfn);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100139 if (!dev) {
140 printk(BIOS_EMERG,
141 "PCI device 00:%x.%x",
142 PCI_SLOT(devfn), PCI_FUNC(devfn));
143 die(" is not listed in devicetree.\n");
144 }
145 return !dev->enabled;
146}
147
148static void i82801ix_hide_functions(void)
149{
150 int i;
151 u32 reg32;
152
153 /* FIXME: This works pretty good if the devicetree is consistent. But
154 some functions have to be disabled in right order and/or have
155 other constraints. */
156
157 if (i82801ix_function_disabled(PCI_DEVFN(0x19, 0)))
158 RCBA32(RCBA_BUC) |= BUC_LAND;
159
160 reg32 = RCBA32(RCBA_FD);
161 struct {
162 int devfn;
163 u32 mask;
164 } functions[] = {
165 { PCI_DEVFN(0x1a, 0), FD_U4D }, /* UHCI #4 */
166 { PCI_DEVFN(0x1a, 1), FD_U5D }, /* UHCI #5 */
167 { PCI_DEVFN(0x1a, 2), FD_U6D }, /* UHCI #6 */
168 { PCI_DEVFN(0x1a, 7), FD_EHCI2D }, /* EHCI #2 */
169 { PCI_DEVFN(0x1b, 0), FD_HDAD }, /* HD Audio */
170 { PCI_DEVFN(0x1c, 0), FD_PE1D }, /* PCIe #1 */
171 { PCI_DEVFN(0x1c, 1), FD_PE2D }, /* PCIe #2 */
172 { PCI_DEVFN(0x1c, 2), FD_PE3D }, /* PCIe #3 */
173 { PCI_DEVFN(0x1c, 3), FD_PE4D }, /* PCIe #4 */
174 { PCI_DEVFN(0x1c, 4), FD_PE5D }, /* PCIe #5 */
175 { PCI_DEVFN(0x1c, 5), FD_PE6D }, /* PCIe #6 */
176 { PCI_DEVFN(0x1d, 0), FD_U1D }, /* UHCI #1 */
177 { PCI_DEVFN(0x1d, 1), FD_U2D }, /* UHCI #2 */
178 { PCI_DEVFN(0x1d, 2), FD_U3D }, /* UHCI #3 */
179 { PCI_DEVFN(0x1d, 7), FD_EHCI1D }, /* EHCI #1 */
180 { PCI_DEVFN(0x1f, 0), FD_LBD }, /* LPC */
181 { PCI_DEVFN(0x1f, 2), FD_SAD1 }, /* SATA #1 */
182 { PCI_DEVFN(0x1f, 3), FD_SD }, /* SMBus */
183 { PCI_DEVFN(0x1f, 5), FD_SAD2 }, /* SATA #2 */
184 { PCI_DEVFN(0x1f, 6), FD_TTD }, /* Thermal Throttle */
185 };
186 for (i = 0; i < ARRAY_SIZE(functions); ++i) {
187 if (i82801ix_function_disabled(functions[i].devfn))
188 reg32 |= functions[i].mask;
189 }
190 RCBA32(RCBA_FD) = reg32;
191 RCBA32(RCBA_FD) |= (1 << 0); /* BIOS must write this... */
192 RCBA32(RCBA_FDSW) |= (1 << 7); /* Lock function-disable? */
193
194 /* Hide PCIe root port PCI functions. RPFN is partially R/WO. */
195 reg32 = RCBA32(RCBA_RPFN);
196 for (i = 0; i < 6; ++i) {
197 if (i82801ix_function_disabled(PCI_DEVFN(0x1c, i)))
198 reg32 |= (1 << ((i * 4) + 3));
199 }
200 RCBA32(RCBA_RPFN) = reg32;
201
202 /* Lock R/WO UHCI controller #6 remapping. */
203 RCBA32(RCBA_MAP) = RCBA32(RCBA_MAP);
204}
205
206static void i82801ix_init(void *chip_info)
207{
208 const config_t *const info = (config_t *)chip_info;
209
210 printk(BIOS_DEBUG, "Initializing i82801ix southbridge...\n");
211
212 i82801ix_early_settings(info);
213
214 /* PCI Express setup. */
215 i82801ix_pcie_init(info);
216
217 /* EHCI configuration. */
218 i82801ix_ehci_init();
219
220 /* Now hide internal functions. We can't access them after this. */
221 i82801ix_hide_functions();
222
223 /* Reset watchdog timer. */
Julius Wernercd49cce2019-03-05 16:53:33 -0800224#if !CONFIG(HAVE_SMI_HANDLER)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100225 outw(0x0008, DEFAULT_TCOBASE + 0x12); /* Set higher timer value. */
226#endif
227 outw(0x0000, DEFAULT_TCOBASE + 0x00); /* Update timer. */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100228}
229
230struct chip_operations southbridge_intel_i82801ix_ops = {
231 CHIP_NAME("Intel ICH9/ICH9-M (82801Ix) Series Southbridge")
232 .enable_dev = i82801ix_enable_device,
233 .init = i82801ix_init,
234};