2 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
3 * Copyright (C) 2003, 2004 Paul Mundt
4 * Copyright (C) 2004 Richard Curnow
6 * May be copied or modified under the terms of the GNU General Public
7 * License. See linux/COPYING for more information.
9 * Support functions for the SH5 PCI hardware.
12 #include <linux/kernel.h>
13 #include <linux/rwsem.h>
14 #include <linux/smp.h>
15 #include <linux/interrupt.h>
16 #include <linux/init.h>
17 #include <linux/errno.h>
18 #include <linux/pci.h>
19 #include <linux/delay.h>
20 #include <linux/types.h>
21 #include <linux/irq.h>
22 #include <asm/cpu/irq.h>
27 unsigned long pcicr_virt
;
28 unsigned long PCI_IO_AREA
;
30 /* Rounds a number UP to the nearest power of two. Used for
31 * sizing the PCI window.
33 static u32 __init
r2p2(u32 num
)
49 /* If the original number isn't a power of 2, round it up */
56 static irqreturn_t
pcish5_err_irq(int irq
, void *dev_id
)
58 struct pt_regs
*regs
= get_irq_regs();
59 unsigned pci_int
, pci_air
, pci_cir
, pci_aint
;
61 pci_int
= SH5PCI_READ(INT
);
62 pci_cir
= SH5PCI_READ(CIR
);
63 pci_air
= SH5PCI_READ(AIR
);
66 printk("PCI INTERRUPT (at %08llx)!\n", regs
->pc
);
67 printk("PCI INT -> 0x%x\n", pci_int
& 0xffff);
68 printk("PCI AIR -> 0x%x\n", pci_air
);
69 printk("PCI CIR -> 0x%x\n", pci_cir
);
70 SH5PCI_WRITE(INT
, ~0);
73 pci_aint
= SH5PCI_READ(AINT
);
75 printk("PCI ARB INTERRUPT!\n");
76 printk("PCI AINT -> 0x%x\n", pci_aint
);
77 printk("PCI AIR -> 0x%x\n", pci_air
);
78 printk("PCI CIR -> 0x%x\n", pci_cir
);
79 SH5PCI_WRITE(AINT
, ~0);
85 static irqreturn_t
pcish5_serr_irq(int irq
, void *dev_id
)
92 int __init
sh5pci_init(unsigned long memStart
, unsigned long memSize
)
97 if (request_irq(IRQ_ERR
, pcish5_err_irq
,
98 IRQF_DISABLED
, "PCI Error",NULL
) < 0) {
99 printk(KERN_ERR
"PCISH5: Cannot hook PCI_PERR interrupt\n");
103 if (request_irq(IRQ_SERR
, pcish5_serr_irq
,
104 IRQF_DISABLED
, "PCI SERR interrupt", NULL
) < 0) {
105 printk(KERN_ERR
"PCISH5: Cannot hook PCI_SERR interrupt\n");
109 pcicr_virt
= onchip_remap(SH5PCI_ICR_BASE
, 1024, "PCICR");
111 panic("Unable to remap PCICR\n");
114 PCI_IO_AREA
= onchip_remap(SH5PCI_IO_BASE
, 0x10000, "PCIIO");
116 panic("Unable to remap PCIIO\n");
119 /* Clear snoop registers */
120 SH5PCI_WRITE(CSCR0
, 0);
121 SH5PCI_WRITE(CSCR1
, 0);
123 /* Switch off interrupts */
124 SH5PCI_WRITE(INTM
, 0);
125 SH5PCI_WRITE(AINTM
, 0);
126 SH5PCI_WRITE(PINTM
, 0);
128 /* Set bus active, take it out of reset */
129 uval
= SH5PCI_READ(CR
);
131 /* Set command Register */
132 SH5PCI_WRITE(CR
, uval
| CR_LOCK_MASK
| CR_CFINT
| CR_FTO
| CR_PFE
|
135 uval
=SH5PCI_READ(CR
);
137 /* Allow it to be a master */
138 /* NB - WE DISABLE I/O ACCESS to stop overlap */
139 /* set WAIT bit to enable stepping, an attempt to improve stability */
140 SH5PCI_WRITE_SHORT(CSR_CMD
,
141 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
145 ** Set translation mapping memory in order to convert the address
146 ** used for the main bus, to the PCI internal address.
148 SH5PCI_WRITE(MBR
,0x40000000);
150 /* Always set the max size 512M */
151 SH5PCI_WRITE(MBMR
, PCISH5_MEM_SIZCONV(512*1024*1024));
154 ** I/O addresses are mapped at internal PCI specific address
155 ** as is described into the configuration bridge table.
156 ** These are changed to 0, to allow cards that have legacy
157 ** io such as vga to function correctly. We set the SH5 IOBAR to
158 ** 256K, which is a bit big as we can only have 64K of address space
161 SH5PCI_WRITE(IOBR
,0x0);
163 /* Set up a 256K window. Totally pointless waste of address space */
164 SH5PCI_WRITE(IOBMR
,0);
166 /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
167 * Ideally, we would want to map the I/O region somewhere, but it
168 * is so big this is not that easy!
170 SH5PCI_WRITE(CSR_IBAR0
,~0);
171 /* Set memory size value */
172 memSize
= memory_end
- memory_start
;
174 /* Now we set up the mbars so the PCI bus can see the memory of
176 if (memSize
< (1024 * 1024)) {
177 printk(KERN_ERR
"PCISH5: Ridiculous memory size of 0x%lx?\n",
183 lsr0
= (memSize
> (512 * 1024 * 1024)) ? 0x1ff00001 :
184 ((r2p2(memSize
) - 0x100000) | 0x1);
185 SH5PCI_WRITE(LSR0
, lsr0
);
188 SH5PCI_WRITE(CSR_MBAR0
, memory_start
);
189 SH5PCI_WRITE(LAR0
, memory_start
);
191 SH5PCI_WRITE(CSR_MBAR1
,0);
192 SH5PCI_WRITE(LAR1
,0);
193 SH5PCI_WRITE(LSR1
,0);
195 /* Enable the PCI interrupts on the device */
196 SH5PCI_WRITE(INTM
, ~0);
197 SH5PCI_WRITE(AINTM
, ~0);
198 SH5PCI_WRITE(PINTM
, ~0);
203 void __devinit
pcibios_fixup_bus(struct pci_bus
*bus
)
205 struct pci_dev
*dev
= bus
->self
;
209 for (i
= 0; i
< 3; i
++) {
211 &dev
->resource
[PCI_BRIDGE_RESOURCES
+i
];
212 bus
->resource
[i
]->name
= bus
->name
;
214 bus
->resource
[0]->flags
|= IORESOURCE_IO
;
215 bus
->resource
[1]->flags
|= IORESOURCE_MEM
;
217 /* For now, propagate host limits to the bus;
218 * we'll adjust them later. */
219 bus
->resource
[0]->end
= 64*1024 - 1 ;
220 bus
->resource
[1]->end
= PCIBIOS_MIN_MEM
+(256*1024*1024)-1;
221 bus
->resource
[0]->start
= PCIBIOS_MIN_IO
;
222 bus
->resource
[1]->start
= PCIBIOS_MIN_MEM
;
224 /* Turn off downstream PF memory address range by default */
225 bus
->resource
[2]->start
= 1024*1024;
226 bus
->resource
[2]->end
= bus
->resource
[2]->start
- 1;