1/* 2 * Atheros AP94 reference board PCI initialization 3 * 4 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation. 9 */ 10 11#include <linux/pci.h> 12#include <linux/delay.h> 13 14#include <asm/mach-ath79/ar71xx_regs.h> 15#include <asm/mach-ath79/ath79.h> 16 17struct ath9k_fixup { 18 u16 *cal_data; 19 unsigned slot; 20}; 21 22static int ath9k_num_fixups; 23static struct ath9k_fixup ath9k_fixups[2]; 24 25static void ath9k_pci_fixup(struct pci_dev *dev) 26{ 27 void __iomem *mem; 28 u16 *cal_data = NULL; 29 u16 cmd; 30 u32 bar0; 31 u32 val; 32 unsigned i; 33 34 for (i = 0; i < ath9k_num_fixups; i++) { 35 if (ath9k_fixups[i].cal_data == NULL) 36 continue; 37 38 if (ath9k_fixups[i].slot != PCI_SLOT(dev->devfn)) 39 continue; 40 41 cal_data = ath9k_fixups[i].cal_data; 42 break; 43 } 44 45 if (cal_data == NULL) 46 return; 47 48 if (*cal_data != 0xa55a) { 49 pr_err("pci %s: invalid calibration data\n", pci_name(dev)); 50 return; 51 } 52 53 pr_info("pci %s: fixup device configuration\n", pci_name(dev)); 54 55 mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); 56 if (!mem) { 57 pr_err("pci %s: ioremap error\n", pci_name(dev)); 58 return; 59 } 60 61 pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0); 62 63 switch (ath79_soc) { 64 case ATH79_SOC_AR7161: 65 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 66 AR71XX_PCI_MEM_BASE); 67 break; 68 case ATH79_SOC_AR7240: 69 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff); 70 break; 71 72 case ATH79_SOC_AR7241: 73 case ATH79_SOC_AR7242: 74 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff); 75 break; 76 77 default: 78 BUG(); 79 } 80 81 pci_read_config_word(dev, PCI_COMMAND, &cmd); 82 cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; 83 pci_write_config_word(dev, PCI_COMMAND, cmd); 84 85 /* set pointer to first reg address */ 86 cal_data += 3; 87 while (*cal_data != 0xffff) { 88 u32 reg; 89 reg = *cal_data++; 90 val = *cal_data++; 91 val |= (*cal_data++) << 16; 92 93 __raw_writel(val, mem + reg); 94 udelay(100); 95 } 96 97 pci_read_config_dword(dev, PCI_VENDOR_ID, &val); 98 dev->vendor = val & 0xffff; 99 dev->device = (val >> 16) & 0xffff; 100 101 pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); 102 dev->revision = val & 0xff; 103 dev->class = val >> 8; /* upper 3 bytes */ 104 105 pci_read_config_word(dev, PCI_COMMAND, &cmd); 106 cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); 107 pci_write_config_word(dev, PCI_COMMAND, cmd); 108 109 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); 110 111 iounmap(mem); 112} 113DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath9k_pci_fixup); 114 115void __init pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) 116{ 117 if (ath9k_num_fixups >= ARRAY_SIZE(ath9k_fixups)) 118 return; 119 120 ath9k_fixups[ath9k_num_fixups].slot = slot; 121 ath9k_fixups[ath9k_num_fixups].cal_data = cal_data; 122 ath9k_num_fixups++; 123} 124