blob: 4f86e9b80b5ffd5fdbdef5806cb957597d6d561f [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
Kyösti Mälkki94464472020-06-13 13:45:42 +0300228 if (CONFIG(DEBUG_PERIODIC_SMI))
229 reg16 |= (3 << 0); // Periodic SMI every 8s
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100230 pci_write_config16(dev, GEN_PMCON_1, reg16);
231
232 // Set the board's GPI routing.
233 pch_gpi_routing(dev);
234
235 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
236
237 outl(config->gpe0_en, pmbase + GPE0_EN);
238 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
239
240 /* Set up power management block and determine sleep mode */
241 reg32 = inl(pmbase + 0x04); // PM1_CNT
242 reg32 &= ~(7 << 10); // SLP_TYP
243 reg32 |= (1 << 0); // SCI_EN
244 outl(reg32, pmbase + 0x04);
245
246 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200247 reg32 = RCBA32(PRSTS);
248 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
249 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100250
Angel Pons42b4e4e2019-09-18 10:58:53 +0200251 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100252 reg32 = RCBA32(0x3f02);
253 reg32 &= ~0xf;
254 RCBA32(0x3f02) = reg32;
255}
256
257static void pch_rtc_init(struct device *dev)
258{
259 u8 reg8;
260 int rtc_failed;
261
262 reg8 = pci_read_config8(dev, GEN_PMCON_3);
263 rtc_failed = reg8 & RTC_BATTERY_DEAD;
264 if (rtc_failed) {
265 reg8 &= ~RTC_BATTERY_DEAD;
266 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100267 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100268 }
269 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
270
Gabe Blackb3f08c62014-04-30 17:12:25 -0700271 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100272}
273
274static void mobile5_pm_init(struct device *dev)
275{
276 int i;
277
278 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
279 pci_write_config8(dev, 0xa9, 0x47);
280
281 RCBA32 (0x1d44) = 0x00000000;
282 (void) RCBA32 (0x1d44);
283 RCBA32 (0x1d48) = 0x00030000;
284 (void) RCBA32 (0x1d48);
285 RCBA32 (0x1e80) = 0x000c0801;
286 (void) RCBA32 (0x1e80);
287 RCBA32 (0x1e84) = 0x000200f0;
288 (void) RCBA32 (0x1e84);
289
290 const u32 rcba2010[] =
291 {
292 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
293 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
294 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200295 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100296 {
297 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
298 RCBA32 (0x2010 + 4 * i);
299 }
300
301 RCBA32 (0x2100) = 0x00000000;
302 (void) RCBA32 (0x2100);
303 RCBA32 (0x2104) = 0x00000757;
304 (void) RCBA32 (0x2104);
305 RCBA32 (0x2108) = 0x00170001;
306 (void) RCBA32 (0x2108);
307
308 RCBA32 (0x211c) = 0x00000000;
309 (void) RCBA32 (0x211c);
310 RCBA32 (0x2120) = 0x00010000;
311 (void) RCBA32 (0x2120);
312
313 RCBA32 (0x21fc) = 0x00000000;
314 (void) RCBA32 (0x21fc);
315 RCBA32 (0x2200) = 0x20000044;
316 (void) RCBA32 (0x2200);
317 RCBA32 (0x2204) = 0x00000001;
318 (void) RCBA32 (0x2204);
319 RCBA32 (0x2208) = 0x00003457;
320 (void) RCBA32 (0x2208);
321
322 const u32 rcba2210[] =
323 {
324 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
325 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
326 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
327 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
328 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
329 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
330 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
331 };
332
Elyes HAOUAS035df002016-10-03 21:54:16 +0200333 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100334 {
335 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
336 RCBA32 (0x2210 + 4 * i);
337 }
338
339 const u32 rcba2300[] =
340 {
341 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
342 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
343 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
344 };
345
Elyes HAOUAS035df002016-10-03 21:54:16 +0200346 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100347 {
348 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
349 RCBA32 (0x2300 + 4 * i);
350 }
351
352 RCBA32 (0x37fc) = 0x00000000;
353 (void) RCBA32 (0x37fc);
354 RCBA32 (0x3dfc) = 0x00000000;
355 (void) RCBA32 (0x3dfc);
356 RCBA32 (0x3e7c) = 0xffffffff;
357 (void) RCBA32 (0x3e7c);
358 RCBA32 (0x3efc) = 0x00000000;
359 (void) RCBA32 (0x3efc);
360 RCBA32 (0x3f00) = 0x0000010b;
361 (void) RCBA32 (0x3f00);
362}
363
364static void enable_hpet(void)
365{
366 u32 reg32;
367
368 /* Move HPET to default address 0xfed00000 and enable it */
369 reg32 = RCBA32(HPTC);
370 reg32 |= (1 << 7); // HPET Address Enable
371 reg32 &= ~(3 << 0);
372 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200373 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100374
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800375 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100376}
377
Elyes HAOUASbe841402018-05-13 13:40:39 +0200378static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100379{
380 u32 reg32;
381 u16 reg16;
382
383 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
384
385 reg16 = pci_read_config16(dev, GEN_PMCON_1);
386 reg16 |= (1 << 2) | (1 << 11);
387 pci_write_config16(dev, GEN_PMCON_1, reg16);
388
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100389 reg32 = RCBA32(CG);
390 reg32 |= (1 << 31);
391 reg32 |= (1 << 29) | (1 << 28);
392 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
393 reg32 |= (1 << 16);
394 reg32 |= (1 << 17);
395 reg32 |= (1 << 18);
396 reg32 |= (1 << 22);
397 reg32 |= (1 << 23);
398 reg32 &= ~(1 << 20);
399 reg32 |= (1 << 19);
400 reg32 |= (1 << 0);
401 reg32 |= (0xf << 1);
402 RCBA32(CG) = reg32;
403
404 RCBA32_OR(0x38c0, 0x7);
405 RCBA32_OR(0x36d4, 0x6680c004);
406 RCBA32_OR(0x3564, 0x3);
407}
408
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200409static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100410{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300411 if (!acpi_is_wakeup_s3()) {
412 apm_control(APM_CNT_ACPI_DISABLE);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100413 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100414}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100415
416static void pch_disable_smm_only_flashing(struct device *dev)
417{
418 u8 reg8;
419
420 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100421 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100422 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100423 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100424}
425
426static void pch_fixups(struct device *dev)
427{
428 /*
429 * Enable DMI ASPM in the PCH
430 */
431 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
432 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
433 RCBA32_OR(0x21a8, 0x3);
434}
435
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100436static void lpc_init(struct device *dev)
437{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100438 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100439
440 /* Set the value for PCI command register. */
441 pci_write_config16(dev, PCI_COMMAND, 0x000f);
442
443 /* IO APIC initialization. */
444 pch_enable_ioapic(dev);
445
446 pch_enable_serial_irqs(dev);
447
448 /* Setup the PIRQ. */
449 pch_pirq_init(dev);
450
451 /* Setup power options. */
452 pch_power_options(dev);
453
454 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200455 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100456
457 /* Set the state of the GPIO lines. */
458 //gpio_init(dev);
459
460 /* Initialize the real time clock. */
461 pch_rtc_init(dev);
462
463 /* Initialize ISA DMA. */
464 isa_dma_init();
465
466 /* Initialize the High Precision Event Timers, if present. */
467 enable_hpet();
468
469 /* Initialize Clock Gating */
470 enable_clock_gating(dev);
471
472 setup_i8259();
473
474 /* The OS should do this? */
475 /* Interrupt 9 should be level triggered (SCI) */
476 i8259_configure_irq_trigger(9, 1);
477
478 pch_disable_smm_only_flashing(dev);
479
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200480 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100481
482 pch_fixups(dev);
483}
484
Elyes HAOUASbe841402018-05-13 13:40:39 +0200485static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100486{
487 struct resource *res;
488 config_t *config = dev->chip_info;
489 u8 io_index = 0;
490
491 /* Get the normal PCI resources of this device. */
492 pci_dev_read_resources(dev);
493
494 /* Add an extra subtractive resource for both memory and I/O. */
495 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
496 res->base = 0;
497 res->size = 0x1000;
498 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
499 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
500
501 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
502 res->base = 0xff800000;
503 res->size = 0x00800000; /* 8 MB for flash */
504 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
505 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
506
507 res = new_resource(dev, 3); /* IOAPIC */
508 res->base = IO_APIC_ADDR;
509 res->size = 0x00001000;
510 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
511
512 /* Set PCH IO decode ranges if required.*/
513 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
514 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
515 res->base = config->gen1_dec & 0xFFFC;
516 res->size = (config->gen1_dec >> 16) & 0xFC;
517 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
518 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
519 }
520
521 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
522 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
523 res->base = config->gen2_dec & 0xFFFC;
524 res->size = (config->gen2_dec >> 16) & 0xFC;
525 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
526 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
527 }
528
529 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
530 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
531 res->base = config->gen3_dec & 0xFFFC;
532 res->size = (config->gen3_dec >> 16) & 0xFC;
533 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
534 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
535 }
536
537 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
538 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
539 res->base = config->gen4_dec & 0xFFFC;
540 res->size = (config->gen4_dec >> 16) & 0xFC;
541 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
542 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
543 }
544}
545
Elyes HAOUASbe841402018-05-13 13:40:39 +0200546static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100547{
548 /* Enable PCH Display Port */
549 RCBA16(DISPBDF) = 0x0010;
550 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
551
552 pch_enable(dev);
553}
554
Furquan Shaikh338fd9a2020-04-24 22:57:05 -0700555static void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200556{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200557 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200558
559 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200560 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200561
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200562 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200563
564 gnvs->apic = 1;
565 gnvs->mpen = 1; /* Enable Multi Processing */
566 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100567
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200568 /* And tell SMI about it */
569 smm_setup_structures(gnvs, NULL, NULL);
570
571 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100572 acpigen_write_scope("\\");
573 acpigen_write_name_dword("NVSA", (u32) gnvs);
574 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200575 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200576}
577
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200578void acpi_fill_fadt(acpi_fadt_t *fadt)
579{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300580 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200581 config_t *chip = dev->chip_info;
582 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
583 int c2_latency;
584
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200585
586 fadt->sci_int = 0x9;
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200587
Kyösti Mälkki0a9e72e2019-08-11 01:22:28 +0300588 if (permanent_smi_handler()) {
Kyösti Mälkkic328a682019-11-23 07:23:40 +0200589 fadt->smi_cmd = APM_CNT;
590 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
591 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
592 }
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200593
594 fadt->pm1a_evt_blk = pmbase;
595 fadt->pm1b_evt_blk = 0x0;
596 fadt->pm1a_cnt_blk = pmbase + 0x4;
597 fadt->pm1b_cnt_blk = 0x0;
598 fadt->pm2_cnt_blk = pmbase + 0x50;
599 fadt->pm_tmr_blk = pmbase + 0x8;
600 fadt->gpe0_blk = pmbase + 0x20;
601 fadt->gpe1_blk = 0;
602
603 fadt->pm1_evt_len = 4;
604 fadt->pm1_cnt_len = 2;
605 fadt->pm2_cnt_len = 1;
606 fadt->pm_tmr_len = 4;
607 fadt->gpe0_blk_len = 16;
608 fadt->gpe1_blk_len = 0;
609 fadt->gpe1_base = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200610 c2_latency = chip->c2_latency;
611 if (!c2_latency) {
612 c2_latency = 101; /* c2 unsupported */
613 }
614 fadt->p_lvl2_lat = c2_latency;
615 fadt->p_lvl3_lat = 87;
Patrick Rudolph78e8db12019-07-19 16:31:37 +0200616 /* flush_* is ignored if ACPI_FADT_WBINVD is set */
617 fadt->flush_size = 0;
618 fadt->flush_stride = 0;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200619 /* P_CNT not supported */
620 fadt->duty_offset = 0;
621 fadt->duty_width = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200622 fadt->day_alrm = 0xd;
623 fadt->mon_alrm = 0x00;
624 fadt->century = 0x32;
625 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
626
627 fadt->flags = ACPI_FADT_WBINVD |
628 ACPI_FADT_C1_SUPPORTED |
629 ACPI_FADT_SLEEP_BUTTON |
630 ACPI_FADT_RESET_REGISTER |
631 ACPI_FADT_S4_RTC_WAKE |
632 ACPI_FADT_PLATFORM_CLOCK;
633 if (chip->docking_supported) {
634 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
635 }
636 if (c2_latency < 100) {
637 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
638 }
639
640 fadt->reset_reg.space_id = 1;
641 fadt->reset_reg.bit_width = 8;
642 fadt->reset_reg.bit_offset = 0;
643 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
644 fadt->reset_reg.addrl = 0xcf9;
645 fadt->reset_reg.addrh = 0;
646
647 fadt->reset_value = 6;
648
649 fadt->x_pm1a_evt_blk.space_id = 1;
650 fadt->x_pm1a_evt_blk.bit_width = 32;
651 fadt->x_pm1a_evt_blk.bit_offset = 0;
652 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
653 fadt->x_pm1a_evt_blk.addrl = pmbase;
654 fadt->x_pm1a_evt_blk.addrh = 0x0;
655
656 fadt->x_pm1b_evt_blk.space_id = 1;
657 fadt->x_pm1b_evt_blk.bit_width = 0;
658 fadt->x_pm1b_evt_blk.bit_offset = 0;
659 fadt->x_pm1b_evt_blk.access_size = 0;
660 fadt->x_pm1b_evt_blk.addrl = 0x0;
661 fadt->x_pm1b_evt_blk.addrh = 0x0;
662
663 fadt->x_pm1a_cnt_blk.space_id = 1;
664 fadt->x_pm1a_cnt_blk.bit_width = 16;
665 fadt->x_pm1a_cnt_blk.bit_offset = 0;
666 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
667 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
668 fadt->x_pm1a_cnt_blk.addrh = 0x0;
669
670 fadt->x_pm1b_cnt_blk.space_id = 1;
671 fadt->x_pm1b_cnt_blk.bit_width = 0;
672 fadt->x_pm1b_cnt_blk.bit_offset = 0;
673 fadt->x_pm1b_cnt_blk.access_size = 0;
674 fadt->x_pm1b_cnt_blk.addrl = 0x0;
675 fadt->x_pm1b_cnt_blk.addrh = 0x0;
676
677 fadt->x_pm2_cnt_blk.space_id = 1;
678 fadt->x_pm2_cnt_blk.bit_width = 8;
679 fadt->x_pm2_cnt_blk.bit_offset = 0;
680 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
681 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
682 fadt->x_pm2_cnt_blk.addrh = 0x0;
683
684 fadt->x_pm_tmr_blk.space_id = 1;
685 fadt->x_pm_tmr_blk.bit_width = 32;
686 fadt->x_pm_tmr_blk.bit_offset = 0;
687 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
688 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
689 fadt->x_pm_tmr_blk.addrh = 0x0;
690
691 fadt->x_gpe0_blk.space_id = 1;
692 fadt->x_gpe0_blk.bit_width = 128;
693 fadt->x_gpe0_blk.bit_offset = 0;
694 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
695 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
696 fadt->x_gpe0_blk.addrh = 0x0;
697
698 fadt->x_gpe1_blk.space_id = 1;
699 fadt->x_gpe1_blk.bit_width = 0;
700 fadt->x_gpe1_blk.bit_offset = 0;
701 fadt->x_gpe1_blk.access_size = 0;
702 fadt->x_gpe1_blk.addrl = 0x0;
703 fadt->x_gpe1_blk.addrh = 0x0;
704}
705
Kyösti Mälkki90993952018-05-01 19:36:25 +0300706static const char *lpc_acpi_name(const struct device *dev)
707{
708 return "LPCB";
709}
710
Furquan Shaikh7536a392020-04-24 21:59:21 -0700711static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100712{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300713 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100714 config_t *chip = dev->chip_info;
715
716 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300717 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100718}
719
Bill XIEd533b162017-08-22 16:26:22 +0800720static void lpc_final(struct device *dev)
721{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200722 spi_finalize_ops();
723
Bill XIEd533b162017-08-22 16:26:22 +0800724 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300725 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
726 acpi_is_wakeup_s3()) {
727 apm_control(APM_CNT_FINALIZE);
Bill XIEd533b162017-08-22 16:26:22 +0800728 }
729}
730
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100731static struct device_operations device_ops = {
732 .read_resources = pch_lpc_read_resources,
733 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200734 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200735 .acpi_inject_dsdt = southbridge_inject_dsdt,
736 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300737 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200738 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100739 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800740 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100741 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100742 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200743 .ops_pci = &pci_dev_ops_pci,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100744};
745
746
Felix Singer838fbc72019-11-21 21:23:32 +0100747static const unsigned short pci_device_ids[] = {
748 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
749 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
750 0
751};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100752
753static const struct pci_driver pch_lpc __pci_driver = {
754 .ops = &device_ops,
755 .vendor = PCI_VENDOR_ID_INTEL,
756 .devices = pci_device_ids,
757};