blob: f8926dc302125aed9ff8d13fc4e2d5f7c52d0f67 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01002
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>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01008#include <pc80/mc146818rtc.h>
9#include <pc80/isa-dma.h>
10#include <pc80/i8259.h>
11#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020012#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020013#include <device/pci_ops.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010014#include <arch/ioapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070015#include <acpi/acpi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010016#include <elog.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070017#include <acpi/acpigen.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020018#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020019#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020020#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030021#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010022#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020023#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010024#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030025#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020026#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010027
28#define NMI_OFF 0
29
Vladimir Serbinenko46957052013-11-26 01:16:20 +010030typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010031
32/**
33 * Set miscellanous static southbridge features.
34 *
35 * @param dev PCI device with I/O APIC control registers
36 */
37static void pch_enable_ioapic(struct device *dev)
38{
39 u32 reg32;
40
41 /* Enable ACPI I/O range decode */
42 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
43
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080044 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010045 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080046 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
47 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010048
49 /*
50 * Select Boot Configuration register (0x03) and
51 * use Processor System Bus (0x01) to deliver interrupts.
52 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080053 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010054}
55
56static void pch_enable_serial_irqs(struct device *dev)
57{
58 /* Set packet length and toggle silent mode bit for one frame. */
59 pci_write_config8(dev, SERIRQ_CNTL,
60 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080061#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010062 pci_write_config8(dev, SERIRQ_CNTL,
63 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
64#endif
65}
66
67/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
68 * 0x00 - 0000 = Reserved
69 * 0x01 - 0001 = Reserved
70 * 0x02 - 0010 = Reserved
71 * 0x03 - 0011 = IRQ3
72 * 0x04 - 0100 = IRQ4
73 * 0x05 - 0101 = IRQ5
74 * 0x06 - 0110 = IRQ6
75 * 0x07 - 0111 = IRQ7
76 * 0x08 - 1000 = Reserved
77 * 0x09 - 1001 = IRQ9
78 * 0x0A - 1010 = IRQ10
79 * 0x0B - 1011 = IRQ11
80 * 0x0C - 1100 = IRQ12
81 * 0x0D - 1101 = Reserved
82 * 0x0E - 1110 = IRQ14
83 * 0x0F - 1111 = IRQ15
84 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
85 * 0x80 - The PIRQ is not routed.
86 */
87
Elyes HAOUASbe841402018-05-13 13:40:39 +020088static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010089{
Elyes HAOUASbe841402018-05-13 13:40:39 +020090 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020091 /* Interrupt 11 is not used by legacy devices and so can always be used for
92 PCI interrupts. Full legacy IRQ routing is complicated and hard to
93 get right. Fortunately all modern OS use MSI and so it's not that big of
94 an issue anyway. Still we have to provide a reasonable default. Using
95 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
96 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010097 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020098 const u8 pirq_routing = 11;
99
100 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
101 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
102 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
104
105 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
106 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
107 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100109
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200110 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200111 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100112
113 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
114 continue;
115
116 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
117
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200118 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100119 continue;
120
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200121 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100122 }
123}
124
Elyes HAOUASbe841402018-05-13 13:40:39 +0200125static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100126{
127 /* Get the chip configuration */
128 config_t *config = dev->chip_info;
129 u32 reg32 = 0;
130
131 /* An array would be much nicer here, or some
132 * other method of doing this.
133 */
134 reg32 |= (config->gpi0_routing & 0x03) << 0;
135 reg32 |= (config->gpi1_routing & 0x03) << 2;
136 reg32 |= (config->gpi2_routing & 0x03) << 4;
137 reg32 |= (config->gpi3_routing & 0x03) << 6;
138 reg32 |= (config->gpi4_routing & 0x03) << 8;
139 reg32 |= (config->gpi5_routing & 0x03) << 10;
140 reg32 |= (config->gpi6_routing & 0x03) << 12;
141 reg32 |= (config->gpi7_routing & 0x03) << 14;
142 reg32 |= (config->gpi8_routing & 0x03) << 16;
143 reg32 |= (config->gpi9_routing & 0x03) << 18;
144 reg32 |= (config->gpi10_routing & 0x03) << 20;
145 reg32 |= (config->gpi11_routing & 0x03) << 22;
146 reg32 |= (config->gpi12_routing & 0x03) << 24;
147 reg32 |= (config->gpi13_routing & 0x03) << 26;
148 reg32 |= (config->gpi14_routing & 0x03) << 28;
149 reg32 |= (config->gpi15_routing & 0x03) << 30;
150
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200151 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100152}
153
Elyes HAOUASbe841402018-05-13 13:40:39 +0200154static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100155{
156 u8 reg8;
157 u16 reg16, pmbase;
158 u32 reg32;
159 const char *state;
160 /* Get the chip configuration */
161 config_t *config = dev->chip_info;
162
Nico Huber9faae2b2018-11-14 00:00:35 +0100163 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100164 int nmi_option;
165
166 /* Which state do we want to goto after g3 (power restored)?
167 * 0 == S0 Full On
168 * 1 == S5 Soft Off
169 *
170 * If the option is not existent (Laptops), use Kconfig setting.
171 */
172 get_option(&pwr_on, "power_on_after_fail");
173
174 reg16 = pci_read_config16(dev, GEN_PMCON_3);
175 reg16 &= 0xfffe;
176 switch (pwr_on) {
177 case MAINBOARD_POWER_OFF:
178 reg16 |= 1;
179 state = "off";
180 break;
181 case MAINBOARD_POWER_ON:
182 reg16 &= ~1;
183 state = "on";
184 break;
185 case MAINBOARD_POWER_KEEP:
186 reg16 &= ~1;
187 state = "state keep";
188 break;
189 default:
190 state = "undefined";
191 }
192
193 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
194 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
195
196 reg16 &= ~(1 << 10);
197 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
198
199 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
200
201 pci_write_config16(dev, GEN_PMCON_3, reg16);
202 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
203
204 /* Set up NMI on errors. */
205 reg8 = inb(0x61);
206 reg8 &= 0x0f; /* Higher Nibble must be 0 */
207 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
208 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
209 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
210 outb(reg8, 0x61);
211
212 reg8 = inb(0x70);
213 nmi_option = NMI_OFF;
214 get_option(&nmi_option, "nmi");
215 if (nmi_option) {
216 printk(BIOS_INFO, "NMI sources enabled.\n");
217 reg8 &= ~(1 << 7); /* Set NMI. */
218 } else {
219 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200220 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100221 }
222 outb(reg8, 0x70);
223
224 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
225 reg16 = pci_read_config16(dev, GEN_PMCON_1);
226 reg16 &= ~(3 << 0); // SMI# rate 1 minute
227 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
228#if DEBUG_PERIODIC_SMIS
229 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
230 * periodic SMIs.
231 */
232 reg16 |= (3 << 0); // Periodic SMI every 8s
233#endif
234 pci_write_config16(dev, GEN_PMCON_1, reg16);
235
236 // Set the board's GPI routing.
237 pch_gpi_routing(dev);
238
239 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
240
241 outl(config->gpe0_en, pmbase + GPE0_EN);
242 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
243
244 /* Set up power management block and determine sleep mode */
245 reg32 = inl(pmbase + 0x04); // PM1_CNT
246 reg32 &= ~(7 << 10); // SLP_TYP
247 reg32 |= (1 << 0); // SCI_EN
248 outl(reg32, pmbase + 0x04);
249
250 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200251 reg32 = RCBA32(PRSTS);
252 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
253 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100254
Angel Pons42b4e4e2019-09-18 10:58:53 +0200255 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100256 reg32 = RCBA32(0x3f02);
257 reg32 &= ~0xf;
258 RCBA32(0x3f02) = reg32;
259}
260
261static void pch_rtc_init(struct device *dev)
262{
263 u8 reg8;
264 int rtc_failed;
265
266 reg8 = pci_read_config8(dev, GEN_PMCON_3);
267 rtc_failed = reg8 & RTC_BATTERY_DEAD;
268 if (rtc_failed) {
269 reg8 &= ~RTC_BATTERY_DEAD;
270 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100271 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100272 }
273 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
274
Gabe Blackb3f08c62014-04-30 17:12:25 -0700275 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100276}
277
278static void mobile5_pm_init(struct device *dev)
279{
280 int i;
281
282 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
283 pci_write_config8(dev, 0xa9, 0x47);
284
285 RCBA32 (0x1d44) = 0x00000000;
286 (void) RCBA32 (0x1d44);
287 RCBA32 (0x1d48) = 0x00030000;
288 (void) RCBA32 (0x1d48);
289 RCBA32 (0x1e80) = 0x000c0801;
290 (void) RCBA32 (0x1e80);
291 RCBA32 (0x1e84) = 0x000200f0;
292 (void) RCBA32 (0x1e84);
293
294 const u32 rcba2010[] =
295 {
296 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
297 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
298 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200299 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100300 {
301 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
302 RCBA32 (0x2010 + 4 * i);
303 }
304
305 RCBA32 (0x2100) = 0x00000000;
306 (void) RCBA32 (0x2100);
307 RCBA32 (0x2104) = 0x00000757;
308 (void) RCBA32 (0x2104);
309 RCBA32 (0x2108) = 0x00170001;
310 (void) RCBA32 (0x2108);
311
312 RCBA32 (0x211c) = 0x00000000;
313 (void) RCBA32 (0x211c);
314 RCBA32 (0x2120) = 0x00010000;
315 (void) RCBA32 (0x2120);
316
317 RCBA32 (0x21fc) = 0x00000000;
318 (void) RCBA32 (0x21fc);
319 RCBA32 (0x2200) = 0x20000044;
320 (void) RCBA32 (0x2200);
321 RCBA32 (0x2204) = 0x00000001;
322 (void) RCBA32 (0x2204);
323 RCBA32 (0x2208) = 0x00003457;
324 (void) RCBA32 (0x2208);
325
326 const u32 rcba2210[] =
327 {
328 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
329 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
330 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
331 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
332 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
333 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
334 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
335 };
336
Elyes HAOUAS035df002016-10-03 21:54:16 +0200337 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100338 {
339 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
340 RCBA32 (0x2210 + 4 * i);
341 }
342
343 const u32 rcba2300[] =
344 {
345 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
346 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
347 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
348 };
349
Elyes HAOUAS035df002016-10-03 21:54:16 +0200350 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100351 {
352 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
353 RCBA32 (0x2300 + 4 * i);
354 }
355
356 RCBA32 (0x37fc) = 0x00000000;
357 (void) RCBA32 (0x37fc);
358 RCBA32 (0x3dfc) = 0x00000000;
359 (void) RCBA32 (0x3dfc);
360 RCBA32 (0x3e7c) = 0xffffffff;
361 (void) RCBA32 (0x3e7c);
362 RCBA32 (0x3efc) = 0x00000000;
363 (void) RCBA32 (0x3efc);
364 RCBA32 (0x3f00) = 0x0000010b;
365 (void) RCBA32 (0x3f00);
366}
367
368static void enable_hpet(void)
369{
370 u32 reg32;
371
372 /* Move HPET to default address 0xfed00000 and enable it */
373 reg32 = RCBA32(HPTC);
374 reg32 |= (1 << 7); // HPET Address Enable
375 reg32 &= ~(3 << 0);
376 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200377 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100378
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800379 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100380}
381
Elyes HAOUASbe841402018-05-13 13:40:39 +0200382static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100383{
384 u32 reg32;
385 u16 reg16;
386
387 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
388
389 reg16 = pci_read_config16(dev, GEN_PMCON_1);
390 reg16 |= (1 << 2) | (1 << 11);
391 pci_write_config16(dev, GEN_PMCON_1, reg16);
392
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100393 reg32 = RCBA32(CG);
394 reg32 |= (1 << 31);
395 reg32 |= (1 << 29) | (1 << 28);
396 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
397 reg32 |= (1 << 16);
398 reg32 |= (1 << 17);
399 reg32 |= (1 << 18);
400 reg32 |= (1 << 22);
401 reg32 |= (1 << 23);
402 reg32 &= ~(1 << 20);
403 reg32 |= (1 << 19);
404 reg32 |= (1 << 0);
405 reg32 |= (0xf << 1);
406 RCBA32(CG) = reg32;
407
408 RCBA32_OR(0x38c0, 0x7);
409 RCBA32_OR(0x36d4, 0x6680c004);
410 RCBA32_OR(0x3564, 0x3);
411}
412
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200413static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100414{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800415 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100416 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200417 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100418 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100419 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100420}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100421
422static void pch_disable_smm_only_flashing(struct device *dev)
423{
424 u8 reg8;
425
426 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100427 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100428 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100429 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100430}
431
432static void pch_fixups(struct device *dev)
433{
434 /*
435 * Enable DMI ASPM in the PCH
436 */
437 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
438 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
439 RCBA32_OR(0x21a8, 0x3);
440}
441
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100442static void lpc_init(struct device *dev)
443{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100444 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100445
446 /* Set the value for PCI command register. */
447 pci_write_config16(dev, PCI_COMMAND, 0x000f);
448
449 /* IO APIC initialization. */
450 pch_enable_ioapic(dev);
451
452 pch_enable_serial_irqs(dev);
453
454 /* Setup the PIRQ. */
455 pch_pirq_init(dev);
456
457 /* Setup power options. */
458 pch_power_options(dev);
459
460 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200461 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100462
463 /* Set the state of the GPIO lines. */
464 //gpio_init(dev);
465
466 /* Initialize the real time clock. */
467 pch_rtc_init(dev);
468
469 /* Initialize ISA DMA. */
470 isa_dma_init();
471
472 /* Initialize the High Precision Event Timers, if present. */
473 enable_hpet();
474
475 /* Initialize Clock Gating */
476 enable_clock_gating(dev);
477
478 setup_i8259();
479
480 /* The OS should do this? */
481 /* Interrupt 9 should be level triggered (SCI) */
482 i8259_configure_irq_trigger(9, 1);
483
484 pch_disable_smm_only_flashing(dev);
485
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200486 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100487
488 pch_fixups(dev);
489}
490
Elyes HAOUASbe841402018-05-13 13:40:39 +0200491static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100492{
493 struct resource *res;
494 config_t *config = dev->chip_info;
495 u8 io_index = 0;
496
497 /* Get the normal PCI resources of this device. */
498 pci_dev_read_resources(dev);
499
500 /* Add an extra subtractive resource for both memory and I/O. */
501 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
502 res->base = 0;
503 res->size = 0x1000;
504 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
505 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
506
507 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
508 res->base = 0xff800000;
509 res->size = 0x00800000; /* 8 MB for flash */
510 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
511 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
512
513 res = new_resource(dev, 3); /* IOAPIC */
514 res->base = IO_APIC_ADDR;
515 res->size = 0x00001000;
516 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
517
518 /* Set PCH IO decode ranges if required.*/
519 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
520 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
521 res->base = config->gen1_dec & 0xFFFC;
522 res->size = (config->gen1_dec >> 16) & 0xFC;
523 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
524 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
525 }
526
527 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
528 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
529 res->base = config->gen2_dec & 0xFFFC;
530 res->size = (config->gen2_dec >> 16) & 0xFC;
531 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
532 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
533 }
534
535 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
536 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
537 res->base = config->gen3_dec & 0xFFFC;
538 res->size = (config->gen3_dec >> 16) & 0xFC;
539 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
540 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
541 }
542
543 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
544 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
545 res->base = config->gen4_dec & 0xFFFC;
546 res->size = (config->gen4_dec >> 16) & 0xFC;
547 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
548 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
549 }
550}
551
Elyes HAOUASbe841402018-05-13 13:40:39 +0200552static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100553{
554 /* Enable PCH Display Port */
555 RCBA16(DISPBDF) = 0x0010;
556 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
557
558 pch_enable(dev);
559}
560
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700561static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200562{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200563 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200564
565 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200566 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200567
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200568 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200569
570 gnvs->apic = 1;
571 gnvs->mpen = 1; /* Enable Multi Processing */
572 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100573
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200574 /* And tell SMI about it */
575 smm_setup_structures(gnvs, NULL, NULL);
576
577 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100578 acpigen_write_scope("\\");
579 acpigen_write_name_dword("NVSA", (u32) gnvs);
580 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200581 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200582}
583
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200584void acpi_fill_fadt(acpi_fadt_t *fadt)
585{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300586 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200587 config_t *chip = dev->chip_info;
588 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
589 int c2_latency;
590
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100591 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200592
593 fadt->sci_int = 0x9;
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200594
Kyösti Mälkki0a9e72e2019-08-11 01:22:28 +0300595 if (permanent_smi_handler()) {
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200596 fadt->smi_cmd = APM_CNT;
597 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
598 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
599 }
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200600
601 fadt->pm1a_evt_blk = pmbase;
602 fadt->pm1b_evt_blk = 0x0;
603 fadt->pm1a_cnt_blk = pmbase + 0x4;
604 fadt->pm1b_cnt_blk = 0x0;
605 fadt->pm2_cnt_blk = pmbase + 0x50;
606 fadt->pm_tmr_blk = pmbase + 0x8;
607 fadt->gpe0_blk = pmbase + 0x20;
608 fadt->gpe1_blk = 0;
609
610 fadt->pm1_evt_len = 4;
611 fadt->pm1_cnt_len = 2;
612 fadt->pm2_cnt_len = 1;
613 fadt->pm_tmr_len = 4;
614 fadt->gpe0_blk_len = 16;
615 fadt->gpe1_blk_len = 0;
616 fadt->gpe1_base = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200617 c2_latency = chip->c2_latency;
618 if (!c2_latency) {
619 c2_latency = 101; /* c2 unsupported */
620 }
621 fadt->p_lvl2_lat = c2_latency;
622 fadt->p_lvl3_lat = 87;
Patrick Rudolph78e8db12019-07-19 16:31:37 +0200623 /* flush_* is ignored if ACPI_FADT_WBINVD is set */
624 fadt->flush_size = 0;
625 fadt->flush_stride = 0;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200626 /* P_CNT not supported */
627 fadt->duty_offset = 0;
628 fadt->duty_width = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200629 fadt->day_alrm = 0xd;
630 fadt->mon_alrm = 0x00;
631 fadt->century = 0x32;
632 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
633
634 fadt->flags = ACPI_FADT_WBINVD |
635 ACPI_FADT_C1_SUPPORTED |
636 ACPI_FADT_SLEEP_BUTTON |
637 ACPI_FADT_RESET_REGISTER |
638 ACPI_FADT_S4_RTC_WAKE |
639 ACPI_FADT_PLATFORM_CLOCK;
640 if (chip->docking_supported) {
641 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
642 }
643 if (c2_latency < 100) {
644 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
645 }
646
647 fadt->reset_reg.space_id = 1;
648 fadt->reset_reg.bit_width = 8;
649 fadt->reset_reg.bit_offset = 0;
650 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
651 fadt->reset_reg.addrl = 0xcf9;
652 fadt->reset_reg.addrh = 0;
653
654 fadt->reset_value = 6;
655
656 fadt->x_pm1a_evt_blk.space_id = 1;
657 fadt->x_pm1a_evt_blk.bit_width = 32;
658 fadt->x_pm1a_evt_blk.bit_offset = 0;
659 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
660 fadt->x_pm1a_evt_blk.addrl = pmbase;
661 fadt->x_pm1a_evt_blk.addrh = 0x0;
662
663 fadt->x_pm1b_evt_blk.space_id = 1;
664 fadt->x_pm1b_evt_blk.bit_width = 0;
665 fadt->x_pm1b_evt_blk.bit_offset = 0;
666 fadt->x_pm1b_evt_blk.access_size = 0;
667 fadt->x_pm1b_evt_blk.addrl = 0x0;
668 fadt->x_pm1b_evt_blk.addrh = 0x0;
669
670 fadt->x_pm1a_cnt_blk.space_id = 1;
671 fadt->x_pm1a_cnt_blk.bit_width = 16;
672 fadt->x_pm1a_cnt_blk.bit_offset = 0;
673 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
674 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
675 fadt->x_pm1a_cnt_blk.addrh = 0x0;
676
677 fadt->x_pm1b_cnt_blk.space_id = 1;
678 fadt->x_pm1b_cnt_blk.bit_width = 0;
679 fadt->x_pm1b_cnt_blk.bit_offset = 0;
680 fadt->x_pm1b_cnt_blk.access_size = 0;
681 fadt->x_pm1b_cnt_blk.addrl = 0x0;
682 fadt->x_pm1b_cnt_blk.addrh = 0x0;
683
684 fadt->x_pm2_cnt_blk.space_id = 1;
685 fadt->x_pm2_cnt_blk.bit_width = 8;
686 fadt->x_pm2_cnt_blk.bit_offset = 0;
687 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
688 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
689 fadt->x_pm2_cnt_blk.addrh = 0x0;
690
691 fadt->x_pm_tmr_blk.space_id = 1;
692 fadt->x_pm_tmr_blk.bit_width = 32;
693 fadt->x_pm_tmr_blk.bit_offset = 0;
694 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
695 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
696 fadt->x_pm_tmr_blk.addrh = 0x0;
697
698 fadt->x_gpe0_blk.space_id = 1;
699 fadt->x_gpe0_blk.bit_width = 128;
700 fadt->x_gpe0_blk.bit_offset = 0;
701 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
702 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
703 fadt->x_gpe0_blk.addrh = 0x0;
704
705 fadt->x_gpe1_blk.space_id = 1;
706 fadt->x_gpe1_blk.bit_width = 0;
707 fadt->x_gpe1_blk.bit_offset = 0;
708 fadt->x_gpe1_blk.access_size = 0;
709 fadt->x_gpe1_blk.addrl = 0x0;
710 fadt->x_gpe1_blk.addrh = 0x0;
711}
712
Kyösti Mälkki90993952018-05-01 19:36:25 +0300713static const char *lpc_acpi_name(const struct device *dev)
714{
715 return "LPCB";
716}
717
Furquan Shaikh7536a392020-04-24 21:59:21 -0700718static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100719{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300720 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100721 config_t *chip = dev->chip_info;
722
723 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300724 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100725}
726
Bill XIEd533b162017-08-22 16:26:22 +0800727static void lpc_final(struct device *dev)
728{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200729 spi_finalize_ops();
730
Bill XIEd533b162017-08-22 16:26:22 +0800731 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800732 if (CONFIG(HAVE_SMI_HANDLER)) {
733 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800734 acpi_is_wakeup_s3()) {
735 outb(APM_CNT_FINALIZE, APM_CNT);
736 }
737 }
738}
739
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100740static struct device_operations device_ops = {
741 .read_resources = pch_lpc_read_resources,
742 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200743 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200744 .acpi_inject_dsdt = southbridge_inject_dsdt,
745 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300746 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200747 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100748 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800749 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100750 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100751 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200752 .ops_pci = &pci_dev_ops_pci,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100753};
754
755
Felix Singer838fbc72019-11-21 21:23:32 +0100756static const unsigned short pci_device_ids[] = {
757 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
758 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
759 0
760};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100761
762static const struct pci_driver pch_lpc __pci_driver = {
763 .ops = &device_ops,
764 .vendor = PCI_VENDOR_ID_INTEL,
765 .devices = pci_device_ids,
766};