1 /* 2 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) 3 * Copyright (C) 2003, 2004 Paul Mundt 4 * Copyright (C) 2004 Richard Curnow 5 * 6 * May be copied or modified under the terms of the GNU General Public 7 * License. See linux/COPYING for more information. 8 * 9 * Support functions for the SH5 PCI hardware. 10 */ 11 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 <cpu/irq.h> 23 #include <asm/pci.h> 24 #include <asm/io.h> 25 #include "pci-sh5.h" 26 27 unsigned long pcicr_virt; 28 unsigned long PCI_IO_AREA; 29 30 /* Rounds a number UP to the nearest power of two. Used for 31 * sizing the PCI window. 32 */ r2p2(u32 num)33 static u32 __init r2p2(u32 num) 34 { 35 int i = 31; 36 u32 tmp = num; 37 38 if (num == 0) 39 return 0; 40 41 do { 42 if (tmp & (1 << 31)) 43 break; 44 i--; 45 tmp <<= 1; 46 } while (i >= 0); 47 48 tmp = 1 << i; 49 /* If the original number isn't a power of 2, round it up */ 50 if (tmp != num) 51 tmp <<= 1; 52 53 return tmp; 54 } 55 pcish5_err_irq(int irq,void * dev_id)56 static irqreturn_t pcish5_err_irq(int irq, void *dev_id) 57 { 58 struct pt_regs *regs = get_irq_regs(); 59 unsigned pci_int, pci_air, pci_cir, pci_aint; 60 61 pci_int = SH5PCI_READ(INT); 62 pci_cir = SH5PCI_READ(CIR); 63 pci_air = SH5PCI_READ(AIR); 64 65 if (pci_int) { 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); 71 } 72 73 pci_aint = SH5PCI_READ(AINT); 74 if (pci_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); 80 } 81 82 return IRQ_HANDLED; 83 } 84 pcish5_serr_irq(int irq,void * dev_id)85 static irqreturn_t pcish5_serr_irq(int irq, void *dev_id) 86 { 87 printk("SERR IRQ\n"); 88 89 return IRQ_NONE; 90 } 91 92 static struct resource sh5_pci_resources[2]; 93 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, 100 }; 101 sh5pci_init(void)102 static int __init sh5pci_init(void) 103 { 104 unsigned long memStart = __pa(memory_start); 105 unsigned long memSize = __pa(memory_end) - memStart; 106 u32 lsr0; 107 u32 uval; 108 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"); 112 return -EINVAL; 113 } 114 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"); 118 return -EINVAL; 119 } 120 121 pcicr_virt = (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE, 1024); 122 if (!pcicr_virt) { 123 panic("Unable to remap PCICR\n"); 124 } 125 126 PCI_IO_AREA = (unsigned long)ioremap_nocache(SH5PCI_IO_BASE, 0x10000); 127 if (!PCI_IO_AREA) { 128 panic("Unable to remap PCIIO\n"); 129 } 130 131 /* Clear snoop registers */ 132 SH5PCI_WRITE(CSCR0, 0); 133 SH5PCI_WRITE(CSCR1, 0); 134 135 /* Switch off interrupts */ 136 SH5PCI_WRITE(INTM, 0); 137 SH5PCI_WRITE(AINTM, 0); 138 SH5PCI_WRITE(PINTM, 0); 139 140 /* Set bus active, take it out of reset */ 141 uval = SH5PCI_READ(CR); 142 143 /* Set command Register */ 144 SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE | 145 CR_PFCS | CR_BMAM); 146 147 uval=SH5PCI_READ(CR); 148 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 | 154 PCI_COMMAND_WAIT); 155 156 /* 157 ** Set translation mapping memory in order to convert the address 158 ** used for the main bus, to the PCI internal address. 159 */ 160 SH5PCI_WRITE(MBR,0x40000000); 161 162 /* Always set the max size 512M */ 163 SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024)); 164 165 /* 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 171 */ 172 173 SH5PCI_WRITE(IOBR,0x0); 174 175 /* Set up a 256K window. Totally pointless waste of address space */ 176 SH5PCI_WRITE(IOBMR,0); 177 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! 181 */ 182 SH5PCI_WRITE(CSR_IBAR0,~0); 183 /* Set memory size value */ 184 memSize = memory_end - memory_start; 185 186 /* Now we set up the mbars so the PCI bus can see the memory of 187 * the machine */ 188 if (memSize < (1024 * 1024)) { 189 printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%lx?\n", 190 memSize); 191 return -EINVAL; 192 } 193 194 /* Set LSR 0 */ 195 lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 : 196 ((r2p2(memSize) - 0x100000) | 0x1); 197 SH5PCI_WRITE(LSR0, lsr0); 198 199 /* Set MBAR 0 */ 200 SH5PCI_WRITE(CSR_MBAR0, memory_start); 201 SH5PCI_WRITE(LAR0, memory_start); 202 203 SH5PCI_WRITE(CSR_MBAR1,0); 204 SH5PCI_WRITE(LAR1,0); 205 SH5PCI_WRITE(LSR1,0); 206 207 /* Enable the PCI interrupts on the device */ 208 SH5PCI_WRITE(INTM, ~0); 209 SH5PCI_WRITE(AINTM, ~0); 210 SH5PCI_WRITE(PINTM, ~0); 211 212 sh5_pci_resources[0].start = PCI_IO_AREA; 213 sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000; 214 215 sh5_pci_resources[1].start = memStart; 216 sh5_pci_resources[1].end = memStart + memSize; 217 218 return register_pci_controller(&sh5pci_controller); 219 } 220 arch_initcall(sh5pci_init); 221