blob: 815a205dd0924a3ddf75293200c1d6f6d58bc2b8 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Arthur Heymans7b9c1392017-04-09 20:40:39 +02002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +02007#include <option.h>
Arthur Heymans7b9c1392017-04-09 20:40:39 +02008#include <pc80/mc146818rtc.h>
9#include <pc80/isa-dma.h>
10#include <pc80/i8259.h>
11#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020012#include <device/pci_ops.h>
Arthur Heymans7b9c1392017-04-09 20:40:39 +020013#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070014#include <acpi/acpi.h>
Arthur Heymans7b9c1392017-04-09 20:40:39 +020015#include <cpu/x86/smm.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070016#include <acpi/acpigen.h>
Arthur Heymansad501492017-04-12 00:15:39 +020017#include <arch/smp/mpspec.h>
Arthur Heymans7b9c1392017-04-09 20:40:39 +020018#include <cbmem.h>
19#include <string.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030020#include "chip.h"
Arthur Heymans349e0852017-04-09 20:48:37 +020021#include "i82801jx.h"
Arthur Heymans7b9c1392017-04-09 20:40:39 +020022#include "nvs.h"
23#include <southbridge/intel/common/pciehp.h>
Arthur Heymansa8a9f342017-12-24 08:11:13 +010024#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymans7b9c1392017-04-09 20:40:39 +020025
26#define NMI_OFF 0
27
Arthur Heymans349e0852017-04-09 20:48:37 +020028typedef struct southbridge_intel_i82801jx_config config_t;
Arthur Heymans7b9c1392017-04-09 20:40:39 +020029
Arthur Heymans349e0852017-04-09 20:48:37 +020030static void i82801jx_enable_apic(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +020031{
32 u32 reg32;
33 volatile u32 *ioapic_index = (volatile u32 *)(IO_APIC_ADDR);
34 volatile u32 *ioapic_data = (volatile u32 *)(IO_APIC_ADDR + 0x10);
35
36 /* Enable IOAPIC. Keep APIC Range Select at zero. */
37 RCBA8(0x31ff) = 0x03;
38 /* We have to read 0x31ff back if bit0 changed. */
39 RCBA8(0x31ff);
40
41 /* Lock maximum redirection entries (MRE), R/WO register. */
42 *ioapic_index = 0x01;
43 reg32 = *ioapic_data;
44 *ioapic_index = 0x01;
45 *ioapic_data = reg32;
46
47 setup_ioapic(VIO_APIC_VADDR, 2); /* ICH7 code uses id 2. */
48}
49
Arthur Heymans349e0852017-04-09 20:48:37 +020050static void i82801jx_enable_serial_irqs(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +020051{
52 /* Set packet length and toggle silent mode bit for one frame. */
53 pci_write_config8(dev, D31F0_SERIRQ_CNTL,
54 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
55}
56
57/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
58 * 0x00 - 0000 = Reserved
59 * 0x01 - 0001 = Reserved
60 * 0x02 - 0010 = Reserved
61 * 0x03 - 0011 = IRQ3
62 * 0x04 - 0100 = IRQ4
63 * 0x05 - 0101 = IRQ5
64 * 0x06 - 0110 = IRQ6
65 * 0x07 - 0111 = IRQ7
66 * 0x08 - 1000 = Reserved
67 * 0x09 - 1001 = IRQ9
68 * 0x0A - 1010 = IRQ10
69 * 0x0B - 1011 = IRQ11
70 * 0x0C - 1100 = IRQ12
71 * 0x0D - 1101 = Reserved
72 * 0x0E - 1110 = IRQ14
73 * 0x0F - 1111 = IRQ15
74 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
75 * 0x80 - The PIRQ is not routed.
76 */
77
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +020078static void i82801jx_pirq_init(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +020079{
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +020080 struct device *irq_dev;
Arthur Heymans7b9c1392017-04-09 20:40:39 +020081
Arthur Heymans87af36a2017-04-12 10:53:30 +020082 /* Interrupt 11 is not used by legacy devices and so can always be used
83 * for PCI interrupts. Full legacy IRQ routing is complicated and hard
84 * to get right. Fortunately all modern OS use MSI and so it's not that
85 * big of an issue anyway. Still we have to provide a reasonable
86 * default. Using interrupt 11 for it everywhere is a working default.
87 * ACPI-aware OS can move it to any interrupt and others will just leave
88 * them at default.
89 */
90 const u8 pirq_routing = 11;
Arthur Heymans7b9c1392017-04-09 20:40:39 +020091
Arthur Heymans87af36a2017-04-12 10:53:30 +020092 pci_write_config8(dev, D31F0_PIRQA_ROUT, pirq_routing);
93 pci_write_config8(dev, D31F0_PIRQB_ROUT, pirq_routing);
94 pci_write_config8(dev, D31F0_PIRQC_ROUT, pirq_routing);
95 pci_write_config8(dev, D31F0_PIRQD_ROUT, pirq_routing);
96
97 pci_write_config8(dev, D31F0_PIRQE_ROUT, pirq_routing);
98 pci_write_config8(dev, D31F0_PIRQF_ROUT, pirq_routing);
99 pci_write_config8(dev, D31F0_PIRQG_ROUT, pirq_routing);
100 pci_write_config8(dev, D31F0_PIRQH_ROUT, pirq_routing);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200101
102 /* Eric Biederman once said we should let the OS do this.
103 * I am not so sure anymore he was right.
104 */
105
106 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Arthur Heymans87af36a2017-04-12 10:53:30 +0200107 u8 int_pin = 0;
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200108
109 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
110 continue;
111
112 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
113
Arthur Heymans87af36a2017-04-12 10:53:30 +0200114 if (int_pin == 0)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200115 continue;
116
Arthur Heymans87af36a2017-04-12 10:53:30 +0200117 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200118 }
119}
120
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +0200121static void i82801jx_gpi_routing(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200122{
123 /* Get the chip configuration */
124 config_t *config = dev->chip_info;
125 u32 reg32 = 0;
126
127 /* An array would be much nicer here, or some
128 * other method of doing this.
129 */
130 reg32 |= (config->gpi0_routing & 0x03) << 0;
131 reg32 |= (config->gpi1_routing & 0x03) << 2;
132 reg32 |= (config->gpi2_routing & 0x03) << 4;
133 reg32 |= (config->gpi3_routing & 0x03) << 6;
134 reg32 |= (config->gpi4_routing & 0x03) << 8;
135 reg32 |= (config->gpi5_routing & 0x03) << 10;
136 reg32 |= (config->gpi6_routing & 0x03) << 12;
137 reg32 |= (config->gpi7_routing & 0x03) << 14;
138 reg32 |= (config->gpi8_routing & 0x03) << 16;
139 reg32 |= (config->gpi9_routing & 0x03) << 18;
140 reg32 |= (config->gpi10_routing & 0x03) << 20;
141 reg32 |= (config->gpi11_routing & 0x03) << 22;
142 reg32 |= (config->gpi12_routing & 0x03) << 24;
143 reg32 |= (config->gpi13_routing & 0x03) << 26;
144 reg32 |= (config->gpi14_routing & 0x03) << 28;
145 reg32 |= (config->gpi15_routing & 0x03) << 30;
146
147 pci_write_config32(dev, D31F0_GPIO_ROUT, reg32);
148}
149
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +0200150static void i82801jx_power_options(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200151{
152 u8 reg8;
153 u16 reg16, pmbase;
154 u32 reg32;
155 const char *state;
156 /* Get the chip configuration */
157 config_t *config = dev->chip_info;
158
Nico Huber9faae2b2018-11-14 00:00:35 +0100159 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200160 int nmi_option;
161
162 /* BIOS must program... */
Angel Pons2048cb42020-06-08 02:09:33 +0200163 pci_or_config32(dev, 0xac, (1 << 30) | (3 << 8));
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200164
165 /* Which state do we want to goto after g3 (power restored)?
166 * 0 == S0 Full On
167 * 1 == S5 Soft Off
168 *
169 * If the option is not existent (Laptops), use MAINBOARD_POWER_ON.
170 */
171 pwr_on = MAINBOARD_POWER_ON;
172 get_option(&pwr_on, "power_on_after_fail");
173
174 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
175 reg8 &= 0xfe;
176 switch (pwr_on) {
177 case MAINBOARD_POWER_OFF:
178 reg8 |= 1;
179 state = "off";
180 break;
181 case MAINBOARD_POWER_ON:
182 reg8 &= ~1;
183 state = "on";
184 break;
185 case MAINBOARD_POWER_KEEP:
186 reg8 &= ~1;
187 state = "state keep";
188 break;
189 default:
190 state = "undefined";
191 }
192
193 reg8 |= (3 << 4); /* avoid #S4 assertions */
194 reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */
195
196 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
197 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
198
199 /* Set up NMI on errors. */
200 reg8 = inb(0x61);
201 reg8 &= 0x0f; /* Higher Nibble must be 0 */
202 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
203 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
204 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
205 outb(reg8, 0x61);
206
207 reg8 = inb(0x74); /* Read from 0x74 as 0x70 is write only. */
208 nmi_option = NMI_OFF;
209 get_option(&nmi_option, "nmi");
210 if (nmi_option) {
211 printk(BIOS_INFO, "NMI sources enabled.\n");
212 reg8 &= ~(1 << 7); /* Set NMI. */
213 } else {
214 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200215 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200216 }
217 outb(reg8, 0x70);
218
219 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
220 reg16 = pci_read_config16(dev, D31F0_GEN_PMCON_1);
221 reg16 &= ~(3 << 0); // SMI# rate 1 minute
222 reg16 |= (1 << 2); // CLKRUN_EN - Mobile/Ultra only
223 reg16 |= (1 << 3); // Speedstep Enable - Mobile/Ultra only
224 reg16 |= (1 << 5); // CPUSLP_EN Desktop only
225
226 if (config->c4onc3_enable)
227 reg16 |= (1 << 7);
228
229 // another laptop wants this?
230 // reg16 &= ~(1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
231 reg16 |= (1 << 10); // BIOS_PCI_EXP_EN - Desktop/Mobile only
Kyösti Mälkki94464472020-06-13 13:45:42 +0300232 if (CONFIG(DEBUG_PERIODIC_SMI))
233 reg16 |= (3 << 0); // Periodic SMI every 8s
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200234 if (config->c5_enable)
235 reg16 |= (1 << 11); /* Enable C5, C6 and PMSYNC# */
236 pci_write_config16(dev, D31F0_GEN_PMCON_1, reg16);
237
238 /* Set exit timings for C5/C6. */
239 if (config->c5_enable) {
240 reg8 = pci_read_config8(dev, D31F0_C5_EXIT_TIMING);
241 reg8 &= ~((7 << 3) | (7 << 0));
242 if (config->c6_enable)
243 reg8 |= (5 << 3) | (3 << 0); /* 38-44us PMSYNC# to STPCLK#,
244 95-102us DPRSTP# to STP_CPU# */
245 else
246 reg8 |= (0 << 3) | (1 << 0); /* 16-17us PMSYNC# to STPCLK#,
247 34-40us DPRSTP# to STP_CPU# */
248 pci_write_config8(dev, D31F0_C5_EXIT_TIMING, reg8);
249 }
250
251 // Set the board's GPI routing.
Arthur Heymans349e0852017-04-09 20:48:37 +0200252 i82801jx_gpi_routing(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200253
254 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
255
256 outl(config->gpe0_en, pmbase + 0x28);
257 outw(config->alt_gp_smi_en, pmbase + 0x38);
258
259 /* Set up power management block and determine sleep mode */
260 reg16 = inw(pmbase + 0x00); /* PM1_STS */
261 outw(reg16, pmbase + 0x00); /* Clear status bits. At least bit11 (power
262 button override) must be cleared or SCI
263 will be constantly fired and OSPM must
264 not know about it (ACPI spec says to
265 ignore the bit). */
266 reg32 = inl(pmbase + 0x04); // PM1_CNT
267 reg32 &= ~(7 << 10); // SLP_TYP
268 outl(reg32, pmbase + 0x04);
269
270 /* Set duty cycle for hardware throttling (defaults to 0x0: 50%). */
271 reg32 = inl(pmbase + 0x10);
272 reg32 &= ~(7 << 5);
273 reg32 |= (config->throttle_duty & 7) << 5;
274 outl(reg32, pmbase + 0x10);
275}
276
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +0200277static void i82801jx_configure_cstates(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200278{
Angel Pons2048cb42020-06-08 02:09:33 +0200279 // Enable Popup & Popdown
280 pci_or_config8(dev, D31F0_CxSTATE_CNF, (1 << 4) | (1 << 3) | (1 << 2));
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200281
282 // Set Deeper Sleep configuration to recommended values
Angel Pons2048cb42020-06-08 02:09:33 +0200283 // Deeper Sleep to Stop CPU: 34-40us
284 // Deeper Sleep to Sleep: 15us
285 pci_update_config8(dev, D31F0_C4TIMING_CNT, ~0x0f, (2 << 2) | (2 << 0));
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200286
287 /* We could enable slow-C4 exit here, if someone needs it? */
288}
289
Arthur Heymans349e0852017-04-09 20:48:37 +0200290static void i82801jx_rtc_init(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200291{
292 u8 reg8;
293 int rtc_failed;
294
295 reg8 = pci_read_config8(dev, D31F0_GEN_PMCON_3);
296 rtc_failed = reg8 & RTC_BATTERY_DEAD;
297 if (rtc_failed) {
298 reg8 &= ~RTC_BATTERY_DEAD;
299 pci_write_config8(dev, D31F0_GEN_PMCON_3, reg8);
300 }
301 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
302
303 cmos_init(rtc_failed);
304}
305
306static void enable_hpet(void)
307{
308 u32 reg32;
309
310 /* Move HPET to default address 0xfed00000 and enable it */
311 reg32 = RCBA32(RCBA_HPTC);
312 reg32 |= (1 << 7); // HPET Address Enable
313 reg32 &= ~(3 << 0);
314 RCBA32(RCBA_HPTC) = reg32;
315}
316
317static void enable_clock_gating(void)
318{
319 u32 reg32;
320
321 /* Enable DMI dynamic clock gating. */
322 RCBA32(RCBA_DMIC) |= 3;
323
324 /* Enable Clock Gating for most devices. */
325 reg32 = RCBA32(RCBA_CG);
326 reg32 |= (1 << 31); /* LPC dynamic clock gating */
327 /* USB UHCI dynamic clock gating: */
328 reg32 |= (1 << 29) | (1 << 28);
329 /* SATA dynamic clock gating [0-3]: */
330 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
331 reg32 |= (1 << 23); /* LAN static clock gating (if LAN disabled) */
332 reg32 |= (1 << 22); /* HD audio dynamic clock gating */
333 reg32 &= ~(1 << 21); /* No HD audio static clock gating */
334 reg32 &= ~(1 << 20); /* No USB EHCI static clock gating */
335 reg32 |= (1 << 19); /* USB EHCI dynamic clock gating */
336 /* More SATA dynamic clock gating [4-5]: */
337 reg32 |= (1 << 18) | (1 << 17);
338 reg32 |= (1 << 16); /* PCI dynamic clock gating */
339 /* PCIe, DMI dynamic clock gating: */
340 reg32 |= (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
341 reg32 |= (1 << 0); /* PCIe root port static clock gating */
342 RCBA32(RCBA_CG) = reg32;
343
344 /* Enable SPI dynamic clock gating. */
345 RCBA32(0x38c0) |= 7;
346}
347
Kyösti Mälkki83d6a8a2019-07-12 08:16:53 +0300348static void i82801jx_set_acpi_mode(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200349{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300350 if (!acpi_is_wakeup_s3()) {
351 apm_control(APM_CNT_ACPI_DISABLE);
352 } else {
353 apm_control(APM_CNT_ACPI_ENABLE);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200354 }
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200355}
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200356
357static void lpc_init(struct device *dev)
358{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100359 printk(BIOS_DEBUG, "i82801jx: %s\n", __func__);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200360
361 /* Set the value for PCI command register. */
362 pci_write_config16(dev, PCI_COMMAND, 0x000f);
363
364 /* IO APIC initialization. */
Arthur Heymans349e0852017-04-09 20:48:37 +0200365 i82801jx_enable_apic(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200366
Arthur Heymans349e0852017-04-09 20:48:37 +0200367 i82801jx_enable_serial_irqs(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200368
369 /* Setup the PIRQ. */
Arthur Heymans349e0852017-04-09 20:48:37 +0200370 i82801jx_pirq_init(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200371
372 /* Setup power options. */
Arthur Heymans349e0852017-04-09 20:48:37 +0200373 i82801jx_power_options(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200374
375 /* Configure Cx state registers */
376 if (LPC_IS_MOBILE(dev))
Arthur Heymans349e0852017-04-09 20:48:37 +0200377 i82801jx_configure_cstates(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200378
379 /* Initialize the real time clock. */
Arthur Heymans349e0852017-04-09 20:48:37 +0200380 i82801jx_rtc_init(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200381
382 /* Initialize ISA DMA. */
383 isa_dma_init();
384
385 /* Initialize the High Precision Event Timers, if present. */
386 enable_hpet();
387
388 /* Initialize Clock Gating */
389 enable_clock_gating();
390
391 setup_i8259();
392
393 /* The OS should do this? */
394 /* Interrupt 9 should be level triggered (SCI) */
395 i8259_configure_irq_trigger(9, 1);
396
Kyösti Mälkki44da9e72019-10-09 12:32:16 +0300397 i82801jx_set_acpi_mode(dev);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200398}
399
Arthur Heymansad501492017-04-12 00:15:39 +0200400unsigned long acpi_fill_madt(unsigned long current)
401{
402 /* Local APICs */
403 current = acpi_create_madt_lapics(current);
404
405 /* IOAPIC */
406 current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current,
407 2, IO_APIC_ADDR, 0);
408
409 /* LAPIC_NMI */
410 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)
411 current, 0,
412 MP_IRQ_POLARITY_HIGH |
413 MP_IRQ_TRIGGER_EDGE, 0x01);
414 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)
415 current, 1, MP_IRQ_POLARITY_HIGH |
416 MP_IRQ_TRIGGER_EDGE, 0x01);
417
418 /* INT_SRC_OVR */
419 current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
420 current, 0, 0, 2, MP_IRQ_POLARITY_HIGH | MP_IRQ_TRIGGER_EDGE);
421 current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
422 current, 0, 9, 9, MP_IRQ_POLARITY_HIGH | MP_IRQ_TRIGGER_LEVEL);
423
424
425 return current;
426}
427
Elyes HAOUAS1a8c1df2018-05-13 13:36:44 +0200428static void i82801jx_lpc_read_resources(struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200429{
Arthur Heymanse5dcaf12017-04-12 00:03:37 +0200430 int i, io_index = 0;
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200431 /*
432 * I/O Resources
433 *
434 * 0x0000 - 0x000f....ISA DMA
435 * 0x0010 - 0x001f....ISA DMA aliases
436 * 0x0020 ~ 0x003d....PIC
437 * 0x002e - 0x002f....Maybe Super I/O
438 * 0x0040 - 0x0043....Timer
439 * 0x004e - 0x004f....Maybe Super I/O
440 * 0x0050 - 0x0053....Timer aliases
441 * 0x0061.............NMI_SC
442 * 0x0070.............NMI_EN (readable in alternative access mode)
443 * 0x0070 - 0x0077....RTC
444 * 0x0080 - 0x008f....ISA DMA
445 * 0x0090 ~ 0x009f....ISA DMA aliases
446 * 0x0092.............Fast A20 and Init
447 * 0x00a0 ~ 0x00bd....PIC
448 * 0x00b2 - 0x00b3....APM
449 * 0x00c0 ~ 0x00de....ISA DMA
450 * 0x00c1 ~ 0x00df....ISA DMA aliases
451 * 0x00f0.............Coprocessor Error
452 * (0x0400-0x041f)....SMBus (SMBUS_IO_BASE, during raminit)
453 * 0x04d0 - 0x04d1....PIC
454 * 0x0500 - 0x057f....PM (DEFAULT_PMBASE)
455 * 0x0580 - 0x05bf....SB GPIO (DEFAULT_GPIOBASE)
456 * 0x05c0 - 0x05ff....SB GPIO cont. (mobile only)
457 * 0x0cf8 - 0x0cff....PCI
458 * 0x0cf9.............Reset Control
459 */
460
461 struct resource *res;
462
463 /* Get the normal PCI resources of this device. */
464 pci_dev_read_resources(dev);
465
466 /* Add an extra subtractive resource for both memory and I/O. */
Arthur Heymanse5dcaf12017-04-12 00:03:37 +0200467 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200468 res->base = 0;
469 res->size = 0x1000;
470 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
471 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
472
Arthur Heymanse5dcaf12017-04-12 00:03:37 +0200473 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
474 res->base = 0xff000000;
475 res->size = 0x01000000; /* 16 MB for flash */
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200476 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
477 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
478
479 res = new_resource(dev, 3); /* IOAPIC */
480 res->base = IO_APIC_ADDR;
481 res->size = 0x00001000;
482 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Arthur Heymanse5dcaf12017-04-12 00:03:37 +0200483
484 /* Set IO decode ranges if required.*/
485 for (i = 0; i < 4; i++) {
486 u32 gen_dec;
487 gen_dec = pci_read_config32(dev, 0x84 + 4 * i);
488
489 if ((gen_dec & 0xFFFC) > 0x1000) {
490 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
491 res->base = gen_dec & 0xFFFC;
492 res->size = (gen_dec >> 16) & 0xFC;
493 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
494 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
495 }
496 }
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200497}
498
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700499static void southbridge_inject_dsdt(const struct device *dev)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200500{
501 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
502
503 if (gnvs) {
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200504 memset(gnvs, 0, sizeof(*gnvs));
505 acpi_create_gnvs(gnvs);
506
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200507 /* And tell SMI about it */
Kyösti Mälkkic3c55212020-06-17 10:34:26 +0300508 apm_control(APM_CNT_GNVS_UPDATE);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200509
510 /* Add it to SSDT. */
511 acpigen_write_scope("\\");
512 acpigen_write_name_dword("NVSA", (u32) gnvs);
513 acpigen_pop_len();
514 }
515}
516
Arthur Heymansa8a9f342017-12-24 08:11:13 +0100517static const char *lpc_acpi_name(const struct device *dev)
518{
519 return "LPCB";
520}
521
Furquan Shaikh7536a392020-04-24 21:59:21 -0700522static void southbridge_fill_ssdt(const struct device *device)
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200523{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300524 struct device *dev = pcidev_on_root(0x1f, 0);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200525 config_t *chip = dev->chip_info;
526
527 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Arthur Heymansa8a9f342017-12-24 08:11:13 +0100528 intel_acpi_gen_def_acpi_pirq(device);
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200529}
530
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200531static struct device_operations device_ops = {
Arthur Heymans349e0852017-04-09 20:48:37 +0200532 .read_resources = i82801jx_lpc_read_resources,
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200533 .set_resources = pci_dev_set_resources,
534 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200535 .acpi_inject_dsdt = southbridge_inject_dsdt,
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200536 .write_acpi_tables = acpi_write_hpet,
Nico Huber68680dd2020-03-31 17:34:52 +0200537 .acpi_fill_ssdt = southbridge_fill_ssdt,
Arthur Heymansa8a9f342017-12-24 08:11:13 +0100538 .acpi_name = lpc_acpi_name,
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200539 .init = lpc_init,
Nico Huber51b75ae2019-03-14 16:02:05 +0100540 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200541 .ops_pci = &pci_dev_ops_pci,
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200542};
543
544static const unsigned short pci_device_ids[] = {
Arthur Heymans349e0852017-04-09 20:48:37 +0200545 0x3a10, /* ICH10R Eng. Sample */
546 0x3a14, /* ICH10DO */
547 0x3a16, /* ICH10R */
548 0x3a18, /* ICH10 */
549 0x3a1a, /* ICH10D */
550 0x3a1e, /* ICH10 Eng. Sample */
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200551 0
552};
553
Arthur Heymans349e0852017-04-09 20:48:37 +0200554static const struct pci_driver ich10_lpc __pci_driver = {
Arthur Heymans7b9c1392017-04-09 20:40:39 +0200555 .ops = &device_ops,
556 .vendor = PCI_VENDOR_ID_INTEL,
557 .devices = pci_device_ids,
558};