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