lib/smbios: Improve Type9
[coreboot2.git] / src / southbridge / intel / i82801dx / lpc.c
blobc8b0760a27dedbc13839f2723e8a6ee1a54630df
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/hpet.h>
4 #include <arch/io.h>
5 #include <arch/ioapic.h>
6 #include <console/console.h>
7 #include <cpu/x86/smm.h>
8 #include <device/device.h>
9 #include <device/pci.h>
10 #include <device/pci_ids.h>
11 #include <device/pci_ops.h>
12 #include <option.h>
13 #include <pc80/i8259.h>
14 #include <pc80/isa-dma.h>
15 #include <pc80/mc146818rtc.h>
16 #include <types.h>
18 #include "chip.h"
19 #include "i82801dx.h"
21 #define NMI_OFF 0
23 typedef struct southbridge_intel_i82801dx_config config_t;
25 /**
26 * Set miscellaneous static southbridge features.
28 * @param dev PCI device with I/O APIC control registers
30 static void i82801dx_enable_ioapic(struct device *dev)
32 u32 reg32;
34 reg32 = pci_read_config32(dev, GEN_CNTL);
35 reg32 |= (1 << 13); /* Coprocessor error enable (COPR_ERR_EN) */
36 reg32 |= (3 << 7); /* IOAPIC enable (APIC_EN) */
37 reg32 |= (1 << 2); /* DMA collection buffer enable (DCB_EN) */
38 reg32 |= (1 << 1); /* Delayed transaction enable (DTE) */
39 pci_write_config32(dev, GEN_CNTL, reg32);
40 printk(BIOS_DEBUG, "IOAPIC Southbridge enabled %x\n", reg32);
42 register_new_ioapic_gsi0(IO_APIC_ADDR);
44 ioapic_set_boot_config(IO_APIC_ADDR, true);
47 static void i82801dx_enable_serial_irqs(struct device *dev)
49 /* Set packet length and toggle silent mode bit. */
50 pci_write_config8(dev, SERIRQ_CNTL,
51 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
52 pci_write_config8(dev, SERIRQ_CNTL,
53 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
56 static void i82801dx_pirq_init(struct device *dev)
58 /* Get the chip configuration */
59 config_t *config = dev->chip_info;
61 pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
62 pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
63 pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
64 pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);
65 pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
66 pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
67 pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
68 pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);
71 static void i82801dx_power_options(struct device *dev)
73 u8 reg8;
74 u16 reg16, pmbase;
75 u32 reg32;
76 const char *state;
78 /* Which state do we want to goto after g3 (power restored)?
79 * 0 == S0 Full On
80 * 1 == S5 Soft Off
82 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
84 const unsigned int pwr_on = get_uint_option("power_on_after_fail", MAINBOARD_POWER_ON);
86 reg8 = pci_read_config8(dev, GEN_PMCON_3);
87 reg8 &= 0xfe;
88 switch (pwr_on) {
89 case MAINBOARD_POWER_OFF:
90 reg8 |= 1;
91 state = "off";
92 break;
93 case MAINBOARD_POWER_ON:
94 reg8 &= ~1;
95 state = "on";
96 break;
97 case MAINBOARD_POWER_KEEP:
98 reg8 &= ~1;
99 state = "state keep";
100 break;
101 default:
102 state = "undefined";
105 reg8 &= ~(1 << 3); /* minimum assertion is 1 to 2 RTCCLK */
107 pci_write_config8(dev, GEN_PMCON_3, reg8);
108 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
110 /* Set up NMI on errors. */
111 reg8 = inb(0x61);
112 reg8 &= 0x0f; /* Higher Nibble must be 0 */
113 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
114 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
115 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
116 outb(reg8, 0x61);
118 reg8 = inb(0x70);
119 const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF);
120 if (nmi_option) {
121 printk(BIOS_INFO, "NMI sources enabled.\n");
122 reg8 &= ~(1 << 7); /* Set NMI. */
123 } else {
124 printk(BIOS_INFO, "NMI sources disabled.\n");
125 reg8 |= (1 << 7); /* Disable NMI. */
127 outb(reg8, 0x70);
129 /* Set SMI# rate down and enable CPU_SLP# */
130 reg16 = pci_read_config16(dev, GEN_PMCON_1);
131 reg16 &= ~(3 << 0); // SMI# rate 1 minute
132 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
133 pci_write_config16(dev, GEN_PMCON_1, reg16);
135 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
137 /* Set up power management block and determine sleep mode */
138 reg32 = inl(pmbase + 0x04); // PM1_CNT
140 reg32 &= ~(7 << 10); // SLP_TYP
141 reg32 |= (1 << 0); // SCI_EN
142 outl(reg32, pmbase + 0x04);
146 static void i82801dx_rtc_init(struct device *dev)
148 u8 reg8;
149 u32 reg32;
150 int rtc_failed;
152 reg8 = pci_read_config8(dev, GEN_PMCON_3);
153 rtc_failed = reg8 & RTC_BATTERY_DEAD;
154 if (rtc_failed) {
155 reg8 &= ~(1 << 1); /* Preserve the power fail state. */
156 pci_write_config8(dev, GEN_PMCON_3, reg8);
158 reg32 = pci_read_config32(dev, GEN_STS);
159 rtc_failed |= reg32 & (1 << 2);
160 cmos_init(rtc_failed);
162 /* Enable access to the upper 128 byte bank of CMOS RAM. */
163 pci_write_config8(dev, RTC_CONF, 0x04);
166 static void i82801dx_set_acpi_mode(struct device *dev)
168 if (!acpi_is_wakeup_s3()) {
169 apm_control(APM_CNT_ACPI_DISABLE);
170 } else {
171 apm_control(APM_CNT_ACPI_ENABLE);
175 static void i82801dx_lpc_route_dma(struct device *dev, u8 mask)
177 u16 reg16;
178 int i;
180 reg16 = pci_read_config16(dev, PCI_DMA_CFG);
181 reg16 &= 0x300;
182 for (i = 0; i < 8; i++) {
183 if (i == 4)
184 continue;
185 reg16 |= ((mask & (1 << i)) ? 3 : 1) << (i * 2);
187 pci_write_config16(dev, PCI_DMA_CFG, reg16);
190 /* ICH4 does not mention HPET in the docs, but
191 * all ICH3 and ICH4 do have HPETs built in.
193 static void enable_hpet(struct device *dev)
195 u32 reg32, hpet, val;
197 /* Set HPET base address and enable it */
198 printk(BIOS_DEBUG, "Enabling HPET at 0x%x\n", HPET_BASE_ADDRESS);
199 reg32 = pci_read_config32(dev, GEN_CNTL);
201 * Bit 17 is HPET enable bit.
202 * Bit 16:15 control the HPET base address.
204 reg32 &= ~(3 << 15); /* Clear it */
206 hpet = HPET_BASE_ADDRESS >> 12;
207 hpet &= 0x3;
209 reg32 |= (hpet << 15);
210 reg32 |= (1 << 17); /* Enable HPET. */
211 pci_write_config32(dev, GEN_CNTL, reg32);
213 /* Check to see whether it took */
214 reg32 = pci_read_config32(dev, GEN_CNTL);
215 val = reg32 >> 15;
216 val &= 0x7;
218 if ((val & 0x4) && (hpet == (val & 0x3))) {
219 printk(BIOS_INFO, "HPET enabled at 0x%x\n", HPET_BASE_ADDRESS);
220 } else {
221 printk(BIOS_WARNING, "HPET was not enabled correctly\n");
222 reg32 &= ~(1 << 17); /* Clear Enable */
223 pci_write_config32(dev, GEN_CNTL, reg32);
227 static void lpc_init(struct device *dev)
229 /* IO APIC initialization. */
230 i82801dx_enable_ioapic(dev);
232 i82801dx_enable_serial_irqs(dev);
234 /* Setup the PIRQ. */
235 i82801dx_pirq_init(dev);
237 /* Setup power options. */
238 i82801dx_power_options(dev);
240 /* Initialize the real time clock. */
241 i82801dx_rtc_init(dev);
243 /* Route DMA. */
244 i82801dx_lpc_route_dma(dev, 0xff);
246 /* Initialize ISA DMA. */
247 isa_dma_init();
249 /* Initialize the High Precision Event Timers */
250 enable_hpet(dev);
252 setup_i8259();
254 i82801dx_set_acpi_mode(dev);
257 static void i82801dx_lpc_read_resources(struct device *dev)
259 struct resource *res;
261 /* Get the normal PCI resources of this device. */
262 pci_dev_read_resources(dev);
264 /* Add an extra subtractive resource for both memory and I/O. */
265 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
266 res->base = 0;
267 res->size = 0x1000;
268 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
269 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
271 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
272 res->base = 0xff800000;
273 res->size = 0x00800000; /* 8 MB for flash */
274 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
275 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
277 res = new_resource(dev, 3); /* IOAPIC */
278 res->base = IO_APIC_ADDR;
279 res->size = 0x00001000;
280 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
283 static struct device_operations lpc_ops = {
284 .read_resources = i82801dx_lpc_read_resources,
285 .set_resources = pci_dev_set_resources,
286 .enable_resources = pci_dev_enable_resources,
287 .init = lpc_init,
288 .scan_bus = scan_static_bus,
289 .enable = i82801dx_enable,
292 /* 82801DB/DBL */
293 static const struct pci_driver lpc_driver_db __pci_driver = {
294 .ops = &lpc_ops,
295 .vendor = PCI_VID_INTEL,
296 .device = PCI_DID_INTEL_82801DB_LPC,
299 /* 82801DBM */
300 static const struct pci_driver lpc_driver_dbm __pci_driver = {
301 .ops = &lpc_ops,
302 .vendor = PCI_VID_INTEL,
303 .device = PCI_DID_INTEL_82801DBM_LPC,