1/* 2 * Low-Level PCI and SB support for BCM47xx (Linux support code) 3 * 4 * Copyright 2006, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: pcibios.c,v 1.1.1.1 2008/10/15 03:26:06 james26_jang Exp $ 13 */ 14 15#include <linux/config.h> 16#include <linux/types.h> 17#include <linux/kernel.h> 18#include <linux/sched.h> 19#include <linux/pci.h> 20#include <linux/init.h> 21#include <linux/delay.h> 22#include <asm/io.h> 23#include <asm/irq.h> 24#include <asm/paccess.h> 25 26#include <typedefs.h> 27#include <bcmutils.h> 28#include <sbconfig.h> 29#include <sbutils.h> 30#include <hndpci.h> 31#include <pcicfg.h> 32#include <bcmdevs.h> 33#include <bcmnvram.h> 34 35/* Global SB handle */ 36extern sb_t *bcm947xx_sbh; 37extern spinlock_t bcm947xx_sbh_lock; 38 39/* Convenience */ 40#define sbh bcm947xx_sbh 41#define sbh_lock bcm947xx_sbh_lock 42 43static int 44sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value) 45{ 46 unsigned long flags; 47 int ret; 48 49 spin_lock_irqsave(&sbh_lock, flags); 50 ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 51 PCI_FUNC(dev->devfn), where, value, sizeof(*value)); 52 spin_unlock_irqrestore(&sbh_lock, flags); 53 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 54} 55 56static int 57sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value) 58{ 59 unsigned long flags; 60 int ret; 61 62 spin_lock_irqsave(&sbh_lock, flags); 63 ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 64 PCI_FUNC(dev->devfn), where, value, sizeof(*value)); 65 spin_unlock_irqrestore(&sbh_lock, flags); 66 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 67} 68 69static int 70sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value) 71{ 72 unsigned long flags; 73 int ret; 74 75 spin_lock_irqsave(&sbh_lock, flags); 76 ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 77 PCI_FUNC(dev->devfn), where, value, sizeof(*value)); 78 spin_unlock_irqrestore(&sbh_lock, flags); 79 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 80} 81 82static int 83sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value) 84{ 85 unsigned long flags; 86 int ret; 87 88 spin_lock_irqsave(&sbh_lock, flags); 89 ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 90 PCI_FUNC(dev->devfn), where, &value, sizeof(value)); 91 spin_unlock_irqrestore(&sbh_lock, flags); 92 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 93} 94 95static int 96sbpci_write_config_word(struct pci_dev *dev, int where, u16 value) 97{ 98 unsigned long flags; 99 int ret; 100 101 spin_lock_irqsave(&sbh_lock, flags); 102 ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 103 PCI_FUNC(dev->devfn), where, &value, sizeof(value)); 104 spin_unlock_irqrestore(&sbh_lock, flags); 105 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 106} 107 108static int 109sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value) 110{ 111 unsigned long flags; 112 int ret; 113 114 spin_lock_irqsave(&sbh_lock, flags); 115 ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), 116 PCI_FUNC(dev->devfn), where, &value, sizeof(value)); 117 spin_unlock_irqrestore(&sbh_lock, flags); 118 return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; 119} 120 121static struct pci_ops pcibios_ops = { 122 sbpci_read_config_byte, 123 sbpci_read_config_word, 124 sbpci_read_config_dword, 125 sbpci_write_config_byte, 126 sbpci_write_config_word, 127 sbpci_write_config_dword 128}; 129 130#if defined(BCMINTERNAL) && defined(CONFIG_BCM4710) 131/* PR9659 WAR: Periodically check PCI data transfer integrity */ 132static struct timer_list pci_timer; 133 134static void 135pci_check(unsigned long unused) 136{ 137 ulong flags; 138 139 spin_lock_irqsave(&sbh_lock, flags); 140 sbpci_check(sbh); 141 spin_unlock_irqrestore(&sbh_lock, flags); 142 143 pci_timer.expires = jiffies + pci_timer.data; 144 add_timer(&pci_timer); 145} 146#endif /* defined(BCMINTERNAL) && defined(CONFIG_BCM4710) */ 147 148 149void __init 150pcibios_init(void) 151{ 152 ulong flags; 153 154 if (!(sbh = sb_kattach(SB_OSH))) 155 panic("sb_kattach failed"); 156 spin_lock_init(&sbh_lock); 157 158 spin_lock_irqsave(&sbh_lock, flags); 159 sbpci_init(sbh); 160 spin_unlock_irqrestore(&sbh_lock, flags); 161 162 set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000)); 163 164 /* Scan the SB bus */ 165 pci_scan_bus(0, &pcibios_ops, NULL); 166 167#if defined(BCMINTERNAL) && defined(CONFIG_BCM4710) 168 if (sb_chip(sbh) == BCM4710_DEVICE_ID) { 169 struct pci_dev *dev; 170 u8 revision; 171 int freq; 172 173 /* Check PCI revision ID through external PCI config access */ 174 if ((dev = pci_find_slot(1, 0)) && 175 (pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision) == 0) && 176 (revision == 0)) { 177 /* Disable the test by default */ 178 freq = simple_strtoul(nvram_get("pcitestfreq") ? : "0", NULL, 0); 179 if (freq > 0) { 180 init_timer(&pci_timer); 181 pci_timer.function = pci_check; 182 pci_timer.data = HZ * freq; 183 pci_timer.expires = jiffies + pci_timer.data; 184 add_timer(&pci_timer); 185 } 186 } 187 } 188#endif /* defined(BCMINTERNAL) && defined(CONFIG_BCM4710) */ 189 190 191} 192 193char * __init 194pcibios_setup(char *str) 195{ 196 if (!strncmp(str, "ban=", 4)) { 197 sbpci_ban(simple_strtoul(str + 4, NULL, 0)); 198 return NULL; 199 } 200 201 return (str); 202} 203 204static u32 pci_iobase = 0x100; 205static u32 pci_membase = SB_PCI_DMA; 206 207void __init 208pcibios_fixup_bus(struct pci_bus *b) 209{ 210 struct list_head *ln; 211 struct pci_dev *d; 212 struct resource *res; 213 int pos, size; 214 u32 *base; 215 u8 irq; 216 217 printk("PCI: Fixing up bus %d\n", b->number); 218 219 /* Fix up SB */ 220 if (b->number == 0) { 221 for (ln = b->devices.next; ln != &b->devices; ln = ln->next) { 222 d = pci_dev_b(ln); 223 /* Fix up interrupt lines */ 224 pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq); 225 d->irq = irq + 2; 226 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); 227 } 228 } 229 230 /* Fix up external PCI */ 231 else { 232 for (ln = b->devices.next; ln != &b->devices; ln = ln->next) { 233 d = pci_dev_b(ln); 234 /* Fix up resource bases */ 235 for (pos = 0; pos < 6; pos++) { 236 res = &d->resource[pos]; 237 base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase; 238 if (res->end) { 239 size = res->end - res->start + 1; 240 if (*base & (size - 1)) 241 *base = (*base + size) & ~(size - 1); 242 res->start = *base; 243 res->end = res->start + size - 1; 244 *base += size; 245 pci_write_config_dword(d, 246 PCI_BASE_ADDRESS_0 + (pos << 2), res->start); 247 } 248 /* Fix up PCI bridge BAR0 only */ 249 if (b->number == 1 && PCI_SLOT(d->devfn) == 0) 250 break; 251 } 252 /* Fix up interrupt lines */ 253 if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL)) 254 d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq; 255 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); 256 } 257 } 258} 259 260unsigned int 261pcibios_assign_all_busses(void) 262{ 263 return 1; 264} 265 266void 267pcibios_align_resource(void *data, struct resource *res, 268 unsigned long size, unsigned long align) 269{ 270} 271 272int 273pcibios_enable_resources(struct pci_dev *dev) 274{ 275 u16 cmd, old_cmd; 276 int idx; 277 struct resource *r; 278 279 /* External PCI only */ 280 if (dev->bus->number == 0) 281 return 0; 282 283 pci_read_config_word(dev, PCI_COMMAND, &cmd); 284 old_cmd = cmd; 285 for (idx = 0; idx < 6; idx++) { 286 r = &dev->resource[idx]; 287 if (r->flags & IORESOURCE_IO) 288 cmd |= PCI_COMMAND_IO; 289 if (r->flags & IORESOURCE_MEM) 290 cmd |= PCI_COMMAND_MEMORY; 291 } 292 if (dev->resource[PCI_ROM_RESOURCE].start) 293 cmd |= PCI_COMMAND_MEMORY; 294 if (cmd != old_cmd) { 295 printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); 296 pci_write_config_word(dev, PCI_COMMAND, cmd); 297 } 298 return 0; 299} 300 301int 302pcibios_enable_device(struct pci_dev *dev, int mask) 303{ 304 ulong flags; 305 uint coreidx; 306 void *regs; 307 308 /* External PCI device enable */ 309 if (dev->bus->number != 0) 310 return pcibios_enable_resources(dev); 311 312 /* These cores come out of reset enabled */ 313 if (dev->device == SB_MIPS || 314 dev->device == SB_MIPS33 || 315 dev->device == SB_EXTIF || 316 dev->device == SB_CC) 317 return 0; 318 319 spin_lock_irqsave(&sbh_lock, flags); 320 coreidx = sb_coreidx(sbh); 321 regs = sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)); 322 if (!regs) 323 return PCIBIOS_DEVICE_NOT_FOUND; 324 325 /* 326 * The USB core requires a special bit to be set during core 327 * reset to enable host (OHCI) mode. Resetting the SB core in 328 * pcibios_enable_device() is a hack for compatibility with 329 * vanilla usb-ohci so that it does not have to know about 330 * SB. A driver that wants to use the USB core in device mode 331 * should know about SB and should reset the bit back to 0 332 * after calling pcibios_enable_device(). 333 */ 334 if (sb_coreid(sbh) == SB_USB) { 335 sb_core_disable(sbh, sb_coreflags(sbh, 0, 0)); 336 sb_core_reset(sbh, 1 << 29, 0); 337 } 338 /* 339 * USB 2.0 special considerations: 340 * 341 * 1. Since the core supports both OHCI and EHCI functions, it must 342 * only be reset once. 343 * 344 * 2. In addition to the standard SB reset sequence, the Host Control 345 * Register must be programmed to bring the USB core and various 346 * phy components out of reset. 347 */ 348 else if (sb_coreid(sbh) == SB_USB20H) { 349 if (!sb_iscoreup(sbh)) { 350#if 0 351 sb_core_reset(sbh, 0, 0); 352 writel(0x7FF, (ulong)regs + 0x200); 353 udelay(1); 354#endif 355 uint32 tmp; 356 357 sb_core_reset(sbh, 0, 0); 358 writel(0x7ff, (uintptr)regs + 0x200); 359 360 tmp = readl((uintptr)regs + 0x400); 361 tmp &= ~8; 362 writel(tmp, (uintptr)regs + 0x400); 363 364 tmp = readl((uintptr)regs + 0x304); 365 tmp &= ~0x100; 366 writel(tmp, (uintptr)regs + 0x304); 367 368 udelay(1); 369 370 } 371 /* War for 5354 failures. */ 372 if ((sb_corerev(sbh) == 2) && (sb_chip(sbh) == BCM5354_CHIP_ID)) { 373 uint32 tmp; 374 375 tmp = readl((uintptr)regs + 0x400); 376 tmp &= ~8; 377 writel(tmp, (uintptr)regs + 0x400); 378 tmp = readl((uintptr)regs + 0x400); 379 printk("USB20H fcr: 0x%x\n", tmp); 380 381 tmp = readl((uintptr)regs + 0x304); 382 tmp &= ~0x100; 383 writel(tmp, (uintptr)regs + 0x304); 384 tmp = readl((uintptr)regs + 0x304); 385 printk("USB20H shim cr: 0x%x\n", tmp); 386 387 tmp = 0x00fe00fe; 388 writel(tmp, (uintptr)regs + 0x894); 389 tmp = readl((uintptr)regs + 0x894); 390 printk("USB20H syn01 register : 0x%x\n", tmp); 391 392 tmp = readl((uintptr)regs + 0x89c); 393 tmp |= 0x1; 394 writel(tmp, (uintptr)regs + 0x89c); 395 tmp = readl((uintptr)regs + 0x89c); 396 printk("USB20H syn03 register : 0x%x\n", tmp); 397 } 398 399 } else 400 sb_core_reset(sbh, 0, 0); 401 402 sb_setcoreidx(sbh, coreidx); 403 spin_unlock_irqrestore(&sbh_lock, flags); 404 405 return 0; 406} 407 408void 409pcibios_update_resource(struct pci_dev *dev, struct resource *root, 410 struct resource *res, int resource) 411{ 412 unsigned long where, size; 413 u32 reg; 414 415 /* External PCI only */ 416 if (dev->bus->number == 0) 417 return; 418 419 where = PCI_BASE_ADDRESS_0 + (resource * 4); 420 size = res->end - res->start; 421 pci_read_config_dword(dev, where, ®); 422 reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); 423 pci_write_config_dword(dev, where, reg); 424} 425 426static void __init 427quirk_sbpci_bridge(struct pci_dev *dev) 428{ 429 if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0) 430 return; 431 432 printk("PCI: Fixing up bridge\n"); 433 434 /* Enable PCI bridge bus mastering and memory space */ 435 pci_set_master(dev); 436 pcibios_enable_resources(dev); 437 438 /* Enable PCI bridge BAR1 prefetch and burst */ 439 pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3); 440} 441 442struct pci_fixup pcibios_fixups[] = { 443 { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge }, 444 { 0 } 445}; 446