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_io_resource
= { /* place holder */ };
93 static struct resource sh5_mem_resource
= { /* place holder */ };
95 static struct pci_channel sh5pci_controller
= {
96 .pci_ops
= &sh5_pci_ops
,
97 .mem_resource
= &sh5_mem_resource
,
98 .mem_offset
= 0x00000000,
99 .io_resource
= &sh5_io_resource
,
100 .io_offset
= 0x00000000,
103 static int __init
sh5pci_init(void)
105 unsigned long memStart
= __pa(memory_start
);
106 unsigned long memSize
= __pa(memory_end
) - memStart
;
110 if (request_irq(IRQ_ERR
, pcish5_err_irq
,
111 IRQF_DISABLED
, "PCI Error",NULL
) < 0) {
112 printk(KERN_ERR
"PCISH5: Cannot hook PCI_PERR interrupt\n");
116 if (request_irq(IRQ_SERR
, pcish5_serr_irq
,
117 IRQF_DISABLED
, "PCI SERR interrupt", NULL
) < 0) {
118 printk(KERN_ERR
"PCISH5: Cannot hook PCI_SERR interrupt\n");
122 pcicr_virt
= (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE
, 1024);
124 panic("Unable to remap PCICR\n");
127 PCI_IO_AREA
= (unsigned long)ioremap_nocache(SH5PCI_IO_BASE
, 0x10000);
129 panic("Unable to remap PCIIO\n");
132 /* Clear snoop registers */
133 SH5PCI_WRITE(CSCR0
, 0);
134 SH5PCI_WRITE(CSCR1
, 0);
136 /* Switch off interrupts */
137 SH5PCI_WRITE(INTM
, 0);
138 SH5PCI_WRITE(AINTM
, 0);
139 SH5PCI_WRITE(PINTM
, 0);
141 /* Set bus active, take it out of reset */
142 uval
= SH5PCI_READ(CR
);
144 /* Set command Register */
145 SH5PCI_WRITE(CR
, uval
| CR_LOCK_MASK
| CR_CFINT
| CR_FTO
| CR_PFE
|
148 uval
=SH5PCI_READ(CR
);
150 /* Allow it to be a master */
151 /* NB - WE DISABLE I/O ACCESS to stop overlap */
152 /* set WAIT bit to enable stepping, an attempt to improve stability */
153 SH5PCI_WRITE_SHORT(CSR_CMD
,
154 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
158 ** Set translation mapping memory in order to convert the address
159 ** used for the main bus, to the PCI internal address.
161 SH5PCI_WRITE(MBR
,0x40000000);
163 /* Always set the max size 512M */
164 SH5PCI_WRITE(MBMR
, PCISH5_MEM_SIZCONV(512*1024*1024));
167 ** I/O addresses are mapped at internal PCI specific address
168 ** as is described into the configuration bridge table.
169 ** These are changed to 0, to allow cards that have legacy
170 ** io such as vga to function correctly. We set the SH5 IOBAR to
171 ** 256K, which is a bit big as we can only have 64K of address space
174 SH5PCI_WRITE(IOBR
,0x0);
176 /* Set up a 256K window. Totally pointless waste of address space */
177 SH5PCI_WRITE(IOBMR
,0);
179 /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
180 * Ideally, we would want to map the I/O region somewhere, but it
181 * is so big this is not that easy!
183 SH5PCI_WRITE(CSR_IBAR0
,~0);
184 /* Set memory size value */
185 memSize
= memory_end
- memory_start
;
187 /* Now we set up the mbars so the PCI bus can see the memory of
189 if (memSize
< (1024 * 1024)) {
190 printk(KERN_ERR
"PCISH5: Ridiculous memory size of 0x%lx?\n",
196 lsr0
= (memSize
> (512 * 1024 * 1024)) ? 0x1ff00001 :
197 ((r2p2(memSize
) - 0x100000) | 0x1);
198 SH5PCI_WRITE(LSR0
, lsr0
);
201 SH5PCI_WRITE(CSR_MBAR0
, memory_start
);
202 SH5PCI_WRITE(LAR0
, memory_start
);
204 SH5PCI_WRITE(CSR_MBAR1
,0);
205 SH5PCI_WRITE(LAR1
,0);
206 SH5PCI_WRITE(LSR1
,0);
208 /* Enable the PCI interrupts on the device */
209 SH5PCI_WRITE(INTM
, ~0);
210 SH5PCI_WRITE(AINTM
, ~0);
211 SH5PCI_WRITE(PINTM
, ~0);
213 sh5_io_resource
.start
= PCI_IO_AREA
;
214 sh5_io_resource
.end
= PCI_IO_AREA
+ 0x10000;
216 sh5_mem_resource
.start
= memStart
;
217 sh5_mem_resource
.end
= memStart
+ memSize
;
219 register_pci_controller(&sh5pci_controller
);
223 arch_initcall(sh5pci_init
);