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>
26 unsigned long pcicr_virt
;
27 unsigned long PCI_IO_AREA
;
29 /* Rounds a number UP to the nearest power of two. Used for
30 * sizing the PCI window.
32 static u32 __init
r2p2(u32 num
)
48 /* If the original number isn't a power of 2, round it up */
55 static irqreturn_t
pcish5_err_irq(int irq
, void *dev_id
)
57 struct pt_regs
*regs
= get_irq_regs();
58 unsigned pci_int
, pci_air
, pci_cir
, pci_aint
;
60 pci_int
= SH5PCI_READ(INT
);
61 pci_cir
= SH5PCI_READ(CIR
);
62 pci_air
= SH5PCI_READ(AIR
);
65 printk("PCI INTERRUPT (at %08llx)!\n", regs
->pc
);
66 printk("PCI INT -> 0x%x\n", pci_int
& 0xffff);
67 printk("PCI AIR -> 0x%x\n", pci_air
);
68 printk("PCI CIR -> 0x%x\n", pci_cir
);
69 SH5PCI_WRITE(INT
, ~0);
72 pci_aint
= SH5PCI_READ(AINT
);
74 printk("PCI ARB INTERRUPT!\n");
75 printk("PCI AINT -> 0x%x\n", pci_aint
);
76 printk("PCI AIR -> 0x%x\n", pci_air
);
77 printk("PCI CIR -> 0x%x\n", pci_cir
);
78 SH5PCI_WRITE(AINT
, ~0);
84 static irqreturn_t
pcish5_serr_irq(int irq
, void *dev_id
)
91 static struct resource sh5_pci_resources
[2];
93 static struct pci_channel sh5pci_controller
= {
94 .pci_ops
= &sh5_pci_ops
,
95 .resources
= sh5_pci_resources
,
96 .nr_resources
= ARRAY_SIZE(sh5_pci_resources
),
97 .mem_offset
= 0x00000000,
98 .io_offset
= 0x00000000,
101 static int __init
sh5pci_init(void)
103 unsigned long memStart
= __pa(memory_start
);
104 unsigned long memSize
= __pa(memory_end
) - memStart
;
108 if (request_irq(IRQ_ERR
, pcish5_err_irq
,
109 0, "PCI Error",NULL
) < 0) {
110 printk(KERN_ERR
"PCISH5: Cannot hook PCI_PERR interrupt\n");
114 if (request_irq(IRQ_SERR
, pcish5_serr_irq
,
115 0, "PCI SERR interrupt", NULL
) < 0) {
116 printk(KERN_ERR
"PCISH5: Cannot hook PCI_SERR interrupt\n");
120 pcicr_virt
= (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE
, 1024);
122 panic("Unable to remap PCICR\n");
125 PCI_IO_AREA
= (unsigned long)ioremap_nocache(SH5PCI_IO_BASE
, 0x10000);
127 panic("Unable to remap PCIIO\n");
130 /* Clear snoop registers */
131 SH5PCI_WRITE(CSCR0
, 0);
132 SH5PCI_WRITE(CSCR1
, 0);
134 /* Switch off interrupts */
135 SH5PCI_WRITE(INTM
, 0);
136 SH5PCI_WRITE(AINTM
, 0);
137 SH5PCI_WRITE(PINTM
, 0);
139 /* Set bus active, take it out of reset */
140 uval
= SH5PCI_READ(CR
);
142 /* Set command Register */
143 SH5PCI_WRITE(CR
, uval
| CR_LOCK_MASK
| CR_CFINT
| CR_FTO
| CR_PFE
|
146 uval
=SH5PCI_READ(CR
);
148 /* Allow it to be a master */
149 /* NB - WE DISABLE I/O ACCESS to stop overlap */
150 /* set WAIT bit to enable stepping, an attempt to improve stability */
151 SH5PCI_WRITE_SHORT(CSR_CMD
,
152 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
156 ** Set translation mapping memory in order to convert the address
157 ** used for the main bus, to the PCI internal address.
159 SH5PCI_WRITE(MBR
,0x40000000);
161 /* Always set the max size 512M */
162 SH5PCI_WRITE(MBMR
, PCISH5_MEM_SIZCONV(512*1024*1024));
165 ** I/O addresses are mapped at internal PCI specific address
166 ** as is described into the configuration bridge table.
167 ** These are changed to 0, to allow cards that have legacy
168 ** io such as vga to function correctly. We set the SH5 IOBAR to
169 ** 256K, which is a bit big as we can only have 64K of address space
172 SH5PCI_WRITE(IOBR
,0x0);
174 /* Set up a 256K window. Totally pointless waste of address space */
175 SH5PCI_WRITE(IOBMR
,0);
177 /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
178 * Ideally, we would want to map the I/O region somewhere, but it
179 * is so big this is not that easy!
181 SH5PCI_WRITE(CSR_IBAR0
,~0);
182 /* Set memory size value */
183 memSize
= memory_end
- memory_start
;
185 /* Now we set up the mbars so the PCI bus can see the memory of
187 if (memSize
< (1024 * 1024)) {
188 printk(KERN_ERR
"PCISH5: Ridiculous memory size of 0x%lx?\n",
194 lsr0
= (memSize
> (512 * 1024 * 1024)) ? 0x1ff00001 :
195 ((r2p2(memSize
) - 0x100000) | 0x1);
196 SH5PCI_WRITE(LSR0
, lsr0
);
199 SH5PCI_WRITE(CSR_MBAR0
, memory_start
);
200 SH5PCI_WRITE(LAR0
, memory_start
);
202 SH5PCI_WRITE(CSR_MBAR1
,0);
203 SH5PCI_WRITE(LAR1
,0);
204 SH5PCI_WRITE(LSR1
,0);
206 /* Enable the PCI interrupts on the device */
207 SH5PCI_WRITE(INTM
, ~0);
208 SH5PCI_WRITE(AINTM
, ~0);
209 SH5PCI_WRITE(PINTM
, ~0);
211 sh5_pci_resources
[0].start
= PCI_IO_AREA
;
212 sh5_pci_resources
[0].end
= PCI_IO_AREA
+ 0x10000;
214 sh5_pci_resources
[1].start
= memStart
;
215 sh5_pci_resources
[1].end
= memStart
+ memSize
;
217 return register_pci_controller(&sh5pci_controller
);
219 arch_initcall(sh5pci_init
);