source: src/linux/pb42/linux-2.6.34.6/arch/mips/pci/pci-ar7100.c @ 17398

Last change on this file since 17398 was 17398, checked in by BrainSlayer, 22 months ago

to make some devices work correct with ath9k, we need some workarounds here

File size: 9.4 KB
Line 
1#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/types.h>
4#include <linux/irq.h>
5#include <linux/interrupt.h>
6#include <linux/pci.h>
7#include <linux/cpumask.h>
8#include <linux/delay.h>
9#include <linux/ath9k_platform.h>
10
11#include <asm/delay.h>
12
13#define ag7100_delay1s()    mdelay(1000);
14
15#include "ar7100.h"
16
17
18static int ar71xx_pci_fixup_enable;
19
20/*
21 * Support for Ar7100 pci interrupt and core pci initialization
22 */
23/*
24 * PCI interrupts.
25 * roughly the interrupts flow is:
26 *
27 * - save flags
28 * - CLI (disable all)
29 * - IC->ack (mask out the source)
30 * - EI (enable all, except the source that was masked of course)
31 * - action (ISR)
32 * - IC->enable (unmask the source)
33 *
34 * The reason we have a separate PCI IC is beacause of the following:
35 * If we dont, then Throughout the "action" of a PCI slot, the
36 * entire PCI "IP" on the cpu will remain disabled. Which means that we cant
37 * prioritize between PCI interrupts. Normally this should be ok, if all PCI
38 * interrupts are considered equal. However, creating a PCI IC gives
39 * the flexibility to prioritize.
40 */
41
42static void
43ar7100_pci_irq_enable(unsigned int irq)
44{
45    ar7100_reg_rmw_set(AR7100_PCI_INT_MASK,
46                       (1 << (irq - AR7100_PCI_IRQ_BASE)));
47}
48
49static void
50ar7100_pci_irq_disable(unsigned int irq)
51{
52    ar7100_reg_rmw_clear(AR7100_PCI_INT_MASK,
53                       (1 << (irq - AR7100_PCI_IRQ_BASE)));
54}
55
56static unsigned int
57ar7100_pci_irq_startup(unsigned int irq)
58{
59        ar7100_pci_irq_enable(irq);
60        return 0;
61}
62
63static void
64ar7100_pci_irq_shutdown(unsigned int irq)
65{
66        ar7100_pci_irq_disable(irq);
67}
68
69static void
70ar7100_pci_irq_ack(unsigned int irq)
71{
72        ar7100_pci_irq_disable(irq);
73}
74
75static void
76ar7100_pci_irq_end(unsigned int irq)
77{
78        if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
79                ar7100_pci_irq_enable(irq);
80}
81
82static int
83ar7100_pci_irq_set_affinity(unsigned int irq, const struct cpumask *mask)
84{
85        /*
86     * Only 1 CPU; ignore affinity request
87     */
88     return 0;
89}
90
91static struct irq_chip ar7100_pci_irq_chip = {
92        .name           = "AR7100 PCI ",
93        .mask           = ar7100_pci_irq_disable,
94        .unmask         = ar7100_pci_irq_enable,
95        .mask_ack       = ar7100_pci_irq_disable,
96};
97
98
99void
100ar7100_pci_irq_init(int irq_base)
101{
102        int i;
103
104        for (i = irq_base; i < irq_base + AR7100_PCI_IRQ_COUNT; i++) {
105                irq_desc[i].status = IRQ_DISABLED;
106                set_irq_chip_and_handler(i, &ar7100_pci_irq_chip,
107                                         handle_level_irq);
108        }
109}
110
111/*
112 * init the pci controller
113 */
114
115static struct resource ar7100_io_resource = {
116        .name           = "PCI IO space",
117        .start          = 0x0000,
118        .end            = 0,
119        .flags          = IORESOURCE_IO,
120};
121
122static struct resource ar7100_mem_resource = {
123        .name           = "PCI memory space",
124        .start          = AR7100_PCI_MEM_BASE,
125        .end            = AR7100_PCI_MEM_BASE + AR7100_PCI_WINDOW - 1,
126        .flags          = IORESOURCE_MEM
127};
128
129extern struct pci_ops ar7100_pci_ops;
130
131static struct pci_controller ar7100_pci_controller = {
132        .pci_ops            = &ar7100_pci_ops,
133        .mem_resource   = &ar7100_mem_resource,
134        .io_resource    = &ar7100_io_resource,
135};
136
137
138irqreturn_t
139ar7100_pci_core_intr(int cpl, void *dev_id)
140{
141        printk("PCI error intr\n");
142        ar7100_check_error(1);
143
144        return IRQ_HANDLED;
145}
146
147/*
148 * We want a 1:1 mapping between PCI and DDR for inbound and outbound.
149 * The PCI<---AHB decoding works as follows:
150 *
151 * 8 registers in the DDR unit provide software configurable 32 bit offsets
152 * for each of the eight 16MB PCI windows in the 128MB. The offsets will be
153 * added to any address in the 16MB segment before being sent to the PCI unit.
154 *
155 * Essentially  for any AHB address generated by the CPU,
156 * 1. the MSB  four bits are stripped off, [31:28],
157 * 2. Bit 27 is used to decide between the lower 128Mb (PCI) or the rest of
158 *    the AHB space
159 * 3. Bits 26:24 are used to access one of the 8 window registers and are
160 *    masked off.
161 * 4. If it is a PCI address, then the WINDOW offset in the WINDOW register
162 *    corresponding to the next 3 bits (bit 26:24) is ADDED to the address,
163 *    to generate the address to PCI unit.
164 *
165 *     eg. CPU address = 0x100000ff
166 *         window 0 offset = 0x10000000
167 *         This points to lowermost 16MB window in PCI space.
168 *         So the resulting address would be 0x000000ff+0x10000000
169 *         = 0x100000ff
170 *
171 *         eg2. CPU address = 0x120000ff
172 *         WINDOW 2 offset = 0x12000000
173 *         resulting address would be 0x000000ff+0x12000000
174 *                         = 0x120000ff
175 *
176 * There is no translation for inbound access (PCI device as a master)
177 */
178static void ar71xx_pci_fixup(struct pci_dev *dev)
179{
180        u32 t;
181
182        if (!ar71xx_pci_fixup_enable)
183                return;
184               
185
186        if (dev->bus->number != 0 || dev->devfn != 0)
187                return;
188
189
190        /* setup COMMAND register */
191        t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
192          | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
193
194        pci_write_config_word(dev, PCI_COMMAND, t);
195}
196DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup);
197
198#ifdef CONFIG_DIR825
199#define STARTSCAN 0x1f660000
200#define DIR825B1_MAC_LOCATION_0                 0x2ffa81b8
201#define DIR825B1_MAC_LOCATION_1                 0x2ffa8370
202static u8 mac0[6];
203static u8 mac1[6];
204#else 
205#define STARTSCAN 0x1f000000
206#endif 
207
208#ifdef CONFIG_WNDR3700
209#define WNDR3700_MAC_LOCATION_0                 0x1fff0000
210#define WNDR3700_MAC_LOCATION_1                 0x1fff000c
211#endif
212static void *getCalData(int slot)
213{
214u8 *base;
215for (base=(u8 *) KSEG1ADDR(STARTSCAN);base<KSEG1ADDR (0x1fff0000);base+=0x1000) {
216    u32 *cal = (u32 *)base;
217    if (*cal==0xa55a0000 || *cal==0x5aa50000) { //protection bit is always zero on inflash devices, so we can use for match it
218        if (slot) {
219            base+=0x4000;
220            }
221        printk(KERN_INFO "found calibration data for slot %d on 0x%08X\n",slot,base);
222        return base;
223        }
224    }
225return NULL;
226}
227static struct ath9k_platform_data wmac_data[2];
228
229
230static void ath_pci_fixup(struct pci_dev *dev)
231{
232        void __iomem *mem;
233        u16 *cal_data = NULL;
234        u16 cmd;
235        u32 bar0;
236        u32 val;
237
238        if (!ar71xx_pci_fixup_enable)
239                return;
240
241        switch (PCI_SLOT(dev->devfn)) {
242        case 0:
243                cal_data = (u16 *)getCalData(0);
244                if (cal_data) {
245                memcpy(wmac_data[0].eeprom_data,cal_data,sizeof(wmac_data[0].eeprom_data));
246                #ifdef CONFIG_DIR825
247                memcpy(mac0,KSEG1ADDR(DIR825B1_MAC_LOCATION_0),6);
248                wmac_data[0].macaddr = mac0;
249                #endif
250                #ifdef CONFIG_WNDR3700
251                memcpy(mac0,KSEG1ADDR(WNDR3700_MAC_LOCATION_0),6);
252                wmac_data[0].macaddr = mac0;
253                /* 2.4 GHz uses the first fixed antenna group (1, 0, 1, 0) */
254                wmac_data[0].gpio_mask = (0xf << 6);
255                wmac_data[0].gpio_val = (0xa << 6);
256                #endif
257                dev->dev.platform_data = &wmac_data[0];
258                }
259                break;
260        case 1:
261                cal_data = (u16 *)getCalData(1);
262                if (cal_data) {
263                memcpy(wmac_data[1].eeprom_data,cal_data,sizeof(wmac_data[1].eeprom_data));
264                #ifdef CONFIG_DIR825
265                memcpy(mac1,KSEG1ADDR(DIR825B1_MAC_LOCATION_1),6);
266                wmac_data[1].macaddr = mac1;
267                #endif
268                #ifdef CONFIG_WNDR3700
269                memcpy(mac1,KSEG1ADDR(WNDR3700_MAC_LOCATION_1),6);
270                wmac_data[1].macaddr = mac1;
271                /* 5 GHz uses the second fixed antenna group (0, 1, 1, 0) */
272                wmac_data[1].gpio_mask = (0xf << 6);
273                wmac_data[1].gpio_val = (0x6 << 6);
274                #endif
275                dev->dev.platform_data = &wmac_data[1];
276                }
277                break;
278        default:
279                return;
280        }
281        if (!cal_data) {
282                printk(KERN_INFO "no in flash calibration fata found, no fix required\n");
283                return;
284        }
285       
286        mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
287        if (!mem) {
288                printk(KERN_ERR "PCI: ioremap error for device %s\n",
289                       pci_name(dev));
290                return;
291        }
292
293        printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
294
295        pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
296
297        /* Setup the PCI device to allow access to the internal registers */
298        pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE);
299        pci_read_config_word(dev, PCI_COMMAND, &cmd);
300        cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
301        pci_write_config_word(dev, PCI_COMMAND, cmd);
302
303        /* set pointer to first reg address */
304        cal_data += 3;
305        while (*cal_data != 0xffff) {
306                u32 reg;
307                reg = *cal_data++;
308                val = *cal_data++;
309                val |= (*cal_data++) << 16;
310
311                __raw_writel(val, mem + reg);
312                udelay(100);
313        }
314
315        pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
316        dev->vendor = val & 0xffff;
317        dev->device = (val >> 16) & 0xffff;
318
319        pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
320        dev->revision = val & 0xff;
321        dev->class = val >> 8; /* upper 3 bytes */
322
323        pci_read_config_word(dev, PCI_COMMAND, &cmd);
324        cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
325        pci_write_config_word(dev, PCI_COMMAND, cmd);
326
327        pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
328
329        iounmap(mem);
330        return;
331}
332DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath_pci_fixup);
333 
334static int __init ar7100_pcibios_init(void)
335{
336        uint32_t cmd;
337
338        ar7100_reg_rmw_set(AR7100_RESET,
339                        (AR7100_RESET_PCI_BUS|AR7100_RESET_PCI_CORE));
340        ag7100_delay1s();
341
342        ar7100_reg_rmw_clear(AR7100_RESET,
343                        (AR7100_RESET_PCI_BUS|AR7100_RESET_PCI_CORE));
344        ag7100_delay1s();
345
346        ar7100_write_pci_window(0);
347        ar7100_write_pci_window(1);
348        ar7100_write_pci_window(2);
349        ar7100_write_pci_window(3);
350        ar7100_write_pci_window(4);
351        ar7100_write_pci_window(5);
352        ar7100_write_pci_window(6);
353        ar7100_write_pci_window(7);
354
355        ag7100_delay1s();
356
357
358        cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE |
359                PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK;
360
361        ar7100_local_write_config(PCI_COMMAND, 4, cmd);
362
363        /*
364         * clear any lingering errors and register core error IRQ
365         */
366        ar7100_check_error(0);
367
368        ar71xx_pci_fixup_enable = 1;
369        register_pci_controller(&ar7100_pci_controller);
370        request_irq(AR7100_PCI_IRQ_CORE, ar7100_pci_core_intr, IRQ_DISABLED,"ar7100 pci core", NULL);
371
372        return 0;
373}
374
375arch_initcall(ar7100_pcibios_init);
Note: See TracBrowser for help on using the repository browser.