unsigned int x86_pci_read_config8(pci_dev_t dev, unsigned where) { uint8_t value; pci_hose_read_config_byte(get_hose(), dev, where, &value); return value; }
static void pci_enet_fixup_irq(struct pci_controller *hose, pci_dev_t dev) { /* a configurable lists of IRQs to steal when we need one */ static int irq_list[] = { CONFIG_SYS_FIRST_PCI_IRQ, CONFIG_SYS_SECOND_PCI_IRQ, CONFIG_SYS_THIRD_PCI_IRQ, CONFIG_SYS_FORTH_PCI_IRQ }; static int next_irq_index=0; uchar tmp_pin; int pin; pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &tmp_pin); pin = tmp_pin; pin -= 1; /* PCI config space use 1-based numbering */ if (pin == -1) { return; /* device use no irq */ } /* map device number + pin to a pin on the sc520 */ switch (PCI_DEV(dev)) { case 12: /* First Ethernet Chip */ pin += SC520_PCI_INTA; break; case 13: /* Second Ethernet Chip */ pin += SC520_PCI_INTB; break; default: return; } pin &= 3; /* wrap around */ if (sc520_pci_ints[pin] == -1) { /* re-route one interrupt for us */ if (next_irq_index > 3) { return; } if (pci_sc520_set_irq(pin, irq_list[next_irq_index])) { return; } next_irq_index++; } if (-1 != sc520_pci_ints[pin]) { pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, sc520_pci_ints[pin]); } printf("fixup_irq: device %d pin %c irq %d\n", PCI_DEV(dev), 'A' + pin, sc520_pci_ints[pin]); }
static void pci_pip405_fixup_irq(struct pci_controller *hose, pci_dev_t dev) { unsigned char int_line = 0xff; unsigned char pin; /* * Write pci interrupt line register */ if(PCI_DEV(dev)==0) /* Device0 = PPC405 -> skip */ return; pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin); if ((pin == 0) || (pin > 4)) return; int_line = ((PCI_DEV(dev) + (pin-1) + 10) % 4) + 28; pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line); #ifdef DEBUG printf("Fixup IRQ: dev %d (%x) int line %d 0x%x\n", PCI_DEV(dev),dev,int_line,int_line); #endif }
int pci_hose_config_device(struct pci_controller *hose, pci_dev_t dev, unsigned long io, pci_addr_t mem, unsigned long command) { u32 bar_response; unsigned int old_command; pci_addr_t bar_value; pci_size_t bar_size; unsigned char pin; int bar, found_mem64; debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io, (u64)mem, command); pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0); for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) { pci_hose_write_config_dword(hose, dev, bar, 0xffffffff); pci_hose_read_config_dword(hose, dev, bar, &bar_response); if (!bar_response) continue; found_mem64 = 0; /* Check the BAR type and set our address mask */ if (bar_response & PCI_BASE_ADDRESS_SPACE) { bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1; /* round up region base address to a multiple of size */ io = ((io - 1) | (bar_size - 1)) + 1; bar_value = io; /* compute new region base address */ io = io + bar_size; } else { if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { u32 bar_response_upper; u64 bar64; pci_hose_write_config_dword(hose, dev, bar + 4, 0xffffffff); pci_hose_read_config_dword(hose, dev, bar + 4, &bar_response_upper); bar64 = ((u64)bar_response_upper << 32) | bar_response; bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1; found_mem64 = 1; } else { bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1); } /* round up region base address to multiple of size */ mem = ((mem - 1) | (bar_size - 1)) + 1; bar_value = mem; /* compute new region base address */ mem = mem + bar_size; } /* Write it out and update our limit */ pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value); if (found_mem64) { bar += 4; #ifdef CONFIG_SYS_PCI_64BIT pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value >> 32)); #else pci_hose_write_config_dword(hose, dev, bar, 0x00000000); #endif } } /* Configure Cache Line Size Register */ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); /* Configure Latency Timer */ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); /* Disable interrupt line, if device says it wants to use interrupts */ pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin); if (pin != 0) { pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, PCI_INTERRUPT_LINE_DISABLE); } pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command); pci_hose_write_config_dword(hose, dev, PCI_COMMAND, (old_command & 0xffff0000) | command); return 0; }
/* HJF: Changed this to return int. I think this is required * to get the correct result when scanning bridges */ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) { unsigned int sub_bus = PCI_BUS(dev); unsigned short class; unsigned char prg_iface; int n; pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); switch(class) { case PCI_CLASS_BRIDGE_PCI: hose->current_busno++; pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_io); DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev)); /* Passing in current_busno allows for sibling P2P bridges */ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); /* * need to figure out if this is a subordinate bridge on the bus * to be able to properly set the pri/sec/sub bridge registers. */ n = pci_hose_scan_bus(hose, hose->current_busno); /* figure out the deepest we've gone for this leg */ sub_bus = max(n, sub_bus); pciauto_postscan_setup_bridge(hose, dev, sub_bus); sub_bus = hose->current_busno; break; case PCI_CLASS_STORAGE_IDE: pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface); if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n"); return sub_bus; } pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); break; case PCI_CLASS_BRIDGE_CARDBUS: /* just do a minimal setup of the bridge, let the OS take care of the rest */ pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_io); DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev)); hose->current_busno++; break; #ifdef CONFIG_MPC5200 case PCI_CLASS_BRIDGE_OTHER: DEBUGF("PCI Autoconfig: Skipping bridge device %d\n", PCI_DEV(dev)); break; #endif default: pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); break; } return sub_bus; }
static void pci_bus_scan(struct ftpci100_data *priv) { struct pci_controller *hose = (struct pci_controller *)&local_hose; unsigned int bus, dev, func; pci_dev_t dev_nu; unsigned int data32; unsigned int tmp; unsigned char header; unsigned char int_pin; unsigned int niobars; unsigned int nmbars; priv->ndevs = 1; nmbars = 0; niobars = 0; for (bus = 0; bus < MAX_BUS_NUM; bus++) for (dev = 0; dev < MAX_DEV_NUM; dev++) for (func = 0; func < MAX_FUN_NUM; func++) { dev_nu = PCI_BDF(bus, dev, func); pci_hose_read_config_dword(hose, dev_nu, PCI_VENDOR_ID, &data32); /* * some broken boards return 0 or ~0, * if a slot is empty. */ if (data32 == 0xffffffff || data32 == 0x00000000 || data32 == 0x0000ffff || data32 == 0xffff0000) continue; pci_hose_read_config_dword(hose, dev_nu, PCI_HEADER_TYPE, &tmp); header = (unsigned char)tmp; setup_pci_bar(bus, dev, func, header, priv); devs[priv->ndevs].v_id = (u16)(data32 & \ 0x0000ffff); devs[priv->ndevs].d_id = (u16)((data32 & \ 0xffff0000) >> 16); /* Figure out what INTX# line the card uses */ pci_hose_read_config_byte(hose, dev_nu, PCI_INTERRUPT_PIN, &int_pin); /* assign the appropriate irq line */ if (int_pin > PCI_IRQ_LINES) { printf("more irq lines than expect\n"); } else if (int_pin != 0) { /* This device uses an interrupt line */ devs[priv->ndevs].pin = int_pin; } pci_hose_read_config_dword(hose, dev_nu, PCI_CLASS_DEVICE, &data32); debug("%06d %03d %03d " \ "%04d %08x %08x " \ "%03d %08x %06d %08x\n", priv->ndevs, devs[priv->ndevs].bus, devs[priv->ndevs].dev, devs[priv->ndevs].func, devs[priv->ndevs].d_id, devs[priv->ndevs].v_id, devs[priv->ndevs].pin, devs[priv->ndevs].bar[0].addr, devs[priv->ndevs].bar[0].size, data32 >> 8); priv->ndevs++; } }
void pci_mpc85xx_init(struct pci_controller *hose) { volatile immap_t *immap = (immap_t *)CFG_CCSRBAR; volatile ccsr_pcix_t *pcix = &immap->im_pcix; u16 reg16; hose->first_busno = 0; hose->last_busno = 0xff; pci_set_region(hose->regions + 0, CFG_PCI1_MEM_BASE, CFG_PCI1_MEM_PHYS, CFG_PCI1_MEM_SIZE, PCI_REGION_MEM); pci_set_region(hose->regions + 1, CFG_PCI1_IO_BASE, CFG_PCI1_IO_PHYS, CFG_PCI1_IO_SIZE, PCI_REGION_IO); hose->region_count = 2; pci_setup_indirect(hose, (CFG_IMMR+0x8000), (CFG_IMMR+0x8004)); pcix->potar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; pcix->potear1 = 0x00000000; pcix->powbar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; pcix->powbear1 = 0x00000000; pcix->powar1 = 0x8004401c; /* 512M MEM space */ pcix->potar2 = 0x00000000; pcix->potear2 = 0x00000000; pcix->powbar2 = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff; pcix->powbear2 = 0x00000000; pcix->powar2 = 0x80088017; /* 16M IO space */ pcix->pitar1 = 0x00000000; pcix->piwbar1 = 0x00000000; pcix->piwar1 = 0xa0f5501e; /* Enable, Prefetch, Local Mem, * Snoop R/W, 2G */ /* * Hose scan. */ pci_register_hose(hose); pci_read_config_word (PCI_BDF(0,0,0), PCI_COMMAND, ®16); reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; pci_write_config_word(PCI_BDF(0,0,0), PCI_COMMAND, reg16); /* * Clear non-reserved bits in status register. */ pci_write_config_word(PCI_BDF(0,0,0), PCI_STATUS, 0xffff); pci_write_config_byte(PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80); #if defined(CONFIG_MPC8555CDS) || defined(CONFIG_MPC8541CDS) /* * This is a SW workaround for an apparent HW problem * in the PCI controller on the MPC85555/41 CDS boards. * The first config cycle must be to a valid, known * device on the PCI bus in order to trick the PCI * controller state machine into a known valid state. * Without this, the first config cycle has the chance * of hanging the controller permanently, just leaving * it in a semi-working state, or leaving it working. * * Pick on the Tundra, Device 17, to get it right. */ { u8 header_type; pci_hose_read_config_byte(hose, PCI_BDF(0,17,0), PCI_HEADER_TYPE, &header_type); } #endif hose->last_busno = pci_hose_scan(hose); }