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>
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 static struct resource sh5_pci_resources
[2];
94 static struct pci_channel sh5pci_controller
= {
95 .pci_ops
= &sh5_pci_ops
,
96 .resources
= sh5_pci_resources
,
97 .nr_resources
= ARRAY_SIZE(sh5_pci_resources
),
98 .mem_offset
= 0x00000000,
99 .io_offset
= 0x00000000,
102 static int __init
sh5pci_init(void)
104 unsigned long memStart
= __pa(memory_start
);
105 unsigned long memSize
= __pa(memory_end
) - memStart
;
109 if (request_irq(IRQ_ERR
, pcish5_err_irq
,
110 0, "PCI Error",NULL
) < 0) {
111 printk(KERN_ERR
"PCISH5: Cannot hook PCI_PERR interrupt\n");
115 if (request_irq(IRQ_SERR
, pcish5_serr_irq
,
116 0, "PCI SERR interrupt", NULL
) < 0) {
117 printk(KERN_ERR
"PCISH5: Cannot hook PCI_SERR interrupt\n");
121 pcicr_virt
= (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE
, 1024);
123 panic("Unable to remap PCICR\n");
126 PCI_IO_AREA
= (unsigned long)ioremap_nocache(SH5PCI_IO_BASE
, 0x10000);
128 panic("Unable to remap PCIIO\n");
131 /* Clear snoop registers */
132 SH5PCI_WRITE(CSCR0
, 0);
133 SH5PCI_WRITE(CSCR1
, 0);
135 /* Switch off interrupts */
136 SH5PCI_WRITE(INTM
, 0);
137 SH5PCI_WRITE(AINTM
, 0);
138 SH5PCI_WRITE(PINTM
, 0);
140 /* Set bus active, take it out of reset */
141 uval
= SH5PCI_READ(CR
);
143 /* Set command Register */
144 SH5PCI_WRITE(CR
, uval
| CR_LOCK_MASK
| CR_CFINT
| CR_FTO
| CR_PFE
|
147 uval
=SH5PCI_READ(CR
);
149 /* Allow it to be a master */
150 /* NB - WE DISABLE I/O ACCESS to stop overlap */
151 /* set WAIT bit to enable stepping, an attempt to improve stability */
152 SH5PCI_WRITE_SHORT(CSR_CMD
,
153 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
157 ** Set translation mapping memory in order to convert the address
158 ** used for the main bus, to the PCI internal address.
160 SH5PCI_WRITE(MBR
,0x40000000);
162 /* Always set the max size 512M */
163 SH5PCI_WRITE(MBMR
, PCISH5_MEM_SIZCONV(512*1024*1024));
166 ** I/O addresses are mapped at internal PCI specific address
167 ** as is described into the configuration bridge table.
168 ** These are changed to 0, to allow cards that have legacy
169 ** io such as vga to function correctly. We set the SH5 IOBAR to
170 ** 256K, which is a bit big as we can only have 64K of address space
173 SH5PCI_WRITE(IOBR
,0x0);
175 /* Set up a 256K window. Totally pointless waste of address space */
176 SH5PCI_WRITE(IOBMR
,0);
178 /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
179 * Ideally, we would want to map the I/O region somewhere, but it
180 * is so big this is not that easy!
182 SH5PCI_WRITE(CSR_IBAR0
,~0);
183 /* Set memory size value */
184 memSize
= memory_end
- memory_start
;
186 /* Now we set up the mbars so the PCI bus can see the memory of
188 if (memSize
< (1024 * 1024)) {
189 printk(KERN_ERR
"PCISH5: Ridiculous memory size of 0x%lx?\n",
195 lsr0
= (memSize
> (512 * 1024 * 1024)) ? 0x1ff00001 :
196 ((r2p2(memSize
) - 0x100000) | 0x1);
197 SH5PCI_WRITE(LSR0
, lsr0
);
200 SH5PCI_WRITE(CSR_MBAR0
, memory_start
);
201 SH5PCI_WRITE(LAR0
, memory_start
);
203 SH5PCI_WRITE(CSR_MBAR1
,0);
204 SH5PCI_WRITE(LAR1
,0);
205 SH5PCI_WRITE(LSR1
,0);
207 /* Enable the PCI interrupts on the device */
208 SH5PCI_WRITE(INTM
, ~0);
209 SH5PCI_WRITE(AINTM
, ~0);
210 SH5PCI_WRITE(PINTM
, ~0);
212 sh5_pci_resources
[0].start
= PCI_IO_AREA
;
213 sh5_pci_resources
[0].end
= PCI_IO_AREA
+ 0x10000;
215 sh5_pci_resources
[1].start
= memStart
;
216 sh5_pci_resources
[1].end
= memStart
+ memSize
;
218 return register_pci_controller(&sh5pci_controller
);
220 arch_initcall(sh5pci_init
);