blob: 230d5eb29fcfc69ace41eb432e083e72d1a39cfb [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>
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +030016#include <acpi/acpi_gnvs.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010017#include <elog.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070018#include <acpi/acpigen.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020019#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020020#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020021#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030022#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010023#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020024#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010025#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030026#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020027#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010028
29#define NMI_OFF 0
30
Vladimir Serbinenko46957052013-11-26 01:16:20 +010031typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010032
33/**
34 * Set miscellanous static southbridge features.
35 *
36 * @param dev PCI device with I/O APIC control registers
37 */
38static void pch_enable_ioapic(struct device *dev)
39{
40 u32 reg32;
41
42 /* Enable ACPI I/O range decode */
43 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
44
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080045 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010046 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080047 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
48 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010049
50 /*
51 * Select Boot Configuration register (0x03) and
52 * use Processor System Bus (0x01) to deliver interrupts.
53 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080054 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010055}
56
57static void pch_enable_serial_irqs(struct device *dev)
58{
59 /* Set packet length and toggle silent mode bit for one frame. */
60 pci_write_config8(dev, SERIRQ_CNTL,
61 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080062#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010063 pci_write_config8(dev, SERIRQ_CNTL,
64 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
65#endif
66}
67
68/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
69 * 0x00 - 0000 = Reserved
70 * 0x01 - 0001 = Reserved
71 * 0x02 - 0010 = Reserved
72 * 0x03 - 0011 = IRQ3
73 * 0x04 - 0100 = IRQ4
74 * 0x05 - 0101 = IRQ5
75 * 0x06 - 0110 = IRQ6
76 * 0x07 - 0111 = IRQ7
77 * 0x08 - 1000 = Reserved
78 * 0x09 - 1001 = IRQ9
79 * 0x0A - 1010 = IRQ10
80 * 0x0B - 1011 = IRQ11
81 * 0x0C - 1100 = IRQ12
82 * 0x0D - 1101 = Reserved
83 * 0x0E - 1110 = IRQ14
84 * 0x0F - 1111 = IRQ15
85 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
86 * 0x80 - The PIRQ is not routed.
87 */
88
Elyes HAOUASbe841402018-05-13 13:40:39 +020089static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010090{
Elyes HAOUASbe841402018-05-13 13:40:39 +020091 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020092 /* Interrupt 11 is not used by legacy devices and so can always be used for
93 PCI interrupts. Full legacy IRQ routing is complicated and hard to
94 get right. Fortunately all modern OS use MSI and so it's not that big of
95 an issue anyway. Still we have to provide a reasonable default. Using
96 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
97 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010098 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +020099 const u8 pirq_routing = 11;
100
101 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
102 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
105
106 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
107 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100110
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200111 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200112 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100113
114 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
115 continue;
116
117 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
118
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200119 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100120 continue;
121
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200122 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100123 }
124}
125
Elyes HAOUASbe841402018-05-13 13:40:39 +0200126static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100127{
128 /* Get the chip configuration */
129 config_t *config = dev->chip_info;
130 u32 reg32 = 0;
131
132 /* An array would be much nicer here, or some
133 * other method of doing this.
134 */
135 reg32 |= (config->gpi0_routing & 0x03) << 0;
136 reg32 |= (config->gpi1_routing & 0x03) << 2;
137 reg32 |= (config->gpi2_routing & 0x03) << 4;
138 reg32 |= (config->gpi3_routing & 0x03) << 6;
139 reg32 |= (config->gpi4_routing & 0x03) << 8;
140 reg32 |= (config->gpi5_routing & 0x03) << 10;
141 reg32 |= (config->gpi6_routing & 0x03) << 12;
142 reg32 |= (config->gpi7_routing & 0x03) << 14;
143 reg32 |= (config->gpi8_routing & 0x03) << 16;
144 reg32 |= (config->gpi9_routing & 0x03) << 18;
145 reg32 |= (config->gpi10_routing & 0x03) << 20;
146 reg32 |= (config->gpi11_routing & 0x03) << 22;
147 reg32 |= (config->gpi12_routing & 0x03) << 24;
148 reg32 |= (config->gpi13_routing & 0x03) << 26;
149 reg32 |= (config->gpi14_routing & 0x03) << 28;
150 reg32 |= (config->gpi15_routing & 0x03) << 30;
151
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200152 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100153}
154
Elyes HAOUASbe841402018-05-13 13:40:39 +0200155static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100156{
157 u8 reg8;
158 u16 reg16, pmbase;
159 u32 reg32;
160 const char *state;
161 /* Get the chip configuration */
162 config_t *config = dev->chip_info;
163
Nico Huber9faae2b2018-11-14 00:00:35 +0100164 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100165 int nmi_option;
166
167 /* Which state do we want to goto after g3 (power restored)?
168 * 0 == S0 Full On
169 * 1 == S5 Soft Off
170 *
171 * If the option is not existent (Laptops), use Kconfig setting.
172 */
173 get_option(&pwr_on, "power_on_after_fail");
174
175 reg16 = pci_read_config16(dev, GEN_PMCON_3);
176 reg16 &= 0xfffe;
177 switch (pwr_on) {
178 case MAINBOARD_POWER_OFF:
179 reg16 |= 1;
180 state = "off";
181 break;
182 case MAINBOARD_POWER_ON:
183 reg16 &= ~1;
184 state = "on";
185 break;
186 case MAINBOARD_POWER_KEEP:
187 reg16 &= ~1;
188 state = "state keep";
189 break;
190 default:
191 state = "undefined";
192 }
193
194 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
195 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
196
197 reg16 &= ~(1 << 10);
198 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
199
200 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
201
202 pci_write_config16(dev, GEN_PMCON_3, reg16);
203 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
204
205 /* Set up NMI on errors. */
206 reg8 = inb(0x61);
207 reg8 &= 0x0f; /* Higher Nibble must be 0 */
208 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
209 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
210 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
211 outb(reg8, 0x61);
212
213 reg8 = inb(0x70);
214 nmi_option = NMI_OFF;
215 get_option(&nmi_option, "nmi");
216 if (nmi_option) {
217 printk(BIOS_INFO, "NMI sources enabled.\n");
218 reg8 &= ~(1 << 7); /* Set NMI. */
219 } else {
220 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200221 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100222 }
223 outb(reg8, 0x70);
224
225 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
226 reg16 = pci_read_config16(dev, GEN_PMCON_1);
227 reg16 &= ~(3 << 0); // SMI# rate 1 minute
228 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300229 if (CONFIG(DEBUG_PERIODIC_SMI))
230 reg16 |= (3 << 0); // Periodic SMI every 8s
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100231 pci_write_config16(dev, GEN_PMCON_1, reg16);
232
233 // Set the board's GPI routing.
234 pch_gpi_routing(dev);
235
236 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
237
238 outl(config->gpe0_en, pmbase + GPE0_EN);
239 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
240
241 /* Set up power management block and determine sleep mode */
242 reg32 = inl(pmbase + 0x04); // PM1_CNT
243 reg32 &= ~(7 << 10); // SLP_TYP
244 reg32 |= (1 << 0); // SCI_EN
245 outl(reg32, pmbase + 0x04);
246
247 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200248 reg32 = RCBA32(PRSTS);
249 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
250 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100251
Angel Pons42b4e4e2019-09-18 10:58:53 +0200252 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100253 reg32 = RCBA32(0x3f02);
254 reg32 &= ~0xf;
255 RCBA32(0x3f02) = reg32;
256}
257
258static void pch_rtc_init(struct device *dev)
259{
260 u8 reg8;
261 int rtc_failed;
262
263 reg8 = pci_read_config8(dev, GEN_PMCON_3);
264 rtc_failed = reg8 & RTC_BATTERY_DEAD;
265 if (rtc_failed) {
266 reg8 &= ~RTC_BATTERY_DEAD;
267 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100268 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100269 }
270 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
271
Gabe Blackb3f08c62014-04-30 17:12:25 -0700272 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100273}
274
275static void mobile5_pm_init(struct device *dev)
276{
277 int i;
278
279 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
280 pci_write_config8(dev, 0xa9, 0x47);
281
282 RCBA32 (0x1d44) = 0x00000000;
283 (void) RCBA32 (0x1d44);
284 RCBA32 (0x1d48) = 0x00030000;
285 (void) RCBA32 (0x1d48);
286 RCBA32 (0x1e80) = 0x000c0801;
287 (void) RCBA32 (0x1e80);
288 RCBA32 (0x1e84) = 0x000200f0;
289 (void) RCBA32 (0x1e84);
290
291 const u32 rcba2010[] =
292 {
293 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
294 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
295 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200296 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100297 {
298 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
299 RCBA32 (0x2010 + 4 * i);
300 }
301
302 RCBA32 (0x2100) = 0x00000000;
303 (void) RCBA32 (0x2100);
304 RCBA32 (0x2104) = 0x00000757;
305 (void) RCBA32 (0x2104);
306 RCBA32 (0x2108) = 0x00170001;
307 (void) RCBA32 (0x2108);
308
309 RCBA32 (0x211c) = 0x00000000;
310 (void) RCBA32 (0x211c);
311 RCBA32 (0x2120) = 0x00010000;
312 (void) RCBA32 (0x2120);
313
314 RCBA32 (0x21fc) = 0x00000000;
315 (void) RCBA32 (0x21fc);
316 RCBA32 (0x2200) = 0x20000044;
317 (void) RCBA32 (0x2200);
318 RCBA32 (0x2204) = 0x00000001;
319 (void) RCBA32 (0x2204);
320 RCBA32 (0x2208) = 0x00003457;
321 (void) RCBA32 (0x2208);
322
323 const u32 rcba2210[] =
324 {
325 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
326 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
327 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
328 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
329 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
330 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
331 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
332 };
333
Elyes HAOUAS035df002016-10-03 21:54:16 +0200334 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100335 {
336 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
337 RCBA32 (0x2210 + 4 * i);
338 }
339
340 const u32 rcba2300[] =
341 {
342 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
343 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
344 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
345 };
346
Elyes HAOUAS035df002016-10-03 21:54:16 +0200347 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100348 {
349 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
350 RCBA32 (0x2300 + 4 * i);
351 }
352
353 RCBA32 (0x37fc) = 0x00000000;
354 (void) RCBA32 (0x37fc);
355 RCBA32 (0x3dfc) = 0x00000000;
356 (void) RCBA32 (0x3dfc);
357 RCBA32 (0x3e7c) = 0xffffffff;
358 (void) RCBA32 (0x3e7c);
359 RCBA32 (0x3efc) = 0x00000000;
360 (void) RCBA32 (0x3efc);
361 RCBA32 (0x3f00) = 0x0000010b;
362 (void) RCBA32 (0x3f00);
363}
364
365static void enable_hpet(void)
366{
367 u32 reg32;
368
369 /* Move HPET to default address 0xfed00000 and enable it */
370 reg32 = RCBA32(HPTC);
371 reg32 |= (1 << 7); // HPET Address Enable
372 reg32 &= ~(3 << 0);
373 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200374 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100375
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800376 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100377}
378
Elyes HAOUASbe841402018-05-13 13:40:39 +0200379static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100380{
381 u32 reg32;
382 u16 reg16;
383
384 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
385
386 reg16 = pci_read_config16(dev, GEN_PMCON_1);
387 reg16 |= (1 << 2) | (1 << 11);
388 pci_write_config16(dev, GEN_PMCON_1, reg16);
389
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100390 reg32 = RCBA32(CG);
391 reg32 |= (1 << 31);
392 reg32 |= (1 << 29) | (1 << 28);
393 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
394 reg32 |= (1 << 16);
395 reg32 |= (1 << 17);
396 reg32 |= (1 << 18);
397 reg32 |= (1 << 22);
398 reg32 |= (1 << 23);
399 reg32 &= ~(1 << 20);
400 reg32 |= (1 << 19);
401 reg32 |= (1 << 0);
402 reg32 |= (0xf << 1);
403 RCBA32(CG) = reg32;
404
405 RCBA32_OR(0x38c0, 0x7);
406 RCBA32_OR(0x36d4, 0x6680c004);
407 RCBA32_OR(0x3564, 0x3);
408}
409
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200410static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100411{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300412 if (!acpi_is_wakeup_s3()) {
413 apm_control(APM_CNT_ACPI_DISABLE);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100414 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100415}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100416
417static void pch_disable_smm_only_flashing(struct device *dev)
418{
419 u8 reg8;
420
421 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100422 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100423 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100424 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100425}
426
427static void pch_fixups(struct device *dev)
428{
429 /*
430 * Enable DMI ASPM in the PCH
431 */
432 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
433 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
434 RCBA32_OR(0x21a8, 0x3);
435}
436
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100437static void lpc_init(struct device *dev)
438{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100439 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100440
441 /* Set the value for PCI command register. */
Angel Pons89739ba2020-07-25 02:46:39 +0200442 pci_write_config16(dev, PCI_COMMAND,
443 PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL |
444 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100445
446 /* IO APIC initialization. */
447 pch_enable_ioapic(dev);
448
449 pch_enable_serial_irqs(dev);
450
451 /* Setup the PIRQ. */
452 pch_pirq_init(dev);
453
454 /* Setup power options. */
455 pch_power_options(dev);
456
457 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200458 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100459
460 /* Set the state of the GPIO lines. */
461 //gpio_init(dev);
462
463 /* Initialize the real time clock. */
464 pch_rtc_init(dev);
465
466 /* Initialize ISA DMA. */
467 isa_dma_init();
468
469 /* Initialize the High Precision Event Timers, if present. */
470 enable_hpet();
471
472 /* Initialize Clock Gating */
473 enable_clock_gating(dev);
474
475 setup_i8259();
476
477 /* The OS should do this? */
478 /* Interrupt 9 should be level triggered (SCI) */
479 i8259_configure_irq_trigger(9, 1);
480
481 pch_disable_smm_only_flashing(dev);
482
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200483 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100484
485 pch_fixups(dev);
486}
487
Elyes HAOUASbe841402018-05-13 13:40:39 +0200488static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100489{
490 struct resource *res;
491 config_t *config = dev->chip_info;
492 u8 io_index = 0;
493
494 /* Get the normal PCI resources of this device. */
495 pci_dev_read_resources(dev);
496
497 /* Add an extra subtractive resource for both memory and I/O. */
498 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
499 res->base = 0;
500 res->size = 0x1000;
501 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
502 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
503
504 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
505 res->base = 0xff800000;
506 res->size = 0x00800000; /* 8 MB for flash */
507 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
508 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
509
510 res = new_resource(dev, 3); /* IOAPIC */
511 res->base = IO_APIC_ADDR;
512 res->size = 0x00001000;
513 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
514
515 /* Set PCH IO decode ranges if required.*/
516 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
517 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
518 res->base = config->gen1_dec & 0xFFFC;
519 res->size = (config->gen1_dec >> 16) & 0xFC;
520 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
521 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
522 }
523
524 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
525 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
526 res->base = config->gen2_dec & 0xFFFC;
527 res->size = (config->gen2_dec >> 16) & 0xFC;
528 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
529 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
530 }
531
532 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
533 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
534 res->base = config->gen3_dec & 0xFFFC;
535 res->size = (config->gen3_dec >> 16) & 0xFC;
536 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
537 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
538 }
539
540 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
541 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
542 res->base = config->gen4_dec & 0xFFFC;
543 res->size = (config->gen4_dec >> 16) & 0xFC;
544 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
545 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
546 }
547}
548
Elyes HAOUASbe841402018-05-13 13:40:39 +0200549static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100550{
551 /* Enable PCH Display Port */
552 RCBA16(DISPBDF) = 0x0010;
553 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
554
555 pch_enable(dev);
556}
557
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300558void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200559{
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300560 struct global_nvs *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200561
562 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200563 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200564
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200565 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200566
567 gnvs->apic = 1;
568 gnvs->mpen = 1; /* Enable Multi Processing */
569 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100570
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200571 /* And tell SMI about it */
Kyösti Mälkkic3c55212020-06-17 10:34:26 +0300572 apm_control(APM_CNT_GNVS_UPDATE);
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200573
574 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100575 acpigen_write_scope("\\");
576 acpigen_write_name_dword("NVSA", (u32) gnvs);
577 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200578 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200579}
580
Kyösti Mälkki90993952018-05-01 19:36:25 +0300581static const char *lpc_acpi_name(const struct device *dev)
582{
583 return "LPCB";
584}
585
Furquan Shaikh7536a392020-04-24 21:59:21 -0700586static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100587{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300588 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100589 config_t *chip = dev->chip_info;
590
591 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300592 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100593}
594
Bill XIEd533b162017-08-22 16:26:22 +0800595static void lpc_final(struct device *dev)
596{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200597 spi_finalize_ops();
598
Bill XIEd533b162017-08-22 16:26:22 +0800599 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300600 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
601 acpi_is_wakeup_s3()) {
602 apm_control(APM_CNT_FINALIZE);
Bill XIEd533b162017-08-22 16:26:22 +0800603 }
604}
605
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100606static struct device_operations device_ops = {
607 .read_resources = pch_lpc_read_resources,
608 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200609 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200610 .acpi_inject_dsdt = southbridge_inject_dsdt,
611 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300612 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200613 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100614 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800615 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100616 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100617 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200618 .ops_pci = &pci_dev_ops_pci,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100619};
620
621
Felix Singer838fbc72019-11-21 21:23:32 +0100622static const unsigned short pci_device_ids[] = {
623 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
624 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
625 0
626};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100627
628static const struct pci_driver pch_lpc __pci_driver = {
629 .ops = &device_ops,
630 .vendor = PCI_VENDOR_ID_INTEL,
631 .devices = pci_device_ids,
632};