blob: 73f19c7ab72b88cee77aaaf0a03c88fdb5a78c3b [file] [log] [blame]
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01001/*
2 * This file is part of the coreboot project.
3 *
Vladimir Serbinenko888d5592013-11-13 17:53:38 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; version 2 of
8 * the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010014 */
15
16#include <console/console.h>
17#include <device/device.h>
18#include <device/pci.h>
19#include <device/pci_ids.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020020#include <option.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010021#include <pc80/mc146818rtc.h>
22#include <pc80/isa-dma.h>
23#include <pc80/i8259.h>
24#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020025#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020026#include <device/pci_ops.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010027#include <arch/ioapic.h>
28#include <arch/acpi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010029#include <elog.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020030#include <arch/acpigen.h>
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020031#include <cbmem.h>
Vladimir Serbinenko7309c642014-10-05 11:07:33 +020032#include <string.h>
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +020033#include <cpu/x86/smm.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030034#include "chip.h"
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010035#include "pch.h"
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +020036#include "nvs.h"
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010037#include <southbridge/intel/common/pciehp.h>
Kyösti Mälkki90993952018-05-01 19:36:25 +030038#include <southbridge/intel/common/acpi_pirq_gen.h>
Arthur Heymansaadd1d02019-05-28 13:39:20 +020039#include <southbridge/intel/common/spi.h>
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010040
41#define NMI_OFF 0
42
Vladimir Serbinenko46957052013-11-26 01:16:20 +010043typedef struct southbridge_intel_ibexpeak_config config_t;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010044
45/**
46 * Set miscellanous static southbridge features.
47 *
48 * @param dev PCI device with I/O APIC control registers
49 */
50static void pch_enable_ioapic(struct device *dev)
51{
52 u32 reg32;
53
54 /* Enable ACPI I/O range decode */
55 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
56
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080057 set_ioapic_id(VIO_APIC_VADDR, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010058 /* affirm full set of redirection table entries ("write once") */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080059 reg32 = io_apic_read(VIO_APIC_VADDR, 0x01);
60 io_apic_write(VIO_APIC_VADDR, 0x01, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010061
62 /*
63 * Select Boot Configuration register (0x03) and
64 * use Processor System Bus (0x01) to deliver interrupts.
65 */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080066 io_apic_write(VIO_APIC_VADDR, 0x03, 0x01);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010067}
68
69static void pch_enable_serial_irqs(struct device *dev)
70{
71 /* Set packet length and toggle silent mode bit for one frame. */
72 pci_write_config8(dev, SERIRQ_CNTL,
73 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -080074#if !CONFIG(SERIRQ_CONTINUOUS_MODE)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010075 pci_write_config8(dev, SERIRQ_CNTL,
76 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
77#endif
78}
79
80/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
81 * 0x00 - 0000 = Reserved
82 * 0x01 - 0001 = Reserved
83 * 0x02 - 0010 = Reserved
84 * 0x03 - 0011 = IRQ3
85 * 0x04 - 0100 = IRQ4
86 * 0x05 - 0101 = IRQ5
87 * 0x06 - 0110 = IRQ6
88 * 0x07 - 0111 = IRQ7
89 * 0x08 - 1000 = Reserved
90 * 0x09 - 1001 = IRQ9
91 * 0x0A - 1010 = IRQ10
92 * 0x0B - 1011 = IRQ11
93 * 0x0C - 1100 = IRQ12
94 * 0x0D - 1101 = Reserved
95 * 0x0E - 1110 = IRQ14
96 * 0x0F - 1111 = IRQ15
97 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
98 * 0x80 - The PIRQ is not routed.
99 */
100
Elyes HAOUASbe841402018-05-13 13:40:39 +0200101static void pch_pirq_init(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100102{
Elyes HAOUASbe841402018-05-13 13:40:39 +0200103 struct device *irq_dev;
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200104 /* Interrupt 11 is not used by legacy devices and so can always be used for
105 PCI interrupts. Full legacy IRQ routing is complicated and hard to
106 get right. Fortunately all modern OS use MSI and so it's not that big of
107 an issue anyway. Still we have to provide a reasonable default. Using
108 interrupt 11 for it everywhere is a working default. ACPI-aware OS can
109 move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100110 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200111 const u8 pirq_routing = 11;
112
113 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
114 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
115 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
116 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
117
118 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
119 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
120 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
121 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100122
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200123 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200124 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100125
126 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
127 continue;
128
129 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
130
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200131 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100132 continue;
133
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200134 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100135 }
136}
137
Elyes HAOUASbe841402018-05-13 13:40:39 +0200138static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100139{
140 /* Get the chip configuration */
141 config_t *config = dev->chip_info;
142 u32 reg32 = 0;
143
144 /* An array would be much nicer here, or some
145 * other method of doing this.
146 */
147 reg32 |= (config->gpi0_routing & 0x03) << 0;
148 reg32 |= (config->gpi1_routing & 0x03) << 2;
149 reg32 |= (config->gpi2_routing & 0x03) << 4;
150 reg32 |= (config->gpi3_routing & 0x03) << 6;
151 reg32 |= (config->gpi4_routing & 0x03) << 8;
152 reg32 |= (config->gpi5_routing & 0x03) << 10;
153 reg32 |= (config->gpi6_routing & 0x03) << 12;
154 reg32 |= (config->gpi7_routing & 0x03) << 14;
155 reg32 |= (config->gpi8_routing & 0x03) << 16;
156 reg32 |= (config->gpi9_routing & 0x03) << 18;
157 reg32 |= (config->gpi10_routing & 0x03) << 20;
158 reg32 |= (config->gpi11_routing & 0x03) << 22;
159 reg32 |= (config->gpi12_routing & 0x03) << 24;
160 reg32 |= (config->gpi13_routing & 0x03) << 26;
161 reg32 |= (config->gpi14_routing & 0x03) << 28;
162 reg32 |= (config->gpi15_routing & 0x03) << 30;
163
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200164 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100165}
166
Elyes HAOUASbe841402018-05-13 13:40:39 +0200167static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100168{
169 u8 reg8;
170 u16 reg16, pmbase;
171 u32 reg32;
172 const char *state;
173 /* Get the chip configuration */
174 config_t *config = dev->chip_info;
175
Nico Huber9faae2b2018-11-14 00:00:35 +0100176 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100177 int nmi_option;
178
179 /* Which state do we want to goto after g3 (power restored)?
180 * 0 == S0 Full On
181 * 1 == S5 Soft Off
182 *
183 * If the option is not existent (Laptops), use Kconfig setting.
184 */
185 get_option(&pwr_on, "power_on_after_fail");
186
187 reg16 = pci_read_config16(dev, GEN_PMCON_3);
188 reg16 &= 0xfffe;
189 switch (pwr_on) {
190 case MAINBOARD_POWER_OFF:
191 reg16 |= 1;
192 state = "off";
193 break;
194 case MAINBOARD_POWER_ON:
195 reg16 &= ~1;
196 state = "on";
197 break;
198 case MAINBOARD_POWER_KEEP:
199 reg16 &= ~1;
200 state = "state keep";
201 break;
202 default:
203 state = "undefined";
204 }
205
206 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
207 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
208
209 reg16 &= ~(1 << 10);
210 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
211
212 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
213
214 pci_write_config16(dev, GEN_PMCON_3, reg16);
215 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
216
217 /* Set up NMI on errors. */
218 reg8 = inb(0x61);
219 reg8 &= 0x0f; /* Higher Nibble must be 0 */
220 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
221 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
222 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
223 outb(reg8, 0x61);
224
225 reg8 = inb(0x70);
226 nmi_option = NMI_OFF;
227 get_option(&nmi_option, "nmi");
228 if (nmi_option) {
229 printk(BIOS_INFO, "NMI sources enabled.\n");
230 reg8 &= ~(1 << 7); /* Set NMI. */
231 } else {
232 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200233 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100234 }
235 outb(reg8, 0x70);
236
237 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
238 reg16 = pci_read_config16(dev, GEN_PMCON_1);
239 reg16 &= ~(3 << 0); // SMI# rate 1 minute
240 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
241#if DEBUG_PERIODIC_SMIS
242 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
243 * periodic SMIs.
244 */
245 reg16 |= (3 << 0); // Periodic SMI every 8s
246#endif
247 pci_write_config16(dev, GEN_PMCON_1, reg16);
248
249 // Set the board's GPI routing.
250 pch_gpi_routing(dev);
251
252 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
253
254 outl(config->gpe0_en, pmbase + GPE0_EN);
255 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
256
257 /* Set up power management block and determine sleep mode */
258 reg32 = inl(pmbase + 0x04); // PM1_CNT
259 reg32 &= ~(7 << 10); // SLP_TYP
260 reg32 |= (1 << 0); // SCI_EN
261 outl(reg32, pmbase + 0x04);
262
263 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200264 reg32 = RCBA32(PRSTS);
265 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
266 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100267
Angel Pons42b4e4e2019-09-18 10:58:53 +0200268 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100269 reg32 = RCBA32(0x3f02);
270 reg32 &= ~0xf;
271 RCBA32(0x3f02) = reg32;
272}
273
274static void pch_rtc_init(struct device *dev)
275{
276 u8 reg8;
277 int rtc_failed;
278
279 reg8 = pci_read_config8(dev, GEN_PMCON_3);
280 rtc_failed = reg8 & RTC_BATTERY_DEAD;
281 if (rtc_failed) {
282 reg8 &= ~RTC_BATTERY_DEAD;
283 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100284 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100285 }
286 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
287
Gabe Blackb3f08c62014-04-30 17:12:25 -0700288 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100289}
290
291static void mobile5_pm_init(struct device *dev)
292{
293 int i;
294
295 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
296 pci_write_config8(dev, 0xa9, 0x47);
297
298 RCBA32 (0x1d44) = 0x00000000;
299 (void) RCBA32 (0x1d44);
300 RCBA32 (0x1d48) = 0x00030000;
301 (void) RCBA32 (0x1d48);
302 RCBA32 (0x1e80) = 0x000c0801;
303 (void) RCBA32 (0x1e80);
304 RCBA32 (0x1e84) = 0x000200f0;
305 (void) RCBA32 (0x1e84);
306
307 const u32 rcba2010[] =
308 {
309 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
310 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
311 };
Elyes HAOUAS035df002016-10-03 21:54:16 +0200312 for (i = 0; i < sizeof(rcba2010) / sizeof(rcba2010[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100313 {
314 RCBA32 (0x2010 + 4 * i) = rcba2010[i];
315 RCBA32 (0x2010 + 4 * i);
316 }
317
318 RCBA32 (0x2100) = 0x00000000;
319 (void) RCBA32 (0x2100);
320 RCBA32 (0x2104) = 0x00000757;
321 (void) RCBA32 (0x2104);
322 RCBA32 (0x2108) = 0x00170001;
323 (void) RCBA32 (0x2108);
324
325 RCBA32 (0x211c) = 0x00000000;
326 (void) RCBA32 (0x211c);
327 RCBA32 (0x2120) = 0x00010000;
328 (void) RCBA32 (0x2120);
329
330 RCBA32 (0x21fc) = 0x00000000;
331 (void) RCBA32 (0x21fc);
332 RCBA32 (0x2200) = 0x20000044;
333 (void) RCBA32 (0x2200);
334 RCBA32 (0x2204) = 0x00000001;
335 (void) RCBA32 (0x2204);
336 RCBA32 (0x2208) = 0x00003457;
337 (void) RCBA32 (0x2208);
338
339 const u32 rcba2210[] =
340 {
341 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
342 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
343 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
344 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
345 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
346 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
347 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
348 };
349
Elyes HAOUAS035df002016-10-03 21:54:16 +0200350 for (i = 0; i < sizeof(rcba2210) / sizeof(rcba2210[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100351 {
352 RCBA32 (0x2210 + 4 * i) = rcba2210[i];
353 RCBA32 (0x2210 + 4 * i);
354 }
355
356 const u32 rcba2300[] =
357 {
358 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
359 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
360 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
361 };
362
Elyes HAOUAS035df002016-10-03 21:54:16 +0200363 for (i = 0; i < sizeof(rcba2300) / sizeof(rcba2300[0]); i++)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100364 {
365 RCBA32 (0x2300 + 4 * i) = rcba2300[i];
366 RCBA32 (0x2300 + 4 * i);
367 }
368
369 RCBA32 (0x37fc) = 0x00000000;
370 (void) RCBA32 (0x37fc);
371 RCBA32 (0x3dfc) = 0x00000000;
372 (void) RCBA32 (0x3dfc);
373 RCBA32 (0x3e7c) = 0xffffffff;
374 (void) RCBA32 (0x3e7c);
375 RCBA32 (0x3efc) = 0x00000000;
376 (void) RCBA32 (0x3efc);
377 RCBA32 (0x3f00) = 0x0000010b;
378 (void) RCBA32 (0x3f00);
379}
380
381static void enable_hpet(void)
382{
383 u32 reg32;
384
385 /* Move HPET to default address 0xfed00000 and enable it */
386 reg32 = RCBA32(HPTC);
387 reg32 |= (1 << 7); // HPET Address Enable
388 reg32 &= ~(3 << 0);
389 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200390 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100391
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800392 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100393}
394
Elyes HAOUASbe841402018-05-13 13:40:39 +0200395static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100396{
397 u32 reg32;
398 u16 reg16;
399
400 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
401
402 reg16 = pci_read_config16(dev, GEN_PMCON_1);
403 reg16 |= (1 << 2) | (1 << 11);
404 pci_write_config16(dev, GEN_PMCON_1, reg16);
405
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100406 reg32 = RCBA32(CG);
407 reg32 |= (1 << 31);
408 reg32 |= (1 << 29) | (1 << 28);
409 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
410 reg32 |= (1 << 16);
411 reg32 |= (1 << 17);
412 reg32 |= (1 << 18);
413 reg32 |= (1 << 22);
414 reg32 |= (1 << 23);
415 reg32 &= ~(1 << 20);
416 reg32 |= (1 << 19);
417 reg32 |= (1 << 0);
418 reg32 |= (0xf << 1);
419 RCBA32(CG) = reg32;
420
421 RCBA32_OR(0x38c0, 0x7);
422 RCBA32_OR(0x36d4, 0x6680c004);
423 RCBA32_OR(0x3564, 0x3);
424}
425
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200426static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100427{
Julius Werner5d1f9a02019-03-07 17:07:26 -0800428 if (!acpi_is_wakeup_s3() && CONFIG(HAVE_SMI_HANDLER)) {
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100429 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200430 outb(APM_CNT_ACPI_DISABLE, APM_CNT); // Disable ACPI mode
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100431 printk(BIOS_DEBUG, "done.\n");
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100432 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100433}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100434
435static void pch_disable_smm_only_flashing(struct device *dev)
436{
437 u8 reg8;
438
439 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100440 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100441 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100442 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100443}
444
445static void pch_fixups(struct device *dev)
446{
447 /*
448 * Enable DMI ASPM in the PCH
449 */
450 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
451 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
452 RCBA32_OR(0x21a8, 0x3);
453}
454
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100455static void lpc_init(struct device *dev)
456{
457 printk(BIOS_DEBUG, "pch: lpc_init\n");
458
459 /* Set the value for PCI command register. */
460 pci_write_config16(dev, PCI_COMMAND, 0x000f);
461
462 /* IO APIC initialization. */
463 pch_enable_ioapic(dev);
464
465 pch_enable_serial_irqs(dev);
466
467 /* Setup the PIRQ. */
468 pch_pirq_init(dev);
469
470 /* Setup power options. */
471 pch_power_options(dev);
472
473 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200474 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100475
476 /* Set the state of the GPIO lines. */
477 //gpio_init(dev);
478
479 /* Initialize the real time clock. */
480 pch_rtc_init(dev);
481
482 /* Initialize ISA DMA. */
483 isa_dma_init();
484
485 /* Initialize the High Precision Event Timers, if present. */
486 enable_hpet();
487
488 /* Initialize Clock Gating */
489 enable_clock_gating(dev);
490
491 setup_i8259();
492
493 /* The OS should do this? */
494 /* Interrupt 9 should be level triggered (SCI) */
495 i8259_configure_irq_trigger(9, 1);
496
497 pch_disable_smm_only_flashing(dev);
498
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200499 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100500
501 pch_fixups(dev);
502}
503
Elyes HAOUASbe841402018-05-13 13:40:39 +0200504static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100505{
506 struct resource *res;
507 config_t *config = dev->chip_info;
508 u8 io_index = 0;
509
510 /* Get the normal PCI resources of this device. */
511 pci_dev_read_resources(dev);
512
513 /* Add an extra subtractive resource for both memory and I/O. */
514 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
515 res->base = 0;
516 res->size = 0x1000;
517 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
518 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
519
520 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
521 res->base = 0xff800000;
522 res->size = 0x00800000; /* 8 MB for flash */
523 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
524 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
525
526 res = new_resource(dev, 3); /* IOAPIC */
527 res->base = IO_APIC_ADDR;
528 res->size = 0x00001000;
529 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
530
531 /* Set PCH IO decode ranges if required.*/
532 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
533 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
534 res->base = config->gen1_dec & 0xFFFC;
535 res->size = (config->gen1_dec >> 16) & 0xFC;
536 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
537 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
538 }
539
540 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
541 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
542 res->base = config->gen2_dec & 0xFFFC;
543 res->size = (config->gen2_dec >> 16) & 0xFC;
544 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
545 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
546 }
547
548 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
549 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
550 res->base = config->gen3_dec & 0xFFFC;
551 res->size = (config->gen3_dec >> 16) & 0xFC;
552 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
553 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
554 }
555
556 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
557 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
558 res->base = config->gen4_dec & 0xFFFC;
559 res->size = (config->gen4_dec >> 16) & 0xFC;
560 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
561 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
562 }
563}
564
Elyes HAOUASbe841402018-05-13 13:40:39 +0200565static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100566{
567 /* Enable PCH Display Port */
568 RCBA16(DISPBDF) = 0x0010;
569 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
570
571 pch_enable(dev);
572}
573
Elyes HAOUASbe841402018-05-13 13:40:39 +0200574static void southbridge_inject_dsdt(struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200575{
Elyes HAOUAS035df002016-10-03 21:54:16 +0200576 global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200577
578 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200579 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200580
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200581 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200582
583 gnvs->apic = 1;
584 gnvs->mpen = 1; /* Enable Multi Processing */
585 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100586
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200587 /* And tell SMI about it */
588 smm_setup_structures(gnvs, NULL, NULL);
589
590 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100591 acpigen_write_scope("\\");
592 acpigen_write_name_dword("NVSA", (u32) gnvs);
593 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200594 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200595}
596
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200597void acpi_fill_fadt(acpi_fadt_t *fadt)
598{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300599 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200600 config_t *chip = dev->chip_info;
601 u16 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
602 int c2_latency;
603
Elyes HAOUAS0d4de2a2019-02-28 13:04:29 +0100604 fadt->reserved = 0;
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200605
606 fadt->sci_int = 0x9;
607 fadt->smi_cmd = APM_CNT;
608 fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
609 fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
610 fadt->s4bios_req = 0x0;
611 fadt->pstate_cnt = 0;
612
613 fadt->pm1a_evt_blk = pmbase;
614 fadt->pm1b_evt_blk = 0x0;
615 fadt->pm1a_cnt_blk = pmbase + 0x4;
616 fadt->pm1b_cnt_blk = 0x0;
617 fadt->pm2_cnt_blk = pmbase + 0x50;
618 fadt->pm_tmr_blk = pmbase + 0x8;
619 fadt->gpe0_blk = pmbase + 0x20;
620 fadt->gpe1_blk = 0;
621
622 fadt->pm1_evt_len = 4;
623 fadt->pm1_cnt_len = 2;
624 fadt->pm2_cnt_len = 1;
625 fadt->pm_tmr_len = 4;
626 fadt->gpe0_blk_len = 16;
627 fadt->gpe1_blk_len = 0;
628 fadt->gpe1_base = 0;
629 fadt->cst_cnt = 0;
630 c2_latency = chip->c2_latency;
631 if (!c2_latency) {
632 c2_latency = 101; /* c2 unsupported */
633 }
634 fadt->p_lvl2_lat = c2_latency;
635 fadt->p_lvl3_lat = 87;
636 fadt->flush_size = 1024;
637 fadt->flush_stride = 16;
Patrick Rudolphb30a47b2019-07-15 18:04:23 +0200638 /* P_CNT not supported */
639 fadt->duty_offset = 0;
640 fadt->duty_width = 0;
641
Vladimir Serbinenko67bfbfd2014-10-25 15:49:23 +0200642 fadt->day_alrm = 0xd;
643 fadt->mon_alrm = 0x00;
644 fadt->century = 0x32;
645 fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
646
647 fadt->flags = ACPI_FADT_WBINVD |
648 ACPI_FADT_C1_SUPPORTED |
649 ACPI_FADT_SLEEP_BUTTON |
650 ACPI_FADT_RESET_REGISTER |
651 ACPI_FADT_S4_RTC_WAKE |
652 ACPI_FADT_PLATFORM_CLOCK;
653 if (chip->docking_supported) {
654 fadt->flags |= ACPI_FADT_DOCKING_SUPPORTED;
655 }
656 if (c2_latency < 100) {
657 fadt->flags |= ACPI_FADT_C2_MP_SUPPORTED;
658 }
659
660 fadt->reset_reg.space_id = 1;
661 fadt->reset_reg.bit_width = 8;
662 fadt->reset_reg.bit_offset = 0;
663 fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
664 fadt->reset_reg.addrl = 0xcf9;
665 fadt->reset_reg.addrh = 0;
666
667 fadt->reset_value = 6;
668
669 fadt->x_pm1a_evt_blk.space_id = 1;
670 fadt->x_pm1a_evt_blk.bit_width = 32;
671 fadt->x_pm1a_evt_blk.bit_offset = 0;
672 fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
673 fadt->x_pm1a_evt_blk.addrl = pmbase;
674 fadt->x_pm1a_evt_blk.addrh = 0x0;
675
676 fadt->x_pm1b_evt_blk.space_id = 1;
677 fadt->x_pm1b_evt_blk.bit_width = 0;
678 fadt->x_pm1b_evt_blk.bit_offset = 0;
679 fadt->x_pm1b_evt_blk.access_size = 0;
680 fadt->x_pm1b_evt_blk.addrl = 0x0;
681 fadt->x_pm1b_evt_blk.addrh = 0x0;
682
683 fadt->x_pm1a_cnt_blk.space_id = 1;
684 fadt->x_pm1a_cnt_blk.bit_width = 16;
685 fadt->x_pm1a_cnt_blk.bit_offset = 0;
686 fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
687 fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
688 fadt->x_pm1a_cnt_blk.addrh = 0x0;
689
690 fadt->x_pm1b_cnt_blk.space_id = 1;
691 fadt->x_pm1b_cnt_blk.bit_width = 0;
692 fadt->x_pm1b_cnt_blk.bit_offset = 0;
693 fadt->x_pm1b_cnt_blk.access_size = 0;
694 fadt->x_pm1b_cnt_blk.addrl = 0x0;
695 fadt->x_pm1b_cnt_blk.addrh = 0x0;
696
697 fadt->x_pm2_cnt_blk.space_id = 1;
698 fadt->x_pm2_cnt_blk.bit_width = 8;
699 fadt->x_pm2_cnt_blk.bit_offset = 0;
700 fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
701 fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
702 fadt->x_pm2_cnt_blk.addrh = 0x0;
703
704 fadt->x_pm_tmr_blk.space_id = 1;
705 fadt->x_pm_tmr_blk.bit_width = 32;
706 fadt->x_pm_tmr_blk.bit_offset = 0;
707 fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
708 fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
709 fadt->x_pm_tmr_blk.addrh = 0x0;
710
711 fadt->x_gpe0_blk.space_id = 1;
712 fadt->x_gpe0_blk.bit_width = 128;
713 fadt->x_gpe0_blk.bit_offset = 0;
714 fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
715 fadt->x_gpe0_blk.addrl = pmbase + 0x20;
716 fadt->x_gpe0_blk.addrh = 0x0;
717
718 fadt->x_gpe1_blk.space_id = 1;
719 fadt->x_gpe1_blk.bit_width = 0;
720 fadt->x_gpe1_blk.bit_offset = 0;
721 fadt->x_gpe1_blk.access_size = 0;
722 fadt->x_gpe1_blk.addrl = 0x0;
723 fadt->x_gpe1_blk.addrh = 0x0;
724}
725
Kyösti Mälkki90993952018-05-01 19:36:25 +0300726static const char *lpc_acpi_name(const struct device *dev)
727{
728 return "LPCB";
729}
730
Elyes HAOUASbe841402018-05-13 13:40:39 +0200731static void southbridge_fill_ssdt(struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100732{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300733 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100734 config_t *chip = dev->chip_info;
735
736 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300737 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100738}
739
Bill XIEd533b162017-08-22 16:26:22 +0800740static void lpc_final(struct device *dev)
741{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200742 spi_finalize_ops();
743
Bill XIEd533b162017-08-22 16:26:22 +0800744 /* Call SMM finalize() handlers before resume */
Julius Wernercd49cce2019-03-05 16:53:33 -0800745 if (CONFIG(HAVE_SMI_HANDLER)) {
746 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
Bill XIEd533b162017-08-22 16:26:22 +0800747 acpi_is_wakeup_s3()) {
748 outb(APM_CNT_FINALIZE, APM_CNT);
749 }
750 }
751}
752
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100753static struct pci_operations pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530754 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100755};
756
757static struct device_operations device_ops = {
758 .read_resources = pch_lpc_read_resources,
759 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200760 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200761 .acpi_inject_dsdt = southbridge_inject_dsdt,
762 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300763 .acpi_name = lpc_acpi_name,
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200764 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100765 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800766 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100767 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100768 .scan_bus = scan_static_bus,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100769 .ops_pci = &pci_ops,
770};
771
772
Felix Singer838fbc72019-11-21 21:23:32 +0100773static const unsigned short pci_device_ids[] = {
774 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
775 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
776 0
777};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100778
779static const struct pci_driver pch_lpc __pci_driver = {
780 .ops = &device_ops,
781 .vendor = PCI_VENDOR_ID_INTEL,
782 .devices = pci_device_ids,
783};