diff options
-rw-r--r-- | arch/mips/pci/pci-ar724x.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index bb4f2162d4e4..07b7e3071735 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <asm/mach-ath79/ath79.h> | ||
12 | #include <asm/mach-ath79/pci.h> | 13 | #include <asm/mach-ath79/pci.h> |
13 | 14 | ||
14 | #define AR724X_PCI_CFG_BASE 0x14000000 | 15 | #define AR724X_PCI_CFG_BASE 0x14000000 |
@@ -16,9 +17,14 @@ | |||
16 | #define AR724X_PCI_MEM_BASE 0x10000000 | 17 | #define AR724X_PCI_MEM_BASE 0x10000000 |
17 | #define AR724X_PCI_MEM_SIZE 0x08000000 | 18 | #define AR724X_PCI_MEM_SIZE 0x08000000 |
18 | 19 | ||
20 | #define AR7240_BAR0_WAR_VALUE 0xffff | ||
21 | |||
19 | static DEFINE_SPINLOCK(ar724x_pci_lock); | 22 | static DEFINE_SPINLOCK(ar724x_pci_lock); |
20 | static void __iomem *ar724x_pci_devcfg_base; | 23 | static void __iomem *ar724x_pci_devcfg_base; |
21 | 24 | ||
25 | static u32 ar724x_pci_bar0_value; | ||
26 | static bool ar724x_pci_bar0_is_cached; | ||
27 | |||
22 | static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, | 28 | static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, |
23 | int size, uint32_t *value) | 29 | int size, uint32_t *value) |
24 | { | 30 | { |
@@ -56,7 +62,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |||
56 | } | 62 | } |
57 | 63 | ||
58 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); | 64 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); |
59 | *value = data; | 65 | |
66 | if (where == PCI_BASE_ADDRESS_0 && size == 4 && | ||
67 | ar724x_pci_bar0_is_cached) { | ||
68 | /* use the cached value */ | ||
69 | *value = ar724x_pci_bar0_value; | ||
70 | } else { | ||
71 | *value = data; | ||
72 | } | ||
60 | 73 | ||
61 | return PCIBIOS_SUCCESSFUL; | 74 | return PCIBIOS_SUCCESSFUL; |
62 | } | 75 | } |
@@ -72,6 +85,27 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |||
72 | if (devfn) | 85 | if (devfn) |
73 | return PCIBIOS_DEVICE_NOT_FOUND; | 86 | return PCIBIOS_DEVICE_NOT_FOUND; |
74 | 87 | ||
88 | if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) { | ||
89 | if (value != 0xffffffff) { | ||
90 | /* | ||
91 | * WAR for a hw issue. If the BAR0 register of the | ||
92 | * device is set to the proper base address, the | ||
93 | * memory space of the device is not accessible. | ||
94 | * | ||
95 | * Cache the intended value so it can be read back, | ||
96 | * and write a SoC specific constant value to the | ||
97 | * BAR0 register in order to make the device memory | ||
98 | * accessible. | ||
99 | */ | ||
100 | ar724x_pci_bar0_is_cached = true; | ||
101 | ar724x_pci_bar0_value = value; | ||
102 | |||
103 | value = AR7240_BAR0_WAR_VALUE; | ||
104 | } else { | ||
105 | ar724x_pci_bar0_is_cached = false; | ||
106 | } | ||
107 | } | ||
108 | |||
75 | base = ar724x_pci_devcfg_base; | 109 | base = ar724x_pci_devcfg_base; |
76 | 110 | ||
77 | spin_lock_irqsave(&ar724x_pci_lock, flags); | 111 | spin_lock_irqsave(&ar724x_pci_lock, flags); |