ar71xx/mac80211: add a workaround for the bad signal strength on the WNDR3700
[openwrt/svn-archive/archive.git] / target / linux / ar71xx / files / arch / mips / ar71xx / dev-ap94-pci.c
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/ath9k_platform.h>
13 #include <linux/delay.h>
14
15 #include <asm/mach-ar71xx/ar71xx.h>
16 #include <asm/mach-ar71xx/pci.h>
17
18 #include "dev-ap94-pci.h"
19
20 static struct ath9k_platform_data ap94_wmac0_data;
21 static struct ath9k_platform_data ap94_wmac1_data;
22 static char ap94_wmac0_mac[6];
23 static char ap94_wmac1_mac[6];
24 static int ap94_pci_fixup_enabled;
25
26 static struct ar71xx_pci_irq ap94_pci_irqs[] __initdata = {
27 {
28 .slot = 0,
29 .pin = 1,
30 .irq = AR71XX_PCI_IRQ_DEV0,
31 }, {
32 .slot = 1,
33 .pin = 1,
34 .irq = AR71XX_PCI_IRQ_DEV1,
35 }
36 };
37
38 static int ap94_pci_plat_dev_init(struct pci_dev *dev)
39 {
40 switch(PCI_SLOT(dev->devfn)) {
41 case 17:
42 dev->dev.platform_data = &ap94_wmac0_data;
43 break;
44
45 case 18:
46 dev->dev.platform_data = &ap94_wmac1_data;
47 break;
48 }
49
50 return 0;
51 }
52
53 static void ap94_pci_fixup(struct pci_dev *dev)
54 {
55 void __iomem *mem;
56 u16 *cal_data;
57 u16 cmd;
58 u32 bar0;
59 u32 val;
60
61 if (!ap94_pci_fixup_enabled)
62 return;
63
64 switch (PCI_SLOT(dev->devfn)) {
65 case 17:
66 cal_data = ap94_wmac0_data.eeprom_data;
67 break;
68 case 18:
69 cal_data = ap94_wmac1_data.eeprom_data;
70 break;
71 default:
72 return;
73 }
74
75 if (*cal_data != 0xa55a) {
76 printk(KERN_ERR "PCI: no calibration data found for %s\n",
77 pci_name(dev));
78 return;
79 }
80
81 mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
82 if (!mem) {
83 printk(KERN_ERR "PCI: ioremap error for device %s\n",
84 pci_name(dev));
85 return;
86 }
87
88 printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
89
90 pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
91
92 /* Setup the PCI device to allow access to the internal registers */
93 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE);
94 pci_read_config_word(dev, PCI_COMMAND, &cmd);
95 cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
96 pci_write_config_word(dev, PCI_COMMAND, cmd);
97
98 /* set pointer to first reg address */
99 cal_data += 3;
100 while (*cal_data != 0xffff) {
101 u32 reg;
102 reg = *cal_data++;
103 val = *cal_data++;
104 val |= (*cal_data++) << 16;
105
106 __raw_writel(val, mem + reg);
107 udelay(100);
108 }
109
110 pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
111 dev->vendor = val & 0xffff;
112 dev->device = (val >> 16) & 0xffff;
113
114 pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
115 dev->revision = val & 0xff;
116 dev->class = val >> 8; /* upper 3 bytes */
117
118 pci_read_config_word(dev, PCI_COMMAND, &cmd);
119 cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
120 pci_write_config_word(dev, PCI_COMMAND, cmd);
121
122 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
123
124 iounmap(mem);
125 }
126 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap94_pci_fixup);
127
128 void __init ap94_pci_enable_quirk_wndr3700(void)
129 {
130 ap94_wmac0_data.quirk_wndr3700 = 1;
131 ap94_wmac1_data.quirk_wndr3700 = 1;
132 }
133
134 void __init ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
135 u8 *cal_data1, u8 *mac_addr1)
136 {
137 if (cal_data0)
138 memcpy(ap94_wmac0_data.eeprom_data, cal_data0,
139 sizeof(ap94_wmac0_data.eeprom_data));
140
141 if (cal_data1)
142 memcpy(ap94_wmac1_data.eeprom_data, cal_data1,
143 sizeof(ap94_wmac1_data.eeprom_data));
144
145 if (mac_addr0) {
146 memcpy(ap94_wmac0_mac, mac_addr0, sizeof(ap94_wmac0_mac));
147 ap94_wmac0_data.macaddr = ap94_wmac0_mac;
148 }
149
150 if (mac_addr1) {
151 memcpy(ap94_wmac1_mac, mac_addr1, sizeof(ap94_wmac1_mac));
152 ap94_wmac1_data.macaddr = ap94_wmac1_mac;
153 }
154
155 ar71xx_pci_plat_dev_init = ap94_pci_plat_dev_init;
156 ar71xx_pci_init(ARRAY_SIZE(ap94_pci_irqs), ap94_pci_irqs);
157
158 ap94_pci_fixup_enabled = 1;
159 }