blob: f26d584a3844c42083ada46f50735a567b7a3cac [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. */
Patrick Georgie72a8a32012-11-06 11:05:09 +01003
Patrick Georgie72a8a32012-11-06 11:05:09 +01004#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Patrick Georgie72a8a32012-11-06 11:05:09 +01006#include <device/device.h>
7#include <device/pci.h>
8#include <console/console.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +03009#include "chip.h"
Patrick Georgie72a8a32012-11-06 11:05:09 +010010#include "i82801ix.h"
11
12typedef struct southbridge_intel_i82801ix_config config_t;
13
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020014static void i82801ix_enable_device(struct device *dev)
Patrick Georgie72a8a32012-11-06 11:05:09 +010015{
16 u32 reg32;
17
18 /* Enable SERR */
19 reg32 = pci_read_config32(dev, PCI_COMMAND);
20 reg32 |= PCI_COMMAND_SERR;
21 pci_write_config32(dev, PCI_COMMAND, reg32);
22}
23
24static void i82801ix_early_settings(const config_t *const info)
25{
26 /* Program FERR# as processor break event indicator. */
Stefan Taunercea31ea2018-08-11 18:45:28 +020027 RCBA32(GCS) |= (1 << 6);
28 /* BIOS must program...
29 * NB: other CIRs are handled in i82801ix_dmi_setup(). */
30 RCBA32(RCBA_CIR8) = (RCBA32(RCBA_CIR8) & ~(0x3 << 0)) | (0x2 << 0);
31 RCBA32(RCBA_FD) |= (1 << 0);
32 RCBA32(RCBA_CIR9) = (RCBA32(RCBA_CIR9) & ~(0x3 << 26)) | (0x2 << 26);
33 RCBA32(RCBA_CIR7) = (RCBA32(RCBA_CIR7) & ~(0xf << 16)) | (0x5 << 16);
34 RCBA32(RCBA_CIR13) = (RCBA32(RCBA_CIR13) & ~(0xf << 16)) | (0x5 << 16);
Stefan Tauner97c80892018-08-15 08:06:13 +020035 /* RCBA32(RCBA_CIR5) |= (1 << 0); cf. Specification Update */
Stefan Taunercea31ea2018-08-11 18:45:28 +020036 RCBA32(RCBA_CIR10) |= (3 << 16);
Patrick Georgie72a8a32012-11-06 11:05:09 +010037}
38
39static void i82801ix_pcie_init(const config_t *const info)
40{
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020041 struct device *pciePort[6];
Patrick Georgie72a8a32012-11-06 11:05:09 +010042 int i, slot_number = 1; /* Reserve slot number 0 for nb's PEG. */
43 u32 reg32;
44
45 /* PCIe - BIOS must program... */
46 for (i = 0; i < 6; ++i) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030047 pciePort[i] = pcidev_on_root(0x1c, i);
Patrick Georgie72a8a32012-11-06 11:05:09 +010048 if (!pciePort[i]) {
49 printk(BIOS_EMERG, "PCIe port 00:1c.%x", i);
50 die(" is not listed in devicetree.\n");
51 }
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030052 reg32 = pci_read_config32(pciePort[i], 0x300);
53 pci_write_config32(pciePort[i], 0x300, reg32 | (1 << 21));
54 pci_write_config8(pciePort[i], 0x324, 0x40);
Patrick Georgie72a8a32012-11-06 11:05:09 +010055 }
56
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030057 if (LPC_IS_MOBILE(pcidev_on_root(0x1f, 0))) {
Patrick Georgie72a8a32012-11-06 11:05:09 +010058 for (i = 0; i < 6; ++i) {
59 if (pciePort[i]->enabled) {
60 reg32 = pci_read_config32(pciePort[i], 0xe8);
61 reg32 |= 1;
62 pci_write_config32(pciePort[i], 0xe8, reg32);
63 }
64 }
65 }
66
67 for (i = 5; (i >= 0) && !pciePort[i]->enabled; --i) {
68 /* Only for the top disabled ports. */
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030069 reg32 = pci_read_config32(pciePort[i], 0x300);
Patrick Georgie72a8a32012-11-06 11:05:09 +010070 reg32 |= 0x3 << 16;
Kyösti Mälkki9b143e12013-07-26 08:35:09 +030071 pci_write_config32(pciePort[i], 0x300, reg32);
Patrick Georgie72a8a32012-11-06 11:05:09 +010072 }
73
74 /* Set slot implemented, slot number and slot power limits. */
75 for (i = 0; i < 6; ++i) {
Elyes HAOUAS8aa50732018-05-13 13:34:58 +020076 struct device *const dev = pciePort[i];
Patrick Georgie72a8a32012-11-06 11:05:09 +010077 u32 xcap = pci_read_config32(dev, D28Fx_XCAP);
78 if (info->pcie_slot_implemented & (1 << i))
79 xcap |= PCI_EXP_FLAGS_SLOT;
80 else
81 xcap &= ~PCI_EXP_FLAGS_SLOT;
82 pci_write_config32(dev, D28Fx_XCAP, xcap);
83
84 if (info->pcie_slot_implemented & (1 << i)) {
85 u32 slcap = pci_read_config32(dev, D28Fx_SLCAP);
86 slcap &= ~(0x1fff << 19);
87 slcap |= (slot_number++ << 19);
88 slcap &= ~(0x0003 << 16);
89 slcap |= (info->pcie_power_limits[i].scale << 16);
90 slcap &= ~(0x00ff << 7);
91 slcap |= (info->pcie_power_limits[i].value << 7);
92 pci_write_config32(dev, D28Fx_SLCAP, slcap);
93 }
94 }
95
96 /* Lock R/WO ASPM support bits. */
97 for (i = 0; i < 6; ++i) {
98 reg32 = pci_read_config32(pciePort[i], 0x4c);
99 pci_write_config32(pciePort[i], 0x4c, reg32);
100 }
101}
102
103static void i82801ix_ehci_init(void)
104{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300105 struct device *const pciEHCI1 = pcidev_on_root(0x1d, 7);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100106 if (!pciEHCI1)
107 die("EHCI controller (00:1d.7) not listed in devicetree.\n");
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300108 struct device *const pciEHCI2 = pcidev_on_root(0x1a, 7);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100109 if (!pciEHCI2)
110 die("EHCI controller (00:1a.7) not listed in devicetree.\n");
111
112 u32 reg32;
113
114 /* TODO: Maybe we have to save and
115 restore these settings across S3. */
116 reg32 = pci_read_config32(pciEHCI1, 0xfc);
117 pci_write_config32(pciEHCI1, 0xfc, (reg32 & ~(3 << 2)) |
118 (1 << 29) | (1 << 17) | (2 << 2));
119 reg32 = pci_read_config32(pciEHCI2, 0xfc);
120 pci_write_config32(pciEHCI2, 0xfc, (reg32 & ~(3 << 2)) |
121 (1 << 29) | (1 << 17) | (2 << 2));
122}
123
Martin Rothff744bf2019-10-23 21:46:03 -0600124static int i82801ix_function_disabled(const unsigned int devfn)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100125{
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300126 struct device *const dev = pcidev_path_on_root(devfn);
Patrick Georgie72a8a32012-11-06 11:05:09 +0100127 if (!dev) {
128 printk(BIOS_EMERG,
129 "PCI device 00:%x.%x",
130 PCI_SLOT(devfn), PCI_FUNC(devfn));
131 die(" is not listed in devicetree.\n");
132 }
133 return !dev->enabled;
134}
135
136static void i82801ix_hide_functions(void)
137{
138 int i;
139 u32 reg32;
140
141 /* FIXME: This works pretty good if the devicetree is consistent. But
142 some functions have to be disabled in right order and/or have
143 other constraints. */
144
145 if (i82801ix_function_disabled(PCI_DEVFN(0x19, 0)))
146 RCBA32(RCBA_BUC) |= BUC_LAND;
147
148 reg32 = RCBA32(RCBA_FD);
149 struct {
150 int devfn;
151 u32 mask;
152 } functions[] = {
153 { PCI_DEVFN(0x1a, 0), FD_U4D }, /* UHCI #4 */
154 { PCI_DEVFN(0x1a, 1), FD_U5D }, /* UHCI #5 */
155 { PCI_DEVFN(0x1a, 2), FD_U6D }, /* UHCI #6 */
156 { PCI_DEVFN(0x1a, 7), FD_EHCI2D }, /* EHCI #2 */
157 { PCI_DEVFN(0x1b, 0), FD_HDAD }, /* HD Audio */
158 { PCI_DEVFN(0x1c, 0), FD_PE1D }, /* PCIe #1 */
159 { PCI_DEVFN(0x1c, 1), FD_PE2D }, /* PCIe #2 */
160 { PCI_DEVFN(0x1c, 2), FD_PE3D }, /* PCIe #3 */
161 { PCI_DEVFN(0x1c, 3), FD_PE4D }, /* PCIe #4 */
162 { PCI_DEVFN(0x1c, 4), FD_PE5D }, /* PCIe #5 */
163 { PCI_DEVFN(0x1c, 5), FD_PE6D }, /* PCIe #6 */
164 { PCI_DEVFN(0x1d, 0), FD_U1D }, /* UHCI #1 */
165 { PCI_DEVFN(0x1d, 1), FD_U2D }, /* UHCI #2 */
166 { PCI_DEVFN(0x1d, 2), FD_U3D }, /* UHCI #3 */
167 { PCI_DEVFN(0x1d, 7), FD_EHCI1D }, /* EHCI #1 */
168 { PCI_DEVFN(0x1f, 0), FD_LBD }, /* LPC */
169 { PCI_DEVFN(0x1f, 2), FD_SAD1 }, /* SATA #1 */
170 { PCI_DEVFN(0x1f, 3), FD_SD }, /* SMBus */
171 { PCI_DEVFN(0x1f, 5), FD_SAD2 }, /* SATA #2 */
172 { PCI_DEVFN(0x1f, 6), FD_TTD }, /* Thermal Throttle */
173 };
174 for (i = 0; i < ARRAY_SIZE(functions); ++i) {
175 if (i82801ix_function_disabled(functions[i].devfn))
176 reg32 |= functions[i].mask;
177 }
178 RCBA32(RCBA_FD) = reg32;
179 RCBA32(RCBA_FD) |= (1 << 0); /* BIOS must write this... */
180 RCBA32(RCBA_FDSW) |= (1 << 7); /* Lock function-disable? */
181
182 /* Hide PCIe root port PCI functions. RPFN is partially R/WO. */
183 reg32 = RCBA32(RCBA_RPFN);
184 for (i = 0; i < 6; ++i) {
185 if (i82801ix_function_disabled(PCI_DEVFN(0x1c, i)))
186 reg32 |= (1 << ((i * 4) + 3));
187 }
188 RCBA32(RCBA_RPFN) = reg32;
189
190 /* Lock R/WO UHCI controller #6 remapping. */
191 RCBA32(RCBA_MAP) = RCBA32(RCBA_MAP);
192}
193
194static void i82801ix_init(void *chip_info)
195{
196 const config_t *const info = (config_t *)chip_info;
197
198 printk(BIOS_DEBUG, "Initializing i82801ix southbridge...\n");
199
200 i82801ix_early_settings(info);
201
202 /* PCI Express setup. */
203 i82801ix_pcie_init(info);
204
205 /* EHCI configuration. */
206 i82801ix_ehci_init();
207
208 /* Now hide internal functions. We can't access them after this. */
209 i82801ix_hide_functions();
210
211 /* Reset watchdog timer. */
Julius Wernercd49cce2019-03-05 16:53:33 -0800212#if !CONFIG(HAVE_SMI_HANDLER)
Patrick Georgie72a8a32012-11-06 11:05:09 +0100213 outw(0x0008, DEFAULT_TCOBASE + 0x12); /* Set higher timer value. */
214#endif
215 outw(0x0000, DEFAULT_TCOBASE + 0x00); /* Update timer. */
Patrick Georgie72a8a32012-11-06 11:05:09 +0100216}
217
218struct chip_operations southbridge_intel_i82801ix_ops = {
219 CHIP_NAME("Intel ICH9/ICH9-M (82801Ix) Series Southbridge")
220 .enable_dev = i82801ix_enable_device,
221 .init = i82801ix_init,
222};