source: src/linux/sl2312/linux-2.6.23/arch/arm/mach-sl2312/pci.c @ 9980

Last change on this file since 9980 was 9980, checked in by BrainSlayer, 5 years ago

delete broken commit

File size: 9.2 KB
Line 
1/*
2 *  linux/arch/arm/mach-sl2312/pci_sl2312.c
3 *
4 *  PCI functions for sl2312 host PCI bridge
5 *
6 *  Copyright (C) 2003 StorLink Corp.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22#include <linux/sched.h>
23#include <linux/kernel.h>
24#include <linux/pci.h>
25#include <linux/ptrace.h>
26#include <linux/slab.h>
27#include <linux/ioport.h>
28#include <linux/interrupt.h>
29#include <linux/spinlock.h>
30#include <linux/init.h>
31
32#include <asm/sizes.h>
33#include <asm/hardware.h>
34#include <asm/irq.h>
35#include <asm/system.h>
36#include <asm/mach/pci.h>
37#include <asm/mach/irq.h>
38#include <asm/mach-types.h>
39
40#include <asm/arch/pci.h>
41
42//#define DEBUG
43
44// sl2312 PCI bridge access routines
45
46#define PCI_IOSIZE_REG  (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE)))
47#define PCI_PROT_REG    (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x04))
48#define PCI_CTRL_REG    (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x08))
49#define PCI_SOFTRST_REG (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x10))
50#define PCI_CONFIG_REG  (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x28))
51#define PCI_DATA_REG    (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x2C))
52
53static spinlock_t sl2312_pci_lock = SPIN_LOCK_UNLOCKED;
54// for initialize PCI devices
55struct resource pci_ioport_resource = {
56                .name = "PCI I/O Space",
57                .start = IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x100,
58                .end = IO_ADDRESS(SL2312_PCI_IO_BASE) + SZ_512K - 1,
59                .flags = IORESOURCE_IO,
60};
61struct resource pci_iomem_resource = {
62                .name = "PCI Mem Space",
63                .start = SL2312_PCI_MEM_BASE,
64                .end = SL2312_PCI_MEM_BASE + SZ_128M - 1,
65                .flags = IORESOURCE_MEM,
66};
67
68static int sl2312_read_config(struct pci_bus *bus, unsigned int devfn, int where,int size, u32 *val)
69{
70        unsigned long addr,data;
71        unsigned long flags;
72
73        spin_lock_irqsave(&sl2312_pci_lock, flags);
74    addr = 0x80000000 | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | (where & ~3);
75        PCI_CONFIG_REG = addr;
76        data = PCI_DATA_REG;
77
78        switch (size) {
79        case 1:
80            *val = (u8) (data >> ((where & 0x03) * 8));
81                break;
82        case 2:
83            *val = (u16) (data >> ((where & 0x02) * 8));
84                break;
85        case 4:
86            *val = data;
87        if ((where >= 0x10) && (where <= 0x24)) {
88                if ((*val & 0xfff00000) == SL2312_PCI_IO_BASE) {
89                        *val &= 0x000fffff;
90                        *val |= IO_ADDRESS(SL2312_PCI_IO_BASE);
91                }
92        }
93                break;
94        }
95        spin_unlock_irqrestore(&sl2312_pci_lock, flags);
96//      printk("READ==>slot=%d fn=%d where=%d value=%x\n",PCI_SLOT(devfn),PCI_FUNC(devfn),where,*val);
97        return PCIBIOS_SUCCESSFUL;
98}
99
100static int sl2312_write_config(struct pci_bus *bus, unsigned int devfn, int where,int size, u32 val)
101{
102        unsigned long addr,data;
103        unsigned long flags;
104
105        spin_lock_irqsave(&sl2312_pci_lock, flags);
106    addr = 0x80000000 | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | (where & ~3);
107        PCI_CONFIG_REG = addr;
108        data = PCI_DATA_REG;
109
110        switch (size) {
111        case 1:
112        data &= ~(0xff << ((where & 0x03) * 8));
113        data |= (val << ((where & 0x03) * 8));
114        PCI_DATA_REG = data;
115                break;
116        case 2:
117        data &= ~(0xffff << ((where & 0x02) * 8));
118        data |= (val << ((where & 0x02) * 8));
119        PCI_DATA_REG = data;
120                break;
121        case 4:
122        if ((where >= 0x10) && (where <= 0x24)) {
123                if ((val & 0xfff00000) == IO_ADDRESS(SL2312_PCI_IO_BASE)) {
124                        val &= 0x000fffff;
125                        val |= SL2312_PCI_IO_BASE;
126                }
127        }
128            PCI_DATA_REG = val;
129                break;
130        }
131        spin_unlock_irqrestore(&sl2312_pci_lock, flags);
132
133//      printk("WRITE==> slot=%d fn=%d where=%d value=%x \n",PCI_SLOT(devfn),PCI_FUNC(devfn),where,val);
134        return PCIBIOS_SUCCESSFUL;
135}
136
137static struct pci_ops sl2312_pci_ops = {
138        .read   = sl2312_read_config,
139        .write  = sl2312_write_config,
140};
141
142
143int __init sl2312_pci_setup_resources(struct resource **resource)
144{
145        PCI_IOSIZE_REG = 0;             // 1M IO size
146        PCI_CTRL_REG = 0x06;
147
148        resource[0] = &pci_ioport_resource;
149        resource[1] = &pci_iomem_resource;
150        resource[2] = NULL;
151
152        return 1;
153}
154
155//static int sl2312_pci_fault(unsigned long addr, struct pt_regs *regs)
156//{
157//      return 1;
158//}
159
160
161/**********************************************************************
162 * MASK(disable) PCI interrupt
163 *    0: PCI INTA, 1: PCI INTB, ...             // for Linux interrupt routing
164 *   16: PERR                                                           // for PCI module internal use
165 *   17: SERR,.. respect to PCI CTRL2 REG
166 **********************************************************************/
167void sl2312_pci_mask_irq(unsigned int irq)
168{
169    struct pci_bus bus;
170        unsigned int tmp;
171
172    bus.number = 0;
173    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
174        if (irq < 16) {                                         // for linux int routing
175                tmp &= ~(1 << (irq + 16 + 6));
176        }
177        else {
178                tmp &= ~(1 << irq);
179        }
180    sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
181}
182
183/* UNMASK(enable) PCI interrupt */
184void sl2312_pci_unmask_irq(unsigned int irq)
185{
186    struct pci_bus bus;
187        unsigned int tmp;
188
189    bus.number = 0;
190    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
191        if (irq < 16) {                                         // for linux int routing
192                tmp |= (1 << (irq + 16 + 6));
193        }
194        else {
195                tmp |= (1 << irq);
196        }
197    sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
198}
199
200/* Get PCI interrupt source */
201int sl2312_pci_get_int_src(void)
202{
203    struct pci_bus bus;
204        unsigned int tmp=0;
205
206    bus.number = 0;
207    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
208        if (tmp & (1 << 28)) {          // PCI INTA
209        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
210                return IRQ_PCI_INTA;
211        }
212        if (tmp & (1 << 29)) {          // PCI INTB
213        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
214                return IRQ_PCI_INTB;
215        }
216        if (tmp & (1 << 30)) {          // PCI INTC
217        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
218                return IRQ_PCI_INTC;
219        }
220        if (tmp & (1 << 31)) {          // PCI INTD
221        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
222                return IRQ_PCI_INTD;
223        }
224        // otherwise, it should be a PCI error
225        return IRQ_PCI;
226}
227
228static irqreturn_t sl2312_pci_irq(int irq, void *devid)
229{
230    struct irq_desc *desc;
231        struct irqaction *action;
232        int retval = 0;
233
234    return 1;
235
236        irq = sl2312_pci_get_int_src();
237        desc = &irq_desc[irq];
238        action = desc->action;
239        do {
240                retval |= action->handler(irq, devid);
241                action = action->next;
242        } while (action);
243
244    return 1;
245}
246
247//extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
248
249void __init sl2312_pci_preinit(void)
250{
251    struct pci_bus bus;
252        unsigned long flags;
253        unsigned int temp;
254        int ret;
255
256        /*
257         * Hook in our fault handler for PCI errors
258         */
259//      external_fault = sl2312_pci_fault;
260
261        spin_lock_irqsave(&sl2312_pci_lock, flags);
262
263        /*
264         * Grab the PCI interrupt.
265         */
266        ret = request_irq(IRQ_PCI, sl2312_pci_irq, 0, "sl2312 pci int", NULL);
267        if (ret)
268                printk(KERN_ERR "PCI: unable to grab PCI error "
269                       "interrupt: %d\n", ret);
270
271        spin_unlock_irqrestore(&sl2312_pci_lock, flags);
272
273        // setup pci bridge
274    bus.number = 0;   /* device 0, function 0 */
275        temp = (SL2312_PCI_DMA_MEM1_BASE & 0xfff00000) | (SL2312_PCI_DMA_MEM1_SIZE << 16);
276    sl2312_write_config(&bus, 0, SL2312_PCI_MEM1_BASE_SIZE, 4, temp);
277}
278
279/*
280 *      No swizzle on SL2312
281 */
282static u8 __init sl2312_pci_swizzle(struct pci_dev *dev, u8 *pinp)
283{
284        return PCI_SLOT(dev->devfn);
285}
286
287/*
288 * map the specified device/slot/pin to an IRQ.  This works out such
289 * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
290 */
291static int __init sl2312_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
292{
293        int intnr = ((slot  + (pin - 1)) & 3) + 4;  /* the IRQ number of PCI bridge */
294
295        // printk("%s : slot = %d  pin = %d \n",__func__,slot,pin);
296    switch (slot)
297    {
298        case 12:
299                if (pin==1)
300                {
301                        intnr = 3;
302                    }
303                    else
304                    {
305                        intnr = 0;
306                    }
307            break;
308        case 11:
309                    intnr = (2 + (pin - 1)) & 3;
310            break;
311        case 10:
312                    intnr = (1 + (pin - 1)) & 3;
313            break;
314        case  9:
315                    intnr = (pin - 1) & 3;
316            break;
317    }
318//      if (slot == 10)
319//              intnr = (1 + (pin - 1)) & 3;
320//      else if (slot == 9)
321//              intnr = (pin - 1) & 3;
322        return (IRQ_PCI_INTA + intnr);
323}
324
325struct pci_bus * __init sl2312_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
326{
327        return (pci_scan_bus(0, &sl2312_pci_ops, sysdata));
328
329}
330
331int __init sl2312_pci_setup(int nr, struct pci_sys_data *sys)
332{
333        int ret = 0;
334
335        if (nr == 0) {
336                ret = sl2312_pci_setup_resources(sys->resource);
337        }
338
339        return ret;
340}
341
342
343struct hw_pci sl2312_pci __initdata = {
344        .setup          =       sl2312_pci_setup,
345        .preinit                =       sl2312_pci_preinit,
346        .nr_controllers =   1,
347        .swizzle                =       sl2312_pci_swizzle,
348        .map_irq                =       sl2312_pci_map_irq,
349        .scan           =   sl2312_pci_scan_bus,
350};
351
352static int __init sl2312_pci_init(void)
353{
354        if (machine_is_sl2312())
355                pci_common_init(&sl2312_pci);
356        return 0;
357}
358
359subsys_initcall(sl2312_pci_init);
Note: See TracBrowser for help on using the repository browser.