1 /* 2 * Common routines for Tundra Semiconductor TSI108 host bridge. 3 * 4 * 2004-2005 (c) Tundra Semiconductor Corp. 5 * Author: Alex Bounine (alexandreb@tundra.com) 6 * Author: Roy Zang (tie-fei.zang@freescale.com) 7 * Add pci interrupt router host 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 * more details. 18 * 19 * You should have received a copy of the GNU General Public License along with 20 * this program; if not, write to the Free Software Foundation, Inc., 59 21 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 */ 23 24 #include <linux/kernel.h> 25 #include <linux/init.h> 26 #include <linux/pci.h> 27 #include <linux/slab.h> 28 #include <linux/irq.h> 29 #include <linux/interrupt.h> 30 31 #include <asm/byteorder.h> 32 #include <asm/io.h> 33 #include <asm/irq.h> 34 #include <asm/uaccess.h> 35 #include <asm/machdep.h> 36 #include <asm/pci-bridge.h> 37 #include <asm/tsi108.h> 38 #include <asm/tsi108_irq.h> 39 #include <asm/prom.h> 40 41 #undef DEBUG 42 #ifdef DEBUG 43 #define DBG(x...) printk(x) 44 #else 45 #define DBG(x...) 46 #endif 47 48 #define tsi_mk_config_addr(bus, devfunc, offset) \ 49 ((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base) 50 51 u32 tsi108_pci_cfg_base; 52 u32 tsi108_csr_vir_base; 53 static struct device_node *pci_irq_node; 54 static struct irq_host *pci_irq_host; 55 56 extern u32 get_vir_csrbase(void); 57 extern u32 tsi108_read_reg(u32 reg_offset); 58 extern void tsi108_write_reg(u32 reg_offset, u32 val); 59 60 int 61 tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc, 62 int offset, int len, u32 val) 63 { 64 volatile unsigned char *cfg_addr; 65 66 if (ppc_md.pci_exclude_device) 67 if (ppc_md.pci_exclude_device(bus->number, devfunc)) 68 return PCIBIOS_DEVICE_NOT_FOUND; 69 70 cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number, 71 devfunc, offset) | 72 (offset & 0x03)); 73 74 #ifdef DEBUG 75 printk("PCI CFG write : "); 76 printk("%d:0x%x:0x%x ", bus->number, devfunc, offset); 77 printk("%d ADDR=0x%08x ", len, (uint) cfg_addr); 78 printk("data = 0x%08x\n", val); 79 #endif 80 81 switch (len) { 82 case 1: 83 out_8((u8 *) cfg_addr, val); 84 break; 85 case 2: 86 out_le16((u16 *) cfg_addr, val); 87 break; 88 default: 89 out_le32((u32 *) cfg_addr, val); 90 break; 91 } 92 93 return PCIBIOS_SUCCESSFUL; 94 } 95 96 void tsi108_clear_pci_error(u32 pci_cfg_base) 97 { 98 u32 err_stat, err_addr, pci_stat; 99 100 /* 101 * Quietly clear PB and PCI error flags set as result 102 * of PCI/X configuration read requests. 103 */ 104 105 /* Read PB Error Log Registers */ 106 107 err_stat = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS); 108 err_addr = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_AERR); 109 110 if (err_stat & TSI108_PB_ERRCS_ES) { 111 /* Clear error flag */ 112 tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS, 113 TSI108_PB_ERRCS_ES); 114 115 /* Clear read error reported in PB_ISR */ 116 tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ISR, 117 TSI108_PB_ISR_PBS_RD_ERR); 118 119 /* Clear PCI/X bus cfg errors if applicable */ 120 if ((err_addr & 0xFF000000) == pci_cfg_base) { 121 pci_stat = 122 tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR); 123 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR, 124 pci_stat); 125 } 126 } 127 128 return; 129 } 130 131 #define __tsi108_read_pci_config(x, addr, op) \ 132 __asm__ __volatile__( \ 133 " "op" %0,0,%1\n" \ 134 "1: eieio\n" \ 135 "2:\n" \ 136 ".section .fixup,\"ax\"\n" \ 137 "3: li %0,-1\n" \ 138 " b 2b\n" \ 139 ".section __ex_table,\"a\"\n" \ 140 " .align 2\n" \ 141 " .long 1b,3b\n" \ 142 ".text" \ 143 : "=r"(x) : "r"(addr)) 144 145 int 146 tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset, 147 int len, u32 * val) 148 { 149 volatile unsigned char *cfg_addr; 150 u32 temp; 151 152 if (ppc_md.pci_exclude_device) 153 if (ppc_md.pci_exclude_device(bus->number, devfn)) 154 return PCIBIOS_DEVICE_NOT_FOUND; 155 156 cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number, 157 devfn, 158 offset) | (offset & 159 0x03)); 160 161 switch (len) { 162 case 1: 163 __tsi108_read_pci_config(temp, cfg_addr, "lbzx"); 164 break; 165 case 2: 166 __tsi108_read_pci_config(temp, cfg_addr, "lhbrx"); 167 break; 168 default: 169 __tsi108_read_pci_config(temp, cfg_addr, "lwbrx"); 170 break; 171 } 172 173 *val = temp; 174 175 #ifdef DEBUG 176 if ((0xFFFFFFFF != temp) && (0xFFFF != temp) && (0xFF != temp)) { 177 printk("PCI CFG read : "); 178 printk("%d:0x%x:0x%x ", bus->number, devfn, offset); 179 printk("%d ADDR=0x%08x ", len, (uint) cfg_addr); 180 printk("data = 0x%x\n", *val); 181 } 182 #endif 183 return PCIBIOS_SUCCESSFUL; 184 } 185 186 void tsi108_clear_pci_cfg_error(void) 187 { 188 tsi108_clear_pci_error(TSI108_PCI_CFG_BASE_PHYS); 189 } 190 191 static struct pci_ops tsi108_direct_pci_ops = { 192 tsi108_direct_read_config, 193 tsi108_direct_write_config 194 }; 195 196 int __init tsi108_setup_pci(struct device_node *dev) 197 { 198 int len; 199 struct pci_controller *hose; 200 struct resource rsrc; 201 const int *bus_range; 202 int primary = 0, has_address = 0; 203 204 /* PCI Config mapping */ 205 tsi108_pci_cfg_base = (u32)ioremap(TSI108_PCI_CFG_BASE_PHYS, 206 TSI108_PCI_CFG_SIZE); 207 DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __FUNCTION__, 208 tsi108_pci_cfg_base); 209 210 /* Fetch host bridge registers address */ 211 has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); 212 213 /* Get bus range if any */ 214 bus_range = get_property(dev, "bus-range", &len); 215 if (bus_range == NULL || len < 2 * sizeof(int)) { 216 printk(KERN_WARNING "Can't get bus-range for %s, assume" 217 " bus 0\n", dev->full_name); 218 } 219 220 hose = pcibios_alloc_controller(); 221 222 if (!hose) { 223 printk("PCI Host bridge init failed\n"); 224 return -ENOMEM; 225 } 226 hose->arch_data = dev; 227 hose->set_cfg_type = 1; 228 229 hose->first_busno = bus_range ? bus_range[0] : 0; 230 hose->last_busno = bus_range ? bus_range[1] : 0xff; 231 232 (hose)->ops = &tsi108_direct_pci_ops; 233 234 printk(KERN_INFO "Found tsi108 PCI host bridge at 0x%08x. " 235 "Firmware bus number: %d->%d\n", 236 rsrc.start, hose->first_busno, hose->last_busno); 237 238 /* Interpret the "ranges" property */ 239 /* This also maps the I/O region and sets isa_io/mem_base */ 240 pci_process_bridge_OF_ranges(hose, dev, primary); 241 return 0; 242 } 243 244 /* 245 * Low level utility functions 246 */ 247 248 static void tsi108_pci_int_mask(u_int irq) 249 { 250 u_int irp_cfg; 251 int int_line = (irq - IRQ_PCI_INTAD_BASE); 252 253 irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL); 254 mb(); 255 irp_cfg |= (1 << int_line); /* INTx_DIR = output */ 256 irp_cfg &= ~(3 << (8 + (int_line * 2))); /* INTx_TYPE = unused */ 257 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg); 258 mb(); 259 irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL); 260 } 261 262 static void tsi108_pci_int_unmask(u_int irq) 263 { 264 u_int irp_cfg; 265 int int_line = (irq - IRQ_PCI_INTAD_BASE); 266 267 irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL); 268 mb(); 269 irp_cfg &= ~(1 << int_line); 270 irp_cfg |= (3 << (8 + (int_line * 2))); 271 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg); 272 mb(); 273 } 274 275 static void init_pci_source(void) 276 { 277 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, 278 0x0000ff00); 279 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE, 280 TSI108_PCI_IRP_ENABLE_P_INT); 281 mb(); 282 } 283 284 static inline unsigned int get_pci_source(void) 285 { 286 u_int temp = 0; 287 int irq = -1; 288 int i; 289 u_int pci_irp_stat; 290 static int mask = 0; 291 292 /* Read PCI/X block interrupt status register */ 293 pci_irp_stat = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT); 294 mb(); 295 296 if (pci_irp_stat & TSI108_PCI_IRP_STAT_P_INT) { 297 /* Process Interrupt from PCI bus INTA# - INTD# lines */ 298 temp = 299 tsi108_read_reg(TSI108_PCI_OFFSET + 300 TSI108_PCI_IRP_INTAD) & 0xf; 301 mb(); 302 for (i = 0; i < 4; i++, mask++) { 303 if (temp & (1 << mask % 4)) { 304 irq = IRQ_PCI_INTA + mask % 4; 305 mask++; 306 break; 307 } 308 } 309 310 /* Disable interrupts from PCI block */ 311 temp = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE); 312 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE, 313 temp & ~TSI108_PCI_IRP_ENABLE_P_INT); 314 mb(); 315 (void)tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE); 316 mb(); 317 } 318 #ifdef DEBUG 319 else { 320 printk("TSI108_PIC: error in TSI108_PCI_IRP_STAT\n"); 321 pci_irp_stat = 322 tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT); 323 temp = 324 tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_INTAD); 325 mb(); 326 printk(">> stat=0x%08x intad=0x%08x ", pci_irp_stat, temp); 327 temp = 328 tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL); 329 mb(); 330 printk("cfg_ctl=0x%08x ", temp); 331 temp = 332 tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE); 333 mb(); 334 printk("irp_enable=0x%08x\n", temp); 335 } 336 #endif /* end of DEBUG */ 337 338 return irq; 339 } 340 341 342 /* 343 * Linux descriptor level callbacks 344 */ 345 346 static void tsi108_pci_irq_enable(u_int irq) 347 { 348 tsi108_pci_int_unmask(irq); 349 } 350 351 static void tsi108_pci_irq_disable(u_int irq) 352 { 353 tsi108_pci_int_mask(irq); 354 } 355 356 static void tsi108_pci_irq_ack(u_int irq) 357 { 358 tsi108_pci_int_mask(irq); 359 } 360 361 static void tsi108_pci_irq_end(u_int irq) 362 { 363 tsi108_pci_int_unmask(irq); 364 365 /* Enable interrupts from PCI block */ 366 tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE, 367 tsi108_read_reg(TSI108_PCI_OFFSET + 368 TSI108_PCI_IRP_ENABLE) | 369 TSI108_PCI_IRP_ENABLE_P_INT); 370 mb(); 371 } 372 373 /* 374 * Interrupt controller descriptor for cascaded PCI interrupt controller. 375 */ 376 377 static struct irq_chip tsi108_pci_irq = { 378 .typename = "tsi108_PCI_int", 379 .mask = tsi108_pci_irq_disable, 380 .ack = tsi108_pci_irq_ack, 381 .end = tsi108_pci_irq_end, 382 .unmask = tsi108_pci_irq_enable, 383 }; 384 385 static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, 386 u32 *intspec, unsigned int intsize, 387 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 388 { 389 *out_hwirq = intspec[0]; 390 *out_flags = IRQ_TYPE_LEVEL_HIGH; 391 return 0; 392 } 393 394 static int pci_irq_host_map(struct irq_host *h, unsigned int virq, 395 irq_hw_number_t hw) 396 { unsigned int irq; 397 DBG("%s(%d, 0x%lx)\n", __FUNCTION__, virq, hw); 398 if ((virq >= 1) && (virq <= 4)){ 399 irq = virq + IRQ_PCI_INTAD_BASE - 1; 400 get_irq_desc(irq)->status |= IRQ_LEVEL; 401 set_irq_chip(irq, &tsi108_pci_irq); 402 } 403 return 0; 404 } 405 406 static int pci_irq_host_match(struct irq_host *h, struct device_node *node) 407 { 408 return pci_irq_node == node; 409 } 410 411 static struct irq_host_ops pci_irq_host_ops = { 412 .match = pci_irq_host_match, 413 .map = pci_irq_host_map, 414 .xlate = pci_irq_host_xlate, 415 }; 416 417 /* 418 * Exported functions 419 */ 420 421 /* 422 * The Tsi108 PCI interrupts initialization routine. 423 * 424 * The INTA# - INTD# interrupts on the PCI bus are reported by the PCI block 425 * to the MPIC using single interrupt source (IRQ_TSI108_PCI). Therefore the 426 * PCI block has to be treated as a cascaded interrupt controller connected 427 * to the MPIC. 428 */ 429 430 void __init tsi108_pci_int_init(struct device_node *node) 431 { 432 DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); 433 434 pci_irq_node = of_node_get(node); 435 pci_irq_host = irq_alloc_host(IRQ_HOST_MAP_LEGACY, 0, &pci_irq_host_ops, 0); 436 if (pci_irq_host == NULL) { 437 printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n"); 438 return; 439 } 440 441 init_pci_source(); 442 } 443 444 void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc) 445 { 446 unsigned int cascade_irq = get_pci_source(); 447 if (cascade_irq != NO_IRQ) 448 generic_handle_irq(cascade_irq); 449 desc->chip->eoi(irq); 450 } 451