xref: /openbmc/linux/arch/x86/kernel/early-quirks.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
254ef3400SAndi Kleen /* Various workarounds for chipset bugs.
354ef3400SAndi Kleen    This code runs very early and can't use the regular PCI subsystem
454ef3400SAndi Kleen    The entries are keyed to PCI bridges which usually identify chipsets
554ef3400SAndi Kleen    uniquely.
654ef3400SAndi Kleen    This is only for whole classes of chipsets with specific problems which
754ef3400SAndi Kleen    need early invasive action (e.g. before the timers are initialized).
854ef3400SAndi Kleen    Most PCI device specific workarounds can be done later and should be
954ef3400SAndi Kleen    in standard PCI quirks
1054ef3400SAndi Kleen    Mainboard specific bugs should be handled by DMI entries.
1154ef3400SAndi Kleen    CPU specific bugs in setup.c */
1254ef3400SAndi Kleen 
1354ef3400SAndi Kleen #include <linux/pci.h>
1454ef3400SAndi Kleen #include <linux/acpi.h>
15abb2bafdSLukas Wunner #include <linux/delay.h>
1654ef3400SAndi Kleen #include <linux/pci_ids.h>
17abb2bafdSLukas Wunner #include <linux/bcma/bcma.h>
18abb2bafdSLukas Wunner #include <linux/bcma/bcma_regs.h>
19630b3affSLukas Wunner #include <linux/platform_data/x86/apple.h>
20814c5f1fSJesse Barnes #include <drm/i915_drm.h>
215f1b97cbSJani Nikula #include <drm/i915_pciids.h>
2254ef3400SAndi Kleen #include <asm/pci-direct.h>
2354ef3400SAndi Kleen #include <asm/dma.h>
2454ef3400SAndi Kleen #include <asm/io_apic.h>
2554ef3400SAndi Kleen #include <asm/apic.h>
2662187910SFeng Tang #include <asm/hpet.h>
2746a7fa27SFUJITA Tomonori #include <asm/iommu.h>
281d9b16d1SJoerg Roedel #include <asm/gart.h>
2903bbcb2eSNeil Horman #include <asm/irq_remapping.h>
30abb2bafdSLukas Wunner #include <asm/early_ioremap.h>
31abb2bafdSLukas Wunner 
fix_hypertransport_config(int num,int slot,int func)32c6b48324SNeil Horman static void __init fix_hypertransport_config(int num, int slot, int func)
33c6b48324SNeil Horman {
34c6b48324SNeil Horman 	u32 htcfg;
35c6b48324SNeil Horman 	/*
36c6b48324SNeil Horman 	 * we found a hypertransport bus
37c6b48324SNeil Horman 	 * make sure that we are broadcasting
38c6b48324SNeil Horman 	 * interrupts to all cpus on the ht bus
39c6b48324SNeil Horman 	 * if we're using extended apic ids
40c6b48324SNeil Horman 	 */
41c6b48324SNeil Horman 	htcfg = read_pci_config(num, slot, func, 0x68);
42c6b48324SNeil Horman 	if (htcfg & (1 << 18)) {
437bcbc78dSNeil Horman 		printk(KERN_INFO "Detected use of extended apic ids "
447bcbc78dSNeil Horman 				 "on hypertransport bus\n");
45c6b48324SNeil Horman 		if ((htcfg & (1 << 17)) == 0) {
467bcbc78dSNeil Horman 			printk(KERN_INFO "Enabling hypertransport extended "
477bcbc78dSNeil Horman 					 "apic interrupt broadcast\n");
487bcbc78dSNeil Horman 			printk(KERN_INFO "Note this is a bios bug, "
497bcbc78dSNeil Horman 					 "please contact your hw vendor\n");
50c6b48324SNeil Horman 			htcfg |= (1 << 17);
51c6b48324SNeil Horman 			write_pci_config(num, slot, func, 0x68, htcfg);
52c6b48324SNeil Horman 		}
53c6b48324SNeil Horman 	}
54c6b48324SNeil Horman 
55c6b48324SNeil Horman 
56c6b48324SNeil Horman }
57c6b48324SNeil Horman 
via_bugs(int num,int slot,int func)58c6b48324SNeil Horman static void __init via_bugs(int  num, int slot, int func)
5954ef3400SAndi Kleen {
60966396d3SJoerg Roedel #ifdef CONFIG_GART_IOMMU
61c987d12fSYinghai Lu 	if ((max_pfn > MAX_DMA32_PFN ||  force_iommu) &&
620440d4c0SJoerg Roedel 	    !gart_iommu_aperture_allowed) {
6354ef3400SAndi Kleen 		printk(KERN_INFO
6454ef3400SAndi Kleen 		       "Looks like a VIA chipset. Disabling IOMMU."
6554ef3400SAndi Kleen 		       " Override with iommu=allowed\n");
660440d4c0SJoerg Roedel 		gart_iommu_aperture_disabled = 1;
6754ef3400SAndi Kleen 	}
6854ef3400SAndi Kleen #endif
6954ef3400SAndi Kleen }
7054ef3400SAndi Kleen 
7154ef3400SAndi Kleen #ifdef CONFIG_ACPI
7203d0d20eSJeff Garzik #ifdef CONFIG_X86_IO_APIC
7354ef3400SAndi Kleen 
nvidia_hpet_check(struct acpi_table_header * header)7454ef3400SAndi Kleen static int __init nvidia_hpet_check(struct acpi_table_header *header)
7554ef3400SAndi Kleen {
7654ef3400SAndi Kleen 	return 0;
7754ef3400SAndi Kleen }
7803d0d20eSJeff Garzik #endif /* CONFIG_X86_IO_APIC */
7903d0d20eSJeff Garzik #endif /* CONFIG_ACPI */
8054ef3400SAndi Kleen 
nvidia_bugs(int num,int slot,int func)81c6b48324SNeil Horman static void __init nvidia_bugs(int num, int slot, int func)
8254ef3400SAndi Kleen {
8354ef3400SAndi Kleen #ifdef CONFIG_ACPI
8454ef3400SAndi Kleen #ifdef CONFIG_X86_IO_APIC
8554ef3400SAndi Kleen 	/*
86447d29d1SLukas Wunner 	 * Only applies to Nvidia root ports (bus 0) and not to
87447d29d1SLukas Wunner 	 * Nvidia graphics cards with PCI ports on secondary buses.
88447d29d1SLukas Wunner 	 */
89447d29d1SLukas Wunner 	if (num)
90447d29d1SLukas Wunner 		return;
91447d29d1SLukas Wunner 
92447d29d1SLukas Wunner 	/*
9354ef3400SAndi Kleen 	 * All timer overrides on Nvidia are
9454ef3400SAndi Kleen 	 * wrong unless HPET is enabled.
9554ef3400SAndi Kleen 	 * Unfortunately that's not true on many Asus boards.
9654ef3400SAndi Kleen 	 * We don't know yet how to detect this automatically, but
9754ef3400SAndi Kleen 	 * at least allow a command line override.
9854ef3400SAndi Kleen 	 */
9954ef3400SAndi Kleen 	if (acpi_use_timer_override)
10054ef3400SAndi Kleen 		return;
10154ef3400SAndi Kleen 
10254ef3400SAndi Kleen 	if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
10354ef3400SAndi Kleen 		acpi_skip_timer_override = 1;
10454ef3400SAndi Kleen 		printk(KERN_INFO "Nvidia board "
10554ef3400SAndi Kleen 		       "detected. Ignoring ACPI "
10654ef3400SAndi Kleen 		       "timer override.\n");
10754ef3400SAndi Kleen 		printk(KERN_INFO "If you got timer trouble "
10854ef3400SAndi Kleen 			"try acpi_use_timer_override\n");
10954ef3400SAndi Kleen 	}
11054ef3400SAndi Kleen #endif
11154ef3400SAndi Kleen #endif
11254ef3400SAndi Kleen 	/* RED-PEN skip them on mptables too? */
11354ef3400SAndi Kleen 
11454ef3400SAndi Kleen }
11554ef3400SAndi Kleen 
11626adcfbfSAndreas Herrmann #if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
ati_ixp4x0_rev(int num,int slot,int func)11726adcfbfSAndreas Herrmann static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
11833fb0e4eSAndreas Herrmann {
11933fb0e4eSAndreas Herrmann 	u32 d;
12033fb0e4eSAndreas Herrmann 	u8  b;
12133fb0e4eSAndreas Herrmann 
12233fb0e4eSAndreas Herrmann 	b = read_pci_config_byte(num, slot, func, 0xac);
12333fb0e4eSAndreas Herrmann 	b &= ~(1<<5);
12433fb0e4eSAndreas Herrmann 	write_pci_config_byte(num, slot, func, 0xac, b);
12533fb0e4eSAndreas Herrmann 
12633fb0e4eSAndreas Herrmann 	d = read_pci_config(num, slot, func, 0x70);
12733fb0e4eSAndreas Herrmann 	d |= 1<<8;
12833fb0e4eSAndreas Herrmann 	write_pci_config(num, slot, func, 0x70, d);
12933fb0e4eSAndreas Herrmann 
13033fb0e4eSAndreas Herrmann 	d = read_pci_config(num, slot, func, 0x8);
13133fb0e4eSAndreas Herrmann 	d &= 0xff;
13233fb0e4eSAndreas Herrmann 	return d;
13333fb0e4eSAndreas Herrmann }
13433fb0e4eSAndreas Herrmann 
ati_bugs(int num,int slot,int func)13533fb0e4eSAndreas Herrmann static void __init ati_bugs(int num, int slot, int func)
13633fb0e4eSAndreas Herrmann {
13733fb0e4eSAndreas Herrmann 	u32 d;
13833fb0e4eSAndreas Herrmann 	u8  b;
13933fb0e4eSAndreas Herrmann 
14033fb0e4eSAndreas Herrmann 	if (acpi_use_timer_override)
14133fb0e4eSAndreas Herrmann 		return;
14233fb0e4eSAndreas Herrmann 
14333fb0e4eSAndreas Herrmann 	d = ati_ixp4x0_rev(num, slot, func);
14433fb0e4eSAndreas Herrmann 	if (d  < 0x82)
14533fb0e4eSAndreas Herrmann 		acpi_skip_timer_override = 1;
14633fb0e4eSAndreas Herrmann 	else {
14733fb0e4eSAndreas Herrmann 		/* check for IRQ0 interrupt swap */
14833fb0e4eSAndreas Herrmann 		outb(0x72, 0xcd6); b = inb(0xcd7);
14933fb0e4eSAndreas Herrmann 		if (!(b & 0x2))
15033fb0e4eSAndreas Herrmann 			acpi_skip_timer_override = 1;
15133fb0e4eSAndreas Herrmann 	}
15233fb0e4eSAndreas Herrmann 
15333fb0e4eSAndreas Herrmann 	if (acpi_skip_timer_override) {
15433fb0e4eSAndreas Herrmann 		printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
15533fb0e4eSAndreas Herrmann 		printk(KERN_INFO "Ignoring ACPI timer override.\n");
15633fb0e4eSAndreas Herrmann 		printk(KERN_INFO "If you got timer trouble "
15733fb0e4eSAndreas Herrmann 		       "try acpi_use_timer_override\n");
15833fb0e4eSAndreas Herrmann 	}
15933fb0e4eSAndreas Herrmann }
16033fb0e4eSAndreas Herrmann 
ati_sbx00_rev(int num,int slot,int func)16126adcfbfSAndreas Herrmann static u32 __init ati_sbx00_rev(int num, int slot, int func)
16226adcfbfSAndreas Herrmann {
1637f74f8f2SAndreas Herrmann 	u32 d;
16426adcfbfSAndreas Herrmann 
16526adcfbfSAndreas Herrmann 	d = read_pci_config(num, slot, func, 0x8);
16626adcfbfSAndreas Herrmann 	d &= 0xff;
16726adcfbfSAndreas Herrmann 
16826adcfbfSAndreas Herrmann 	return d;
16926adcfbfSAndreas Herrmann }
17026adcfbfSAndreas Herrmann 
ati_bugs_contd(int num,int slot,int func)17126adcfbfSAndreas Herrmann static void __init ati_bugs_contd(int num, int slot, int func)
17226adcfbfSAndreas Herrmann {
17326adcfbfSAndreas Herrmann 	u32 d, rev;
17426adcfbfSAndreas Herrmann 
1757f74f8f2SAndreas Herrmann 	rev = ati_sbx00_rev(num, slot, func);
1767f74f8f2SAndreas Herrmann 	if (rev >= 0x40)
1777f74f8f2SAndreas Herrmann 		acpi_fix_pin2_polarity = 1;
1787f74f8f2SAndreas Herrmann 
1791d3e09a3SAndreas Herrmann 	/*
1801d3e09a3SAndreas Herrmann 	 * SB600: revisions 0x11, 0x12, 0x13, 0x14, ...
1811d3e09a3SAndreas Herrmann 	 * SB700: revisions 0x39, 0x3a, ...
1821d3e09a3SAndreas Herrmann 	 * SB800: revisions 0x40, 0x41, ...
1831d3e09a3SAndreas Herrmann 	 */
1841d3e09a3SAndreas Herrmann 	if (rev >= 0x39)
18526adcfbfSAndreas Herrmann 		return;
18626adcfbfSAndreas Herrmann 
1877f74f8f2SAndreas Herrmann 	if (acpi_use_timer_override)
18826adcfbfSAndreas Herrmann 		return;
18926adcfbfSAndreas Herrmann 
19026adcfbfSAndreas Herrmann 	/* check for IRQ0 interrupt swap */
19126adcfbfSAndreas Herrmann 	d = read_pci_config(num, slot, func, 0x64);
19226adcfbfSAndreas Herrmann 	if (!(d & (1<<14)))
19326adcfbfSAndreas Herrmann 		acpi_skip_timer_override = 1;
19426adcfbfSAndreas Herrmann 
19526adcfbfSAndreas Herrmann 	if (acpi_skip_timer_override) {
19626adcfbfSAndreas Herrmann 		printk(KERN_INFO "SB600 revision 0x%x\n", rev);
19726adcfbfSAndreas Herrmann 		printk(KERN_INFO "Ignoring ACPI timer override.\n");
19826adcfbfSAndreas Herrmann 		printk(KERN_INFO "If you got timer trouble "
19926adcfbfSAndreas Herrmann 		       "try acpi_use_timer_override\n");
20026adcfbfSAndreas Herrmann 	}
20126adcfbfSAndreas Herrmann }
20226adcfbfSAndreas Herrmann #else
ati_bugs(int num,int slot,int func)20326adcfbfSAndreas Herrmann static void __init ati_bugs(int num, int slot, int func)
20426adcfbfSAndreas Herrmann {
20526adcfbfSAndreas Herrmann }
20626adcfbfSAndreas Herrmann 
ati_bugs_contd(int num,int slot,int func)20726adcfbfSAndreas Herrmann static void __init ati_bugs_contd(int num, int slot, int func)
20826adcfbfSAndreas Herrmann {
20926adcfbfSAndreas Herrmann }
21026adcfbfSAndreas Herrmann #endif
21126adcfbfSAndreas Herrmann 
intel_remapping_check(int num,int slot,int func)21203bbcb2eSNeil Horman static void __init intel_remapping_check(int num, int slot, int func)
21303bbcb2eSNeil Horman {
21403bbcb2eSNeil Horman 	u8 revision;
215803075dbSNeil Horman 	u16 device;
21603bbcb2eSNeil Horman 
217803075dbSNeil Horman 	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
21803bbcb2eSNeil Horman 	revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
21903bbcb2eSNeil Horman 
22003bbcb2eSNeil Horman 	/*
2216f8a1b33SNeil Horman 	 * Revision <= 13 of all triggering devices id in this quirk
2226f8a1b33SNeil Horman 	 * have a problem draining interrupts when irq remapping is
2236f8a1b33SNeil Horman 	 * enabled, and should be flagged as broken. Additionally
2246f8a1b33SNeil Horman 	 * revision 0x22 of device id 0x3405 has this problem.
22503bbcb2eSNeil Horman 	 */
2266f8a1b33SNeil Horman 	if (revision <= 0x13)
22703bbcb2eSNeil Horman 		set_irq_remapping_broken();
2286f8a1b33SNeil Horman 	else if (device == 0x3405 && revision == 0x22)
229803075dbSNeil Horman 		set_irq_remapping_broken();
23003bbcb2eSNeil Horman }
23103bbcb2eSNeil Horman 
232814c5f1fSJesse Barnes /*
233814c5f1fSJesse Barnes  * Systems with Intel graphics controllers set aside memory exclusively
234814c5f1fSJesse Barnes  * for gfx driver use.  This memory is not marked in the E820 as reserved
235814c5f1fSJesse Barnes  * or as RAM, and so is subject to overlap from E820 manipulation later
236814c5f1fSJesse Barnes  * in the boot process.  On some systems, MMIO space is allocated on top,
237814c5f1fSJesse Barnes  * despite the efforts of the "RAM buffer" approach, which simply rounds
238814c5f1fSJesse Barnes  * memory boundaries up to 64M to try to catch space that may decode
239814c5f1fSJesse Barnes  * as RAM and so is not suitable for MMIO.
240814c5f1fSJesse Barnes  */
241814c5f1fSJesse Barnes 
24286e58762SVille Syrjälä #define KB(x)	((x) * 1024UL)
243814c5f1fSJesse Barnes #define MB(x)	(KB (KB (x)))
244814c5f1fSJesse Barnes 
i830_tseg_size(void)2456f9fa996SJoonas Lahtinen static resource_size_t __init i830_tseg_size(void)
246a4dff769SVille Syrjälä {
247c0dd3460SJoonas Lahtinen 	u8 esmramc = read_pci_config_byte(0, 0, 0, I830_ESMRAMC);
248a4dff769SVille Syrjälä 
249c0dd3460SJoonas Lahtinen 	if (!(esmramc & TSEG_ENABLE))
250a4dff769SVille Syrjälä 		return 0;
251a4dff769SVille Syrjälä 
252c0dd3460SJoonas Lahtinen 	if (esmramc & I830_TSEG_SIZE_1M)
253a4dff769SVille Syrjälä 		return MB(1);
254a4dff769SVille Syrjälä 	else
255a4dff769SVille Syrjälä 		return KB(512);
256a4dff769SVille Syrjälä }
257a4dff769SVille Syrjälä 
i845_tseg_size(void)2586f9fa996SJoonas Lahtinen static resource_size_t __init i845_tseg_size(void)
259a4dff769SVille Syrjälä {
260c0dd3460SJoonas Lahtinen 	u8 esmramc = read_pci_config_byte(0, 0, 0, I845_ESMRAMC);
261c0dd3460SJoonas Lahtinen 	u8 tseg_size = esmramc & I845_TSEG_SIZE_MASK;
262a4dff769SVille Syrjälä 
263c0dd3460SJoonas Lahtinen 	if (!(esmramc & TSEG_ENABLE))
264a4dff769SVille Syrjälä 		return 0;
265a4dff769SVille Syrjälä 
266c0dd3460SJoonas Lahtinen 	switch (tseg_size) {
267c0dd3460SJoonas Lahtinen 	case I845_TSEG_SIZE_512K:	return KB(512);
268c0dd3460SJoonas Lahtinen 	case I845_TSEG_SIZE_1M:		return MB(1);
269a4dff769SVille Syrjälä 	default:
270c0dd3460SJoonas Lahtinen 		WARN(1, "Unknown ESMRAMC value: %x!\n", esmramc);
271a4dff769SVille Syrjälä 	}
272c0dd3460SJoonas Lahtinen 	return 0;
273a4dff769SVille Syrjälä }
274a4dff769SVille Syrjälä 
i85x_tseg_size(void)2756f9fa996SJoonas Lahtinen static resource_size_t __init i85x_tseg_size(void)
276a4dff769SVille Syrjälä {
277c0dd3460SJoonas Lahtinen 	u8 esmramc = read_pci_config_byte(0, 0, 0, I85X_ESMRAMC);
278a4dff769SVille Syrjälä 
279c0dd3460SJoonas Lahtinen 	if (!(esmramc & TSEG_ENABLE))
280a4dff769SVille Syrjälä 		return 0;
281a4dff769SVille Syrjälä 
282a4dff769SVille Syrjälä 	return MB(1);
283a4dff769SVille Syrjälä }
284a4dff769SVille Syrjälä 
i830_mem_size(void)2856f9fa996SJoonas Lahtinen static resource_size_t __init i830_mem_size(void)
286a4dff769SVille Syrjälä {
287a4dff769SVille Syrjälä 	return read_pci_config_byte(0, 0, 0, I830_DRB3) * MB(32);
288a4dff769SVille Syrjälä }
289a4dff769SVille Syrjälä 
i85x_mem_size(void)2906f9fa996SJoonas Lahtinen static resource_size_t __init i85x_mem_size(void)
291a4dff769SVille Syrjälä {
292a4dff769SVille Syrjälä 	return read_pci_config_byte(0, 0, 1, I85X_DRB3) * MB(32);
293a4dff769SVille Syrjälä }
294a4dff769SVille Syrjälä 
295a4dff769SVille Syrjälä /*
296a4dff769SVille Syrjälä  * On 830/845/85x the stolen memory base isn't available in any
297a4dff769SVille Syrjälä  * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size.
298a4dff769SVille Syrjälä  */
i830_stolen_base(int num,int slot,int func,resource_size_t stolen_size)2996f9fa996SJoonas Lahtinen static resource_size_t __init i830_stolen_base(int num, int slot, int func,
3006f9fa996SJoonas Lahtinen 					       resource_size_t stolen_size)
301a4dff769SVille Syrjälä {
3026f9fa996SJoonas Lahtinen 	return i830_mem_size() - i830_tseg_size() - stolen_size;
303a4dff769SVille Syrjälä }
304a4dff769SVille Syrjälä 
i845_stolen_base(int num,int slot,int func,resource_size_t stolen_size)3056f9fa996SJoonas Lahtinen static resource_size_t __init i845_stolen_base(int num, int slot, int func,
3066f9fa996SJoonas Lahtinen 					       resource_size_t stolen_size)
307a4dff769SVille Syrjälä {
3086f9fa996SJoonas Lahtinen 	return i830_mem_size() - i845_tseg_size() - stolen_size;
309a4dff769SVille Syrjälä }
310a4dff769SVille Syrjälä 
i85x_stolen_base(int num,int slot,int func,resource_size_t stolen_size)3116f9fa996SJoonas Lahtinen static resource_size_t __init i85x_stolen_base(int num, int slot, int func,
3126f9fa996SJoonas Lahtinen 					       resource_size_t stolen_size)
313a4dff769SVille Syrjälä {
3146f9fa996SJoonas Lahtinen 	return i85x_mem_size() - i85x_tseg_size() - stolen_size;
315a4dff769SVille Syrjälä }
316a4dff769SVille Syrjälä 
i865_stolen_base(int num,int slot,int func,resource_size_t stolen_size)3176f9fa996SJoonas Lahtinen static resource_size_t __init i865_stolen_base(int num, int slot, int func,
3186f9fa996SJoonas Lahtinen 					       resource_size_t stolen_size)
319a4dff769SVille Syrjälä {
320d721b02fSVille Syrjälä 	u16 toud = 0;
321c0dd3460SJoonas Lahtinen 
322c0dd3460SJoonas Lahtinen 	toud = read_pci_config_16(0, 0, 0, I865_TOUD);
323c0dd3460SJoonas Lahtinen 
3246f9fa996SJoonas Lahtinen 	return toud * KB(64) + i845_tseg_size();
325c0dd3460SJoonas Lahtinen }
326c0dd3460SJoonas Lahtinen 
gen3_stolen_base(int num,int slot,int func,resource_size_t stolen_size)3276f9fa996SJoonas Lahtinen static resource_size_t __init gen3_stolen_base(int num, int slot, int func,
3286f9fa996SJoonas Lahtinen 					       resource_size_t stolen_size)
329c0dd3460SJoonas Lahtinen {
330c0dd3460SJoonas Lahtinen 	u32 bsm;
331c0dd3460SJoonas Lahtinen 
332c0dd3460SJoonas Lahtinen 	/* Almost universally we can find the Graphics Base of Stolen Memory
333c0dd3460SJoonas Lahtinen 	 * at register BSM (0x5c) in the igfx configuration space. On a few
334c0dd3460SJoonas Lahtinen 	 * (desktop) machines this is also mirrored in the bridge device at
335c0dd3460SJoonas Lahtinen 	 * different locations, or in the MCHBAR.
336c0dd3460SJoonas Lahtinen 	 */
337c0dd3460SJoonas Lahtinen 	bsm = read_pci_config(num, slot, func, INTEL_BSM);
338c0dd3460SJoonas Lahtinen 
3396f9fa996SJoonas Lahtinen 	return bsm & INTEL_BSM_MASK;
340a4dff769SVille Syrjälä }
341a4dff769SVille Syrjälä 
gen11_stolen_base(int num,int slot,int func,resource_size_t stolen_size)342db0c8d8bSPaulo Zanoni static resource_size_t __init gen11_stolen_base(int num, int slot, int func,
343db0c8d8bSPaulo Zanoni 						resource_size_t stolen_size)
344db0c8d8bSPaulo Zanoni {
345db0c8d8bSPaulo Zanoni 	u64 bsm;
346db0c8d8bSPaulo Zanoni 
347db0c8d8bSPaulo Zanoni 	bsm = read_pci_config(num, slot, func, INTEL_GEN11_BSM_DW0);
348db0c8d8bSPaulo Zanoni 	bsm &= INTEL_BSM_MASK;
349db0c8d8bSPaulo Zanoni 	bsm |= (u64)read_pci_config(num, slot, func, INTEL_GEN11_BSM_DW1) << 32;
350db0c8d8bSPaulo Zanoni 
351db0c8d8bSPaulo Zanoni 	return bsm;
352db0c8d8bSPaulo Zanoni }
353db0c8d8bSPaulo Zanoni 
i830_stolen_size(int num,int slot,int func)3546f9fa996SJoonas Lahtinen static resource_size_t __init i830_stolen_size(int num, int slot, int func)
355a4dff769SVille Syrjälä {
356a4dff769SVille Syrjälä 	u16 gmch_ctrl;
357c0dd3460SJoonas Lahtinen 	u16 gms;
358a4dff769SVille Syrjälä 
359a4dff769SVille Syrjälä 	gmch_ctrl = read_pci_config_16(0, 0, 0, I830_GMCH_CTRL);
360c0dd3460SJoonas Lahtinen 	gms = gmch_ctrl & I830_GMCH_GMS_MASK;
361a4dff769SVille Syrjälä 
362c0dd3460SJoonas Lahtinen 	switch (gms) {
363c0dd3460SJoonas Lahtinen 	case I830_GMCH_GMS_STOLEN_512:	return KB(512);
364c0dd3460SJoonas Lahtinen 	case I830_GMCH_GMS_STOLEN_1024:	return MB(1);
365c0dd3460SJoonas Lahtinen 	case I830_GMCH_GMS_STOLEN_8192:	return MB(8);
366a4dff769SVille Syrjälä 	/* local memory isn't part of the normal address space */
367c0dd3460SJoonas Lahtinen 	case I830_GMCH_GMS_LOCAL:	return 0;
368a4dff769SVille Syrjälä 	default:
369c0dd3460SJoonas Lahtinen 		WARN(1, "Unknown GMCH_CTRL value: %x!\n", gmch_ctrl);
370a4dff769SVille Syrjälä 	}
371a4dff769SVille Syrjälä 
372c0dd3460SJoonas Lahtinen 	return 0;
373a4dff769SVille Syrjälä }
374a4dff769SVille Syrjälä 
gen3_stolen_size(int num,int slot,int func)3756f9fa996SJoonas Lahtinen static resource_size_t __init gen3_stolen_size(int num, int slot, int func)
376814c5f1fSJesse Barnes {
377814c5f1fSJesse Barnes 	u16 gmch_ctrl;
378c0dd3460SJoonas Lahtinen 	u16 gms;
379814c5f1fSJesse Barnes 
380814c5f1fSJesse Barnes 	gmch_ctrl = read_pci_config_16(0, 0, 0, I830_GMCH_CTRL);
381c0dd3460SJoonas Lahtinen 	gms = gmch_ctrl & I855_GMCH_GMS_MASK;
382814c5f1fSJesse Barnes 
383c0dd3460SJoonas Lahtinen 	switch (gms) {
384c0dd3460SJoonas Lahtinen 	case I855_GMCH_GMS_STOLEN_1M:	return MB(1);
385c0dd3460SJoonas Lahtinen 	case I855_GMCH_GMS_STOLEN_4M:	return MB(4);
386c0dd3460SJoonas Lahtinen 	case I855_GMCH_GMS_STOLEN_8M:	return MB(8);
387c0dd3460SJoonas Lahtinen 	case I855_GMCH_GMS_STOLEN_16M:	return MB(16);
388c0dd3460SJoonas Lahtinen 	case I855_GMCH_GMS_STOLEN_32M:	return MB(32);
389c0dd3460SJoonas Lahtinen 	case I915_GMCH_GMS_STOLEN_48M:	return MB(48);
390c0dd3460SJoonas Lahtinen 	case I915_GMCH_GMS_STOLEN_64M:	return MB(64);
391c0dd3460SJoonas Lahtinen 	case G33_GMCH_GMS_STOLEN_128M:	return MB(128);
392c0dd3460SJoonas Lahtinen 	case G33_GMCH_GMS_STOLEN_256M:	return MB(256);
393c0dd3460SJoonas Lahtinen 	case INTEL_GMCH_GMS_STOLEN_96M:	return MB(96);
394c0dd3460SJoonas Lahtinen 	case INTEL_GMCH_GMS_STOLEN_160M:return MB(160);
395c0dd3460SJoonas Lahtinen 	case INTEL_GMCH_GMS_STOLEN_224M:return MB(224);
396c0dd3460SJoonas Lahtinen 	case INTEL_GMCH_GMS_STOLEN_352M:return MB(352);
397814c5f1fSJesse Barnes 	default:
398c0dd3460SJoonas Lahtinen 		WARN(1, "Unknown GMCH_CTRL value: %x!\n", gmch_ctrl);
399814c5f1fSJesse Barnes 	}
400814c5f1fSJesse Barnes 
401c0dd3460SJoonas Lahtinen 	return 0;
402814c5f1fSJesse Barnes }
403814c5f1fSJesse Barnes 
gen6_stolen_size(int num,int slot,int func)4046f9fa996SJoonas Lahtinen static resource_size_t __init gen6_stolen_size(int num, int slot, int func)
405814c5f1fSJesse Barnes {
406814c5f1fSJesse Barnes 	u16 gmch_ctrl;
407c0dd3460SJoonas Lahtinen 	u16 gms;
408814c5f1fSJesse Barnes 
409814c5f1fSJesse Barnes 	gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
410c0dd3460SJoonas Lahtinen 	gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
411814c5f1fSJesse Barnes 
4126f9fa996SJoonas Lahtinen 	return gms * MB(32);
413814c5f1fSJesse Barnes }
414814c5f1fSJesse Barnes 
gen8_stolen_size(int num,int slot,int func)4156f9fa996SJoonas Lahtinen static resource_size_t __init gen8_stolen_size(int num, int slot, int func)
4169459d252SBen Widawsky {
4179459d252SBen Widawsky 	u16 gmch_ctrl;
418c0dd3460SJoonas Lahtinen 	u16 gms;
4199459d252SBen Widawsky 
4209459d252SBen Widawsky 	gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
421c0dd3460SJoonas Lahtinen 	gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
422c0dd3460SJoonas Lahtinen 
4236f9fa996SJoonas Lahtinen 	return gms * MB(32);
4249459d252SBen Widawsky }
4259459d252SBen Widawsky 
chv_stolen_size(int num,int slot,int func)4266f9fa996SJoonas Lahtinen static resource_size_t __init chv_stolen_size(int num, int slot, int func)
4273e3b2c39SDamien Lespiau {
4283e3b2c39SDamien Lespiau 	u16 gmch_ctrl;
429c0dd3460SJoonas Lahtinen 	u16 gms;
4303e3b2c39SDamien Lespiau 
4313e3b2c39SDamien Lespiau 	gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
432c0dd3460SJoonas Lahtinen 	gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
4333e3b2c39SDamien Lespiau 
4343e3b2c39SDamien Lespiau 	/*
4353e3b2c39SDamien Lespiau 	 * 0x0  to 0x10: 32MB increments starting at 0MB
4363e3b2c39SDamien Lespiau 	 * 0x11 to 0x16: 4MB increments starting at 8MB
4373e3b2c39SDamien Lespiau 	 * 0x17 to 0x1d: 4MB increments start at 36MB
4383e3b2c39SDamien Lespiau 	 */
439c0dd3460SJoonas Lahtinen 	if (gms < 0x11)
4406f9fa996SJoonas Lahtinen 		return gms * MB(32);
441c0dd3460SJoonas Lahtinen 	else if (gms < 0x17)
4423b51b6f3SMatthew Auld 		return (gms - 0x11) * MB(4) + MB(8);
4433e3b2c39SDamien Lespiau 	else
4443b51b6f3SMatthew Auld 		return (gms - 0x17) * MB(4) + MB(36);
4453e3b2c39SDamien Lespiau }
44652ca7045SVille Syrjälä 
gen9_stolen_size(int num,int slot,int func)4476f9fa996SJoonas Lahtinen static resource_size_t __init gen9_stolen_size(int num, int slot, int func)
44866375014SDamien Lespiau {
44966375014SDamien Lespiau 	u16 gmch_ctrl;
450c0dd3460SJoonas Lahtinen 	u16 gms;
45166375014SDamien Lespiau 
45266375014SDamien Lespiau 	gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
453c0dd3460SJoonas Lahtinen 	gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
45466375014SDamien Lespiau 
455c0dd3460SJoonas Lahtinen 	/* 0x0  to 0xef: 32MB increments starting at 0MB */
456c0dd3460SJoonas Lahtinen 	/* 0xf0 to 0xfe: 4MB increments starting at 4MB */
457c0dd3460SJoonas Lahtinen 	if (gms < 0xf0)
4586f9fa996SJoonas Lahtinen 		return gms * MB(32);
45966375014SDamien Lespiau 	else
4603b51b6f3SMatthew Auld 		return (gms - 0xf0) * MB(4) + MB(4);
46166375014SDamien Lespiau }
46266375014SDamien Lespiau 
463ee0629cfSJoonas Lahtinen struct intel_early_ops {
4646f9fa996SJoonas Lahtinen 	resource_size_t (*stolen_size)(int num, int slot, int func);
4656f9fa996SJoonas Lahtinen 	resource_size_t (*stolen_base)(int num, int slot, int func,
4666f9fa996SJoonas Lahtinen 				       resource_size_t size);
467a4dff769SVille Syrjälä };
468a4dff769SVille Syrjälä 
469ee0629cfSJoonas Lahtinen static const struct intel_early_ops i830_early_ops __initconst = {
470ee0629cfSJoonas Lahtinen 	.stolen_base = i830_stolen_base,
471ee0629cfSJoonas Lahtinen 	.stolen_size = i830_stolen_size,
472a4dff769SVille Syrjälä };
473a4dff769SVille Syrjälä 
474ee0629cfSJoonas Lahtinen static const struct intel_early_ops i845_early_ops __initconst = {
475ee0629cfSJoonas Lahtinen 	.stolen_base = i845_stolen_base,
476ee0629cfSJoonas Lahtinen 	.stolen_size = i830_stolen_size,
477a4dff769SVille Syrjälä };
478a4dff769SVille Syrjälä 
479ee0629cfSJoonas Lahtinen static const struct intel_early_ops i85x_early_ops __initconst = {
480ee0629cfSJoonas Lahtinen 	.stolen_base = i85x_stolen_base,
481ee0629cfSJoonas Lahtinen 	.stolen_size = gen3_stolen_size,
482a4dff769SVille Syrjälä };
483a4dff769SVille Syrjälä 
484ee0629cfSJoonas Lahtinen static const struct intel_early_ops i865_early_ops __initconst = {
485ee0629cfSJoonas Lahtinen 	.stolen_base = i865_stolen_base,
486ee0629cfSJoonas Lahtinen 	.stolen_size = gen3_stolen_size,
48752ca7045SVille Syrjälä };
48852ca7045SVille Syrjälä 
489ee0629cfSJoonas Lahtinen static const struct intel_early_ops gen3_early_ops __initconst = {
490ee0629cfSJoonas Lahtinen 	.stolen_base = gen3_stolen_base,
491ee0629cfSJoonas Lahtinen 	.stolen_size = gen3_stolen_size,
49252ca7045SVille Syrjälä };
49352ca7045SVille Syrjälä 
494ee0629cfSJoonas Lahtinen static const struct intel_early_ops gen6_early_ops __initconst = {
495ee0629cfSJoonas Lahtinen 	.stolen_base = gen3_stolen_base,
496ee0629cfSJoonas Lahtinen 	.stolen_size = gen6_stolen_size,
49752ca7045SVille Syrjälä };
498814c5f1fSJesse Barnes 
499ee0629cfSJoonas Lahtinen static const struct intel_early_ops gen8_early_ops __initconst = {
500ee0629cfSJoonas Lahtinen 	.stolen_base = gen3_stolen_base,
501ee0629cfSJoonas Lahtinen 	.stolen_size = gen8_stolen_size,
50266375014SDamien Lespiau };
50366375014SDamien Lespiau 
504ee0629cfSJoonas Lahtinen static const struct intel_early_ops gen9_early_ops __initconst = {
505ee0629cfSJoonas Lahtinen 	.stolen_base = gen3_stolen_base,
506ee0629cfSJoonas Lahtinen 	.stolen_size = gen9_stolen_size,
5073e3b2c39SDamien Lespiau };
5083e3b2c39SDamien Lespiau 
509ee0629cfSJoonas Lahtinen static const struct intel_early_ops chv_early_ops __initconst = {
510ee0629cfSJoonas Lahtinen 	.stolen_base = gen3_stolen_base,
511ee0629cfSJoonas Lahtinen 	.stolen_size = chv_stolen_size,
512814c5f1fSJesse Barnes };
513814c5f1fSJesse Barnes 
514db0c8d8bSPaulo Zanoni static const struct intel_early_ops gen11_early_ops __initconst = {
515db0c8d8bSPaulo Zanoni 	.stolen_base = gen11_stolen_base,
516db0c8d8bSPaulo Zanoni 	.stolen_size = gen9_stolen_size,
517db0c8d8bSPaulo Zanoni };
518db0c8d8bSPaulo Zanoni 
5199c494ca4SLucas De Marchi /* Intel integrated GPUs for which we need to reserve "stolen memory" */
520ee0629cfSJoonas Lahtinen static const struct pci_device_id intel_early_ids[] __initconst = {
521ee0629cfSJoonas Lahtinen 	INTEL_I830_IDS(&i830_early_ops),
522ee0629cfSJoonas Lahtinen 	INTEL_I845G_IDS(&i845_early_ops),
523ee0629cfSJoonas Lahtinen 	INTEL_I85X_IDS(&i85x_early_ops),
524ee0629cfSJoonas Lahtinen 	INTEL_I865G_IDS(&i865_early_ops),
525ee0629cfSJoonas Lahtinen 	INTEL_I915G_IDS(&gen3_early_ops),
526ee0629cfSJoonas Lahtinen 	INTEL_I915GM_IDS(&gen3_early_ops),
527ee0629cfSJoonas Lahtinen 	INTEL_I945G_IDS(&gen3_early_ops),
528ee0629cfSJoonas Lahtinen 	INTEL_I945GM_IDS(&gen3_early_ops),
5298d9c20e1SCarlos Santa 	INTEL_VLV_IDS(&gen6_early_ops),
53086d35d4eSTvrtko Ursulin 	INTEL_PINEVIEW_G_IDS(&gen3_early_ops),
53186d35d4eSTvrtko Ursulin 	INTEL_PINEVIEW_M_IDS(&gen3_early_ops),
532ee0629cfSJoonas Lahtinen 	INTEL_I965G_IDS(&gen3_early_ops),
533ee0629cfSJoonas Lahtinen 	INTEL_G33_IDS(&gen3_early_ops),
534ee0629cfSJoonas Lahtinen 	INTEL_I965GM_IDS(&gen3_early_ops),
535ee0629cfSJoonas Lahtinen 	INTEL_GM45_IDS(&gen3_early_ops),
536ee0629cfSJoonas Lahtinen 	INTEL_G45_IDS(&gen3_early_ops),
537ee0629cfSJoonas Lahtinen 	INTEL_IRONLAKE_D_IDS(&gen3_early_ops),
538ee0629cfSJoonas Lahtinen 	INTEL_IRONLAKE_M_IDS(&gen3_early_ops),
539ee0629cfSJoonas Lahtinen 	INTEL_SNB_D_IDS(&gen6_early_ops),
540ee0629cfSJoonas Lahtinen 	INTEL_SNB_M_IDS(&gen6_early_ops),
541ee0629cfSJoonas Lahtinen 	INTEL_IVB_M_IDS(&gen6_early_ops),
542ee0629cfSJoonas Lahtinen 	INTEL_IVB_D_IDS(&gen6_early_ops),
5438d9c20e1SCarlos Santa 	INTEL_HSW_IDS(&gen6_early_ops),
5448d9c20e1SCarlos Santa 	INTEL_BDW_IDS(&gen8_early_ops),
545ee0629cfSJoonas Lahtinen 	INTEL_CHV_IDS(&chv_early_ops),
546ee0629cfSJoonas Lahtinen 	INTEL_SKL_IDS(&gen9_early_ops),
547ee0629cfSJoonas Lahtinen 	INTEL_BXT_IDS(&gen9_early_ops),
548ee0629cfSJoonas Lahtinen 	INTEL_KBL_IDS(&gen9_early_ops),
54933aa69edSLucas De Marchi 	INTEL_CFL_IDS(&gen9_early_ops),
550bc384c77SPaulo Zanoni 	INTEL_GLK_IDS(&gen9_early_ops),
5512e1e9d48SPaulo Zanoni 	INTEL_CNL_IDS(&gen9_early_ops),
552db0c8d8bSPaulo Zanoni 	INTEL_ICL_11_IDS(&gen11_early_ops),
553d53fef0bSRodrigo Vivi 	INTEL_EHL_IDS(&gen11_early_ops),
55431b77c70STejas Upadhyay 	INTEL_JSL_IDS(&gen11_early_ops),
5556b2436aeSMichel Thierry 	INTEL_TGL_12_IDS(&gen11_early_ops),
556efbee021SMatt Roper 	INTEL_RKL_IDS(&gen11_early_ops),
557c6bba9e5SCaz Yokoyama 	INTEL_ADLS_IDS(&gen11_early_ops),
558bdd27cadSClinton Taylor 	INTEL_ADLP_IDS(&gen11_early_ops),
5597e28d0b2STejas Upadhyay 	INTEL_ADLN_IDS(&gen11_early_ops),
56052407c22SAnusha Srivatsa 	INTEL_RPLS_IDS(&gen11_early_ops),
561*72c3c8d6SMatt Atwood 	INTEL_RPLP_IDS(&gen11_early_ops),
562ee0629cfSJoonas Lahtinen };
563ee0629cfSJoonas Lahtinen 
56455f56fc4SMatthew Auld struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
56555f56fc4SMatthew Auld EXPORT_SYMBOL(intel_graphics_stolen_res);
56655f56fc4SMatthew Auld 
567ee0629cfSJoonas Lahtinen static void __init
intel_graphics_stolen(int num,int slot,int func,const struct intel_early_ops * early_ops)568ee0629cfSJoonas Lahtinen intel_graphics_stolen(int num, int slot, int func,
569ee0629cfSJoonas Lahtinen 		      const struct intel_early_ops *early_ops)
570814c5f1fSJesse Barnes {
5716f9fa996SJoonas Lahtinen 	resource_size_t base, size;
5726f9fa996SJoonas Lahtinen 	resource_size_t end;
573ee0629cfSJoonas Lahtinen 
574ee0629cfSJoonas Lahtinen 	size = early_ops->stolen_size(num, slot, func);
575ee0629cfSJoonas Lahtinen 	base = early_ops->stolen_base(num, slot, func, size);
576ee0629cfSJoonas Lahtinen 
577ee0629cfSJoonas Lahtinen 	if (!size || !base)
578ee0629cfSJoonas Lahtinen 		return;
579ee0629cfSJoonas Lahtinen 
58001e5d3b4SChris Wilson 	end = base + size - 1;
58155f56fc4SMatthew Auld 
58255f56fc4SMatthew Auld 	intel_graphics_stolen_res.start = base;
58355f56fc4SMatthew Auld 	intel_graphics_stolen_res.end = end;
58455f56fc4SMatthew Auld 
58555f56fc4SMatthew Auld 	printk(KERN_INFO "Reserving Intel graphics memory at %pR\n",
58655f56fc4SMatthew Auld 	       &intel_graphics_stolen_res);
587ee0629cfSJoonas Lahtinen 
588ee0629cfSJoonas Lahtinen 	/* Mark this space as reserved */
58909821ff1SIngo Molnar 	e820__range_add(base, size, E820_TYPE_RESERVED);
590f9748fa0SIngo Molnar 	e820__update_table(e820_table);
591ee0629cfSJoonas Lahtinen }
592ee0629cfSJoonas Lahtinen 
intel_graphics_quirks(int num,int slot,int func)593ee0629cfSJoonas Lahtinen static void __init intel_graphics_quirks(int num, int slot, int func)
594ee0629cfSJoonas Lahtinen {
595ee0629cfSJoonas Lahtinen 	const struct intel_early_ops *early_ops;
596ee0629cfSJoonas Lahtinen 	u16 device;
597814c5f1fSJesse Barnes 	int i;
598814c5f1fSJesse Barnes 
5999c494ca4SLucas De Marchi 	/*
6009c494ca4SLucas De Marchi 	 * Reserve "stolen memory" for an integrated GPU.  If we've already
6019c494ca4SLucas De Marchi 	 * found one, there's nothing to do for other (discrete) GPUs.
6029c494ca4SLucas De Marchi 	 */
6039c494ca4SLucas De Marchi 	if (resource_size(&intel_graphics_stolen_res))
6049c494ca4SLucas De Marchi 		return;
6059c494ca4SLucas De Marchi 
606814c5f1fSJesse Barnes 	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
607814c5f1fSJesse Barnes 
608ee0629cfSJoonas Lahtinen 	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
609ee0629cfSJoonas Lahtinen 		kernel_ulong_t driver_data = intel_early_ids[i].driver_data;
610ee0629cfSJoonas Lahtinen 
611ee0629cfSJoonas Lahtinen 		if (intel_early_ids[i].device != device)
612ee0629cfSJoonas Lahtinen 			continue;
613ee0629cfSJoonas Lahtinen 
614ee0629cfSJoonas Lahtinen 		early_ops = (typeof(early_ops))driver_data;
615ee0629cfSJoonas Lahtinen 
616ee0629cfSJoonas Lahtinen 		intel_graphics_stolen(num, slot, func, early_ops);
617ee0629cfSJoonas Lahtinen 
618814c5f1fSJesse Barnes 		return;
619814c5f1fSJesse Barnes 	}
620814c5f1fSJesse Barnes }
621814c5f1fSJesse Barnes 
force_disable_hpet(int num,int slot,int func)62262187910SFeng Tang static void __init force_disable_hpet(int num, int slot, int func)
62362187910SFeng Tang {
62462187910SFeng Tang #ifdef CONFIG_HPET_TIMER
6253d45ac4bSJan Beulich 	boot_hpet_disable = true;
62662187910SFeng Tang 	pr_info("x86/hpet: Will disable the HPET for this platform because it's not reliable\n");
62762187910SFeng Tang #endif
62862187910SFeng Tang }
62962187910SFeng Tang 
630abb2bafdSLukas Wunner #define BCM4331_MMIO_SIZE	16384
631abb2bafdSLukas Wunner #define BCM4331_PM_CAP		0x40
632abb2bafdSLukas Wunner #define bcma_aread32(reg)	ioread32(mmio + 1 * BCMA_CORE_SIZE + reg)
633abb2bafdSLukas Wunner #define bcma_awrite32(reg, val)	iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg)
634abb2bafdSLukas Wunner 
apple_airport_reset(int bus,int slot,int func)635abb2bafdSLukas Wunner static void __init apple_airport_reset(int bus, int slot, int func)
636abb2bafdSLukas Wunner {
637abb2bafdSLukas Wunner 	void __iomem *mmio;
638abb2bafdSLukas Wunner 	u16 pmcsr;
639abb2bafdSLukas Wunner 	u64 addr;
640abb2bafdSLukas Wunner 	int i;
641abb2bafdSLukas Wunner 
642630b3affSLukas Wunner 	if (!x86_apple_machine)
643abb2bafdSLukas Wunner 		return;
644abb2bafdSLukas Wunner 
645abb2bafdSLukas Wunner 	/* Card may have been put into PCI_D3hot by grub quirk */
646abb2bafdSLukas Wunner 	pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
647abb2bafdSLukas Wunner 
648abb2bafdSLukas Wunner 	if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
649abb2bafdSLukas Wunner 		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
650abb2bafdSLukas Wunner 		write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr);
651abb2bafdSLukas Wunner 		mdelay(10);
652abb2bafdSLukas Wunner 
653abb2bafdSLukas Wunner 		pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
654abb2bafdSLukas Wunner 		if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
655a7a3153aSJoe Perches 			pr_err("pci 0000:%02x:%02x.%d: Cannot power up Apple AirPort card\n",
656a7a3153aSJoe Perches 			       bus, slot, func);
657abb2bafdSLukas Wunner 			return;
658abb2bafdSLukas Wunner 		}
659abb2bafdSLukas Wunner 	}
660abb2bafdSLukas Wunner 
661abb2bafdSLukas Wunner 	addr  =      read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
662abb2bafdSLukas Wunner 	addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32;
663abb2bafdSLukas Wunner 	addr &= PCI_BASE_ADDRESS_MEM_MASK;
664abb2bafdSLukas Wunner 
665abb2bafdSLukas Wunner 	mmio = early_ioremap(addr, BCM4331_MMIO_SIZE);
666abb2bafdSLukas Wunner 	if (!mmio) {
667a7a3153aSJoe Perches 		pr_err("pci 0000:%02x:%02x.%d: Cannot iomap Apple AirPort card\n",
668a7a3153aSJoe Perches 		       bus, slot, func);
669abb2bafdSLukas Wunner 		return;
670abb2bafdSLukas Wunner 	}
671abb2bafdSLukas Wunner 
672abb2bafdSLukas Wunner 	pr_info("Resetting Apple AirPort card (left enabled by EFI)\n");
673abb2bafdSLukas Wunner 
674abb2bafdSLukas Wunner 	for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++)
675abb2bafdSLukas Wunner 		udelay(10);
676abb2bafdSLukas Wunner 
677abb2bafdSLukas Wunner 	bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
678abb2bafdSLukas Wunner 	bcma_aread32(BCMA_RESET_CTL);
679abb2bafdSLukas Wunner 	udelay(1);
680abb2bafdSLukas Wunner 
681abb2bafdSLukas Wunner 	bcma_awrite32(BCMA_RESET_CTL, 0);
682abb2bafdSLukas Wunner 	bcma_aread32(BCMA_RESET_CTL);
683abb2bafdSLukas Wunner 	udelay(10);
684abb2bafdSLukas Wunner 
685abb2bafdSLukas Wunner 	early_iounmap(mmio, BCM4331_MMIO_SIZE);
686abb2bafdSLukas Wunner }
68762187910SFeng Tang 
688c6b48324SNeil Horman #define QFLAG_APPLY_ONCE 	0x1
689c6b48324SNeil Horman #define QFLAG_APPLIED		0x2
690c6b48324SNeil Horman #define QFLAG_DONE		(QFLAG_APPLY_ONCE|QFLAG_APPLIED)
69154ef3400SAndi Kleen struct chipset {
692c6b48324SNeil Horman 	u32 vendor;
693c6b48324SNeil Horman 	u32 device;
694c6b48324SNeil Horman 	u32 class;
695c6b48324SNeil Horman 	u32 class_mask;
696c6b48324SNeil Horman 	u32 flags;
697c6b48324SNeil Horman 	void (*f)(int num, int slot, int func);
69854ef3400SAndi Kleen };
69954ef3400SAndi Kleen 
70054ef3400SAndi Kleen static struct chipset early_qrk[] __initdata = {
701c6b48324SNeil Horman 	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
702c6b48324SNeil Horman 	  PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
703c6b48324SNeil Horman 	{ PCI_VENDOR_ID_VIA, PCI_ANY_ID,
704c6b48324SNeil Horman 	  PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
705c6b48324SNeil Horman 	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
706c6b48324SNeil Horman 	  PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
70733fb0e4eSAndreas Herrmann 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
70833fb0e4eSAndreas Herrmann 	  PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
70926adcfbfSAndreas Herrmann 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
71026adcfbfSAndreas Herrmann 	  PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
71103bbcb2eSNeil Horman 	{ PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST,
71203bbcb2eSNeil Horman 	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
713803075dbSNeil Horman 	{ PCI_VENDOR_ID_INTEL, 0x3405, PCI_CLASS_BRIDGE_HOST,
714803075dbSNeil Horman 	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
71503bbcb2eSNeil Horman 	{ PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
71603bbcb2eSNeil Horman 	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
717814c5f1fSJesse Barnes 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
7189c494ca4SLucas De Marchi 	  0, intel_graphics_quirks },
71962187910SFeng Tang 	/*
720b58d9307SFeng Tang 	 * HPET on the current version of the Baytrail platform has accuracy
721b58d9307SFeng Tang 	 * problems: it will halt in deep idle state - so we disable it.
722b58d9307SFeng Tang 	 *
723b58d9307SFeng Tang 	 * More details can be found in section 18.10.1.3 of the datasheet:
724b58d9307SFeng Tang 	 *
725b58d9307SFeng Tang 	 *    http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/atom-z8000-datasheet-vol-1.pdf
72662187910SFeng Tang 	 */
72762187910SFeng Tang 	{ PCI_VENDOR_ID_INTEL, 0x0f00,
72862187910SFeng Tang 		PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
729abb2bafdSLukas Wunner 	{ PCI_VENDOR_ID_BROADCOM, 0x4331,
730abb2bafdSLukas Wunner 	  PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset},
73154ef3400SAndi Kleen 	{}
73254ef3400SAndi Kleen };
73354ef3400SAndi Kleen 
734850c3210SLukas Wunner static void __init early_pci_scan_bus(int bus);
735850c3210SLukas Wunner 
73615650a2fSJesse Barnes /**
73715650a2fSJesse Barnes  * check_dev_quirk - apply early quirks to a given PCI device
73815650a2fSJesse Barnes  * @num: bus number
73915650a2fSJesse Barnes  * @slot: slot number
74015650a2fSJesse Barnes  * @func: PCI function
74115650a2fSJesse Barnes  *
74215650a2fSJesse Barnes  * Check the vendor & device ID against the early quirks table.
74315650a2fSJesse Barnes  *
744850c3210SLukas Wunner  * If the device is single function, let early_pci_scan_bus() know so we don't
74515650a2fSJesse Barnes  * poke at this device again.
74615650a2fSJesse Barnes  */
check_dev_quirk(int num,int slot,int func)74715650a2fSJesse Barnes static int __init check_dev_quirk(int num, int slot, int func)
74854ef3400SAndi Kleen {
749c6b48324SNeil Horman 	u16 class;
750c6b48324SNeil Horman 	u16 vendor;
751c6b48324SNeil Horman 	u16 device;
75254ef3400SAndi Kleen 	u8 type;
753850c3210SLukas Wunner 	u8 sec;
75454ef3400SAndi Kleen 	int i;
755c6b48324SNeil Horman 
7567bcbc78dSNeil Horman 	class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE);
7577bcbc78dSNeil Horman 
758c6b48324SNeil Horman 	if (class == 0xffff)
75915650a2fSJesse Barnes 		return -1; /* no class, treat as single function */
76054ef3400SAndi Kleen 
7617bcbc78dSNeil Horman 	vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID);
76254ef3400SAndi Kleen 
7637bcbc78dSNeil Horman 	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
764c6b48324SNeil Horman 
765c6b48324SNeil Horman 	for (i = 0; early_qrk[i].f != NULL; i++) {
766c6b48324SNeil Horman 		if (((early_qrk[i].vendor == PCI_ANY_ID) ||
767c6b48324SNeil Horman 			(early_qrk[i].vendor == vendor)) &&
768c6b48324SNeil Horman 			((early_qrk[i].device == PCI_ANY_ID) ||
769c6b48324SNeil Horman 			(early_qrk[i].device == device)) &&
770c6b48324SNeil Horman 			(!((early_qrk[i].class ^ class) &
771c6b48324SNeil Horman 			    early_qrk[i].class_mask))) {
7727bcbc78dSNeil Horman 				if ((early_qrk[i].flags &
7737bcbc78dSNeil Horman 				     QFLAG_DONE) != QFLAG_DONE)
774c6b48324SNeil Horman 					early_qrk[i].f(num, slot, func);
775c6b48324SNeil Horman 				early_qrk[i].flags |= QFLAG_APPLIED;
776c6b48324SNeil Horman 			}
77754ef3400SAndi Kleen 	}
77854ef3400SAndi Kleen 
77954ef3400SAndi Kleen 	type = read_pci_config_byte(num, slot, func,
78054ef3400SAndi Kleen 				    PCI_HEADER_TYPE);
781850c3210SLukas Wunner 
782850c3210SLukas Wunner 	if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
783850c3210SLukas Wunner 		sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS);
784850c3210SLukas Wunner 		if (sec > num)
785850c3210SLukas Wunner 			early_pci_scan_bus(sec);
786850c3210SLukas Wunner 	}
787850c3210SLukas Wunner 
78854ef3400SAndi Kleen 	if (!(type & 0x80))
78915650a2fSJesse Barnes 		return -1;
79015650a2fSJesse Barnes 
79115650a2fSJesse Barnes 	return 0;
79254ef3400SAndi Kleen }
7937bcbc78dSNeil Horman 
early_pci_scan_bus(int bus)794850c3210SLukas Wunner static void __init early_pci_scan_bus(int bus)
7957bcbc78dSNeil Horman {
7968659c406SAndi Kleen 	int slot, func;
7977bcbc78dSNeil Horman 
7987bcbc78dSNeil Horman 	/* Poor man's PCI discovery */
7997bcbc78dSNeil Horman 	for (slot = 0; slot < 32; slot++)
80015650a2fSJesse Barnes 		for (func = 0; func < 8; func++) {
80115650a2fSJesse Barnes 			/* Only probe function 0 on single fn devices */
802850c3210SLukas Wunner 			if (check_dev_quirk(bus, slot, func))
80315650a2fSJesse Barnes 				break;
80415650a2fSJesse Barnes 		}
80554ef3400SAndi Kleen }
806850c3210SLukas Wunner 
early_quirks(void)807850c3210SLukas Wunner void __init early_quirks(void)
808850c3210SLukas Wunner {
809850c3210SLukas Wunner 	if (!early_pci_allowed())
810850c3210SLukas Wunner 		return;
811850c3210SLukas Wunner 
812850c3210SLukas Wunner 	early_pci_scan_bus(0);
813850c3210SLukas Wunner }
814