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); |
