blob: 8269dd9f225c647eac79dae1d0271d4f3dd3a500 [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;
Angel Pons77f340a2020-10-17 18:39:04 +020092 /*
93 * Interrupt 11 is not used by legacy devices and so can always be used for
94 * PCI interrupts. Full legacy IRQ routing is complicated and hard to
95 * get right. Fortunately all modern OS use MSI and so it's not that big of
96 * an issue anyway. Still we have to provide a reasonable default. Using
97 * interrupt 11 for it everywhere is a working default. ACPI-aware OS can
98 * move it to any interrupt and others will just leave them at default.
Vladimir Serbinenko888d5592013-11-13 17:53:38 +010099 */
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200100 const u8 pirq_routing = 11;
101
102 pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
103 pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
104 pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
105 pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
106
107 pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
108 pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
109 pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
110 pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100111
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200112 for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200113 u8 int_pin=0;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100114
115 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
116 continue;
117
118 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
119
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200120 if (int_pin == 0)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100121 continue;
122
Vladimir Serbinenko33b535f2014-10-19 10:13:14 +0200123 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, pirq_routing);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100124 }
125}
126
Elyes HAOUASbe841402018-05-13 13:40:39 +0200127static void pch_gpi_routing(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100128{
129 /* Get the chip configuration */
130 config_t *config = dev->chip_info;
131 u32 reg32 = 0;
132
133 /* An array would be much nicer here, or some
134 * other method of doing this.
135 */
136 reg32 |= (config->gpi0_routing & 0x03) << 0;
137 reg32 |= (config->gpi1_routing & 0x03) << 2;
138 reg32 |= (config->gpi2_routing & 0x03) << 4;
139 reg32 |= (config->gpi3_routing & 0x03) << 6;
140 reg32 |= (config->gpi4_routing & 0x03) << 8;
141 reg32 |= (config->gpi5_routing & 0x03) << 10;
142 reg32 |= (config->gpi6_routing & 0x03) << 12;
143 reg32 |= (config->gpi7_routing & 0x03) << 14;
144 reg32 |= (config->gpi8_routing & 0x03) << 16;
145 reg32 |= (config->gpi9_routing & 0x03) << 18;
146 reg32 |= (config->gpi10_routing & 0x03) << 20;
147 reg32 |= (config->gpi11_routing & 0x03) << 22;
148 reg32 |= (config->gpi12_routing & 0x03) << 24;
149 reg32 |= (config->gpi13_routing & 0x03) << 26;
150 reg32 |= (config->gpi14_routing & 0x03) << 28;
151 reg32 |= (config->gpi15_routing & 0x03) << 30;
152
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200153 pci_write_config32(dev, GPIO_ROUT, reg32);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100154}
155
Elyes HAOUASbe841402018-05-13 13:40:39 +0200156static void pch_power_options(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100157{
158 u8 reg8;
159 u16 reg16, pmbase;
160 u32 reg32;
161 const char *state;
162 /* Get the chip configuration */
163 config_t *config = dev->chip_info;
164
Nico Huber9faae2b2018-11-14 00:00:35 +0100165 int pwr_on = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100166 int nmi_option;
167
168 /* Which state do we want to goto after g3 (power restored)?
169 * 0 == S0 Full On
170 * 1 == S5 Soft Off
171 *
172 * If the option is not existent (Laptops), use Kconfig setting.
173 */
174 get_option(&pwr_on, "power_on_after_fail");
175
176 reg16 = pci_read_config16(dev, GEN_PMCON_3);
177 reg16 &= 0xfffe;
178 switch (pwr_on) {
179 case MAINBOARD_POWER_OFF:
180 reg16 |= 1;
181 state = "off";
182 break;
183 case MAINBOARD_POWER_ON:
184 reg16 &= ~1;
185 state = "on";
186 break;
187 case MAINBOARD_POWER_KEEP:
188 reg16 &= ~1;
189 state = "state keep";
190 break;
191 default:
192 state = "undefined";
193 }
194
195 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
196 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
197
198 reg16 &= ~(1 << 10);
199 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
200
201 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
202
203 pci_write_config16(dev, GEN_PMCON_3, reg16);
204 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
205
206 /* Set up NMI on errors. */
207 reg8 = inb(0x61);
208 reg8 &= 0x0f; /* Higher Nibble must be 0 */
209 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
210 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
211 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
212 outb(reg8, 0x61);
213
214 reg8 = inb(0x70);
215 nmi_option = NMI_OFF;
216 get_option(&nmi_option, "nmi");
217 if (nmi_option) {
218 printk(BIOS_INFO, "NMI sources enabled.\n");
219 reg8 &= ~(1 << 7); /* Set NMI. */
220 } else {
221 printk(BIOS_INFO, "NMI sources disabled.\n");
Elyes HAOUAS9c5d4632018-04-26 22:21:21 +0200222 reg8 |= (1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100223 }
224 outb(reg8, 0x70);
225
226 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
227 reg16 = pci_read_config16(dev, GEN_PMCON_1);
228 reg16 &= ~(3 << 0); // SMI# rate 1 minute
229 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
Kyösti Mälkki94464472020-06-13 13:45:42 +0300230 if (CONFIG(DEBUG_PERIODIC_SMI))
231 reg16 |= (3 << 0); // Periodic SMI every 8s
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100232 pci_write_config16(dev, GEN_PMCON_1, reg16);
233
234 // Set the board's GPI routing.
235 pch_gpi_routing(dev);
236
237 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
238
239 outl(config->gpe0_en, pmbase + GPE0_EN);
240 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
241
242 /* Set up power management block and determine sleep mode */
243 reg32 = inl(pmbase + 0x04); // PM1_CNT
244 reg32 &= ~(7 << 10); // SLP_TYP
245 reg32 |= (1 << 0); // SCI_EN
246 outl(reg32, pmbase + 0x04);
247
248 /* Clear magic status bits to prevent unexpected wake */
Angel Pons42b4e4e2019-09-18 10:58:53 +0200249 reg32 = RCBA32(PRSTS);
250 reg32 |= (1 << 5) | (1 << 4) | (1 << 0);
251 RCBA32(PRSTS) = reg32;
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100252
Angel Pons42b4e4e2019-09-18 10:58:53 +0200253 /* FIXME: Does this even exist? */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100254 reg32 = RCBA32(0x3f02);
255 reg32 &= ~0xf;
256 RCBA32(0x3f02) = reg32;
257}
258
259static void pch_rtc_init(struct device *dev)
260{
261 u8 reg8;
262 int rtc_failed;
263
264 reg8 = pci_read_config8(dev, GEN_PMCON_3);
265 rtc_failed = reg8 & RTC_BATTERY_DEAD;
266 if (rtc_failed) {
267 reg8 &= ~RTC_BATTERY_DEAD;
268 pci_write_config8(dev, GEN_PMCON_3, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100269 elog_add_event(ELOG_TYPE_RTC_RESET);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100270 }
271 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
272
Gabe Blackb3f08c62014-04-30 17:12:25 -0700273 cmos_init(rtc_failed);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100274}
275
276static void mobile5_pm_init(struct device *dev)
277{
278 int i;
279
280 printk(BIOS_DEBUG, "Mobile 5 PM init\n");
281 pci_write_config8(dev, 0xa9, 0x47);
282
Angel Pons77f340a2020-10-17 18:39:04 +0200283 RCBA32(0x1d44) = 0x00000000;
284 (void)RCBA32(0x1d44);
285 RCBA32(0x1d48) = 0x00030000;
286 (void)RCBA32(0x1d48);
287 RCBA32(0x1e80) = 0x000c0801;
288 (void)RCBA32(0x1e80);
289 RCBA32(0x1e84) = 0x000200f0;
290 (void)RCBA32(0x1e84);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100291
Angel Pons77f340a2020-10-17 18:39:04 +0200292 const u32 rcba2010[] = {
293 /* 2010: */ 0x00188200, 0x14000016, 0xbc4abcb5, 0x00000000,
294 /* 2020: */ 0xf0c9605b, 0x13683040, 0x04c8f16e, 0x09e90170
295 };
296 for (i = 0; i < ARRAY_SIZE(rcba2010); i++) {
297 RCBA32(0x2010 + 4 * i) = rcba2010[i];
298 RCBA32(0x2010 + 4 * i);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100299 }
300
Angel Pons77f340a2020-10-17 18:39:04 +0200301 RCBA32(0x2100) = 0x00000000;
302 (void)RCBA32(0x2100);
303 RCBA32(0x2104) = 0x00000757;
304 (void)RCBA32(0x2104);
305 RCBA32(0x2108) = 0x00170001;
306 (void)RCBA32(0x2108);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100307
Angel Pons77f340a2020-10-17 18:39:04 +0200308 RCBA32(0x211c) = 0x00000000;
309 (void)RCBA32(0x211c);
310 RCBA32(0x2120) = 0x00010000;
311 (void)RCBA32(0x2120);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100312
Angel Pons77f340a2020-10-17 18:39:04 +0200313 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);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100321
Angel Pons77f340a2020-10-17 18:39:04 +0200322 const u32 rcba2210[] = {
323 /* 2210 */ 0x00000000, 0x00000001, 0xa0fff210, 0x0000df00,
324 /* 2220 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
325 /* 2230 */ 0x00e30880, 0x00000070, 0x00004000, 0x00000000,
326 /* 2240 */ 0x00002301, 0x36000000, 0x00010107, 0x00160000,
327 /* 2250 */ 0x00001b01, 0x36000000, 0x00010107, 0x00160000,
328 /* 2260 */ 0x00000601, 0x16000000, 0x00010107, 0x00160000,
329 /* 2270 */ 0x00001c01, 0x16000000, 0x00010107, 0x00160000
330 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100331
Angel Pons77f340a2020-10-17 18:39:04 +0200332 for (i = 0; i < ARRAY_SIZE(rcba2210); i++) {
333 RCBA32(0x2210 + 4 * i) = rcba2210[i];
334 RCBA32(0x2210 + 4 * i);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100335 }
336
Angel Pons77f340a2020-10-17 18:39:04 +0200337 const u32 rcba2300[] = {
338 /* 2300: */ 0x00000000, 0x40000000, 0x4646827b, 0x6e803131,
339 /* 2310: */ 0x32c77887, 0x00077733, 0x00007447, 0x00000040,
340 /* 2320: */ 0xcccc0cfc, 0x0fbb0fff
341 };
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100342
Angel Pons77f340a2020-10-17 18:39:04 +0200343 for (i = 0; i < ARRAY_SIZE(rcba2300); i++) {
344 RCBA32(0x2300 + 4 * i) = rcba2300[i];
345 RCBA32(0x2300 + 4 * i);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100346 }
347
Angel Pons77f340a2020-10-17 18:39:04 +0200348 RCBA32(0x37fc) = 0x00000000;
349 (void)RCBA32(0x37fc);
350 RCBA32(0x3dfc) = 0x00000000;
351 (void)RCBA32(0x3dfc);
352 RCBA32(0x3e7c) = 0xffffffff;
353 (void)RCBA32(0x3e7c);
354 RCBA32(0x3efc) = 0x00000000;
355 (void)RCBA32(0x3efc);
356 RCBA32(0x3f00) = 0x0000010b;
357 (void)RCBA32(0x3f00);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100358}
359
360static void enable_hpet(void)
361{
362 u32 reg32;
363
364 /* Move HPET to default address 0xfed00000 and enable it */
365 reg32 = RCBA32(HPTC);
366 reg32 |= (1 << 7); // HPET Address Enable
367 reg32 &= ~(3 << 0);
368 RCBA32(HPTC) = reg32;
Arthur Heymans37e1d932019-10-02 14:33:34 +0200369 RCBA32(HPTC); /* Read back for it to work */
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100370
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800371 write32((u32 *)0xfed00010, read32((u32 *)0xfed00010) | 1);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100372}
373
Elyes HAOUASbe841402018-05-13 13:40:39 +0200374static void enable_clock_gating(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100375{
376 u32 reg32;
377 u16 reg16;
378
379 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
380
381 reg16 = pci_read_config16(dev, GEN_PMCON_1);
382 reg16 |= (1 << 2) | (1 << 11);
383 pci_write_config16(dev, GEN_PMCON_1, reg16);
384
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100385 reg32 = RCBA32(CG);
386 reg32 |= (1 << 31);
387 reg32 |= (1 << 29) | (1 << 28);
388 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
389 reg32 |= (1 << 16);
390 reg32 |= (1 << 17);
391 reg32 |= (1 << 18);
392 reg32 |= (1 << 22);
393 reg32 |= (1 << 23);
394 reg32 &= ~(1 << 20);
395 reg32 |= (1 << 19);
396 reg32 |= (1 << 0);
397 reg32 |= (0xf << 1);
398 RCBA32(CG) = reg32;
399
400 RCBA32_OR(0x38c0, 0x7);
401 RCBA32_OR(0x36d4, 0x6680c004);
402 RCBA32_OR(0x3564, 0x3);
403}
404
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200405static void pch_set_acpi_mode(void)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100406{
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300407 if (!acpi_is_wakeup_s3()) {
408 apm_control(APM_CNT_ACPI_DISABLE);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100409 }
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100410}
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100411
412static void pch_disable_smm_only_flashing(struct device *dev)
413{
414 u8 reg8;
415
416 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100417 reg8 = pci_read_config8(dev, BIOS_CNTL);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100418 reg8 &= ~(1 << 5);
Elyes HAOUAS0c22d2f2018-12-01 12:19:52 +0100419 pci_write_config8(dev, BIOS_CNTL, reg8);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100420}
421
422static void pch_fixups(struct device *dev)
423{
424 /*
425 * Enable DMI ASPM in the PCH
426 */
427 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
428 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
429 RCBA32_OR(0x21a8, 0x3);
430}
431
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100432static void lpc_init(struct device *dev)
433{
Elyes HAOUASbfc255a2020-03-07 13:05:14 +0100434 printk(BIOS_DEBUG, "pch: %s\n", __func__);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100435
436 /* Set the value for PCI command register. */
Angel Pons89739ba2020-07-25 02:46:39 +0200437 pci_write_config16(dev, PCI_COMMAND,
438 PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL |
439 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100440
441 /* IO APIC initialization. */
442 pch_enable_ioapic(dev);
443
444 pch_enable_serial_irqs(dev);
445
446 /* Setup the PIRQ. */
447 pch_pirq_init(dev);
448
449 /* Setup power options. */
450 pch_power_options(dev);
451
452 /* Initialize power management */
Arthur Heymansd0310fa2019-10-02 00:21:01 +0200453 mobile5_pm_init(dev);
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100454
455 /* Set the state of the GPIO lines. */
456 //gpio_init(dev);
457
458 /* Initialize the real time clock. */
459 pch_rtc_init(dev);
460
461 /* Initialize ISA DMA. */
462 isa_dma_init();
463
464 /* Initialize the High Precision Event Timers, if present. */
465 enable_hpet();
466
467 /* Initialize Clock Gating */
468 enable_clock_gating(dev);
469
470 setup_i8259();
471
472 /* The OS should do this? */
473 /* Interrupt 9 should be level triggered (SCI) */
474 i8259_configure_irq_trigger(9, 1);
475
476 pch_disable_smm_only_flashing(dev);
477
Vladimir Serbinenko456f4952015-05-28 20:42:32 +0200478 pch_set_acpi_mode();
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100479
480 pch_fixups(dev);
481}
482
Elyes HAOUASbe841402018-05-13 13:40:39 +0200483static void pch_lpc_read_resources(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100484{
485 struct resource *res;
486 config_t *config = dev->chip_info;
487 u8 io_index = 0;
488
489 /* Get the normal PCI resources of this device. */
490 pci_dev_read_resources(dev);
491
492 /* Add an extra subtractive resource for both memory and I/O. */
493 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
494 res->base = 0;
495 res->size = 0x1000;
496 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
497 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
498
499 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
500 res->base = 0xff800000;
501 res->size = 0x00800000; /* 8 MB for flash */
502 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
503 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
504
505 res = new_resource(dev, 3); /* IOAPIC */
506 res->base = IO_APIC_ADDR;
507 res->size = 0x00001000;
508 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
509
510 /* Set PCH IO decode ranges if required.*/
511 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
512 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
513 res->base = config->gen1_dec & 0xFFFC;
514 res->size = (config->gen1_dec >> 16) & 0xFC;
515 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
516 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
517 }
518
519 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
520 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
521 res->base = config->gen2_dec & 0xFFFC;
522 res->size = (config->gen2_dec >> 16) & 0xFC;
523 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
524 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
525 }
526
527 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
528 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
529 res->base = config->gen3_dec & 0xFFFC;
530 res->size = (config->gen3_dec >> 16) & 0xFC;
531 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
532 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
533 }
534
535 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
536 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
537 res->base = config->gen4_dec & 0xFFFC;
538 res->size = (config->gen4_dec >> 16) & 0xFC;
539 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
540 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
541 }
542}
543
Elyes HAOUASbe841402018-05-13 13:40:39 +0200544static void pch_lpc_enable(struct device *dev)
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100545{
546 /* Enable PCH Display Port */
547 RCBA16(DISPBDF) = 0x0010;
548 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
549
550 pch_enable(dev);
551}
552
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300553void southbridge_inject_dsdt(const struct device *dev)
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200554{
Kyösti Mälkki0c1dd9c2020-06-17 23:37:49 +0300555 struct global_nvs *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200556
557 if (gnvs) {
Elyes HAOUAS035df002016-10-03 21:54:16 +0200558 memset(gnvs, 0, sizeof(*gnvs));
Vladimir Serbinenko7309c642014-10-05 11:07:33 +0200559
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200560 acpi_create_gnvs(gnvs);
Vladimir Serbinenko9d45d692014-10-20 19:16:44 +0200561
562 gnvs->apic = 1;
563 gnvs->mpen = 1; /* Enable Multi Processing */
564 gnvs->pcnt = dev_count_cpu();
Nico Huber744d6bd2019-01-12 14:58:20 +0100565
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200566 /* And tell SMI about it */
Kyösti Mälkkic3c55212020-06-17 10:34:26 +0300567 apm_control(APM_CNT_GNVS_UPDATE);
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200568
569 /* Add it to SSDT. */
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100570 acpigen_write_scope("\\");
Angel Pons77f340a2020-10-17 18:39:04 +0200571 acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
Vladimir Serbinenko226d7842014-11-04 21:09:23 +0100572 acpigen_pop_len();
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200573 }
Vladimir Serbinenko35c0f432014-09-02 22:25:36 +0200574}
575
Kyösti Mälkki90993952018-05-01 19:36:25 +0300576static const char *lpc_acpi_name(const struct device *dev)
577{
578 return "LPCB";
579}
580
Furquan Shaikh7536a392020-04-24 21:59:21 -0700581static void southbridge_fill_ssdt(const struct device *device)
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100582{
Kyösti Mälkkic70eed12018-05-22 02:18:00 +0300583 struct device *dev = pcidev_on_root(0x1f, 0);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100584 config_t *chip = dev->chip_info;
585
586 intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8);
Kyösti Mälkki90993952018-05-01 19:36:25 +0300587 intel_acpi_gen_def_acpi_pirq(dev);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100588}
589
Bill XIEd533b162017-08-22 16:26:22 +0800590static void lpc_final(struct device *dev)
591{
Arthur Heymansaadd1d02019-05-28 13:39:20 +0200592 spi_finalize_ops();
593
Bill XIEd533b162017-08-22 16:26:22 +0800594 /* Call SMM finalize() handlers before resume */
Kyösti Mälkkiad882c32020-06-02 05:05:30 +0300595 if (CONFIG(INTEL_CHIPSET_LOCKDOWN) ||
596 acpi_is_wakeup_s3()) {
597 apm_control(APM_CNT_FINALIZE);
Bill XIEd533b162017-08-22 16:26:22 +0800598 }
599}
600
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100601static struct device_operations device_ops = {
602 .read_resources = pch_lpc_read_resources,
603 .set_resources = pci_dev_set_resources,
Arthur Heymans3b452e02019-10-03 09:16:10 +0200604 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200605 .acpi_inject_dsdt = southbridge_inject_dsdt,
606 .acpi_fill_ssdt = southbridge_fill_ssdt,
Kyösti Mälkki90993952018-05-01 19:36:25 +0300607 .acpi_name = lpc_acpi_name,
Angel Pons77f340a2020-10-17 18:39:04 +0200608 .write_acpi_tables = acpi_write_hpet,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100609 .init = lpc_init,
Bill XIEd533b162017-08-22 16:26:22 +0800610 .final = lpc_final,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100611 .enable = pch_lpc_enable,
Nico Huber51b75ae2019-03-14 16:02:05 +0100612 .scan_bus = scan_static_bus,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200613 .ops_pci = &pci_dev_ops_pci,
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100614};
615
Felix Singer838fbc72019-11-21 21:23:32 +0100616static const unsigned short pci_device_ids[] = {
617 PCI_DID_INTEL_IBEXPEAK_LPC_QM57,
618 PCI_DID_INTEL_IBEXPEAK_LPC_HM55,
619 0
620};
Vladimir Serbinenko888d5592013-11-13 17:53:38 +0100621
622static const struct pci_driver pch_lpc __pci_driver = {
623 .ops = &device_ops,
624 .vendor = PCI_VENDOR_ID_INTEL,
625 .devices = pci_device_ids,
626};