📄 sb1250_pci_machdep.c
字号:
/* Try again. Do a reset iff an LDT master, since a poorly timed reset by a slave will break any link initialization in progress. */ retry--; if (sb1250_ldt_slave_mode) cfe_sleep(CFE_HZ/10); else lhb_link_reset(CFE_HZ/10); } /* Rev 0.17 does not support dyanmic frequency updates. */ if (!rev017) { /* Leave the target frequency in the LinkFreq register, which is just a shadow until a link reset happens. */ pci_conf_write8(SB1250_LDT_BRIDGE, LHB_LFREQ_REG, ldt_freq); } finish: t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG); if ((t & LDT_LINKCTRL_INITDONE) == 0) { xprintf("HyperTransport not initialized: InitDone not set\n"); if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, " Link Cmd = 0x%08x, Link Ctrl = 0x%08x\n", pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCMD_REG), pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG)); /* In production code, consider doing a chip cold reset (via the SCD) here if the system requires an initialized HT bus. See the advisory on HT PLL problems. */ } else if ((t & LHB_LINKCTRL_ERRORS) != 0) { xprintf("HyperTransport not initialized: " "LinkFail or CRCErr set, LinkCtrl = 0x%08x\n", t); } else if (!sb1250_ldt_slave_mode) sb1250_ldt_init = 1; /* Clear any pending error bits */ t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG); pci_conf_write32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG, t & 0xFF000000); if (sb1250_ldt_slave_mode) { /* This is LDT slave mode. The documentation is not very clear on how much low level initialization should be done before sleeping. We just set Master Enable so that we can subsequently access LDT space. */ pcireg_t cmd; /* If there are intermediate devices on the LDT, we would like our addressing to match the master's, but we don't know it and can't force it here. Instead, we close all the windows into configurable space, which is at least safe. */ lhb_null_config(); cmd = pci_conf_read32(SB1250_LDT_BRIDGE, PCI_COMMAND_STATUS_REG); cmd &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT); /* preserve status */ cmd |= PCI_COMMAND_MASTER_ENABLE; pci_conf_write32(SB1250_LDT_BRIDGE, PCI_COMMAND_STATUS_REG, cmd); } else if (!sb1250_ldt_init) { pcireg_t lr; lhb_null_config(); /* Also, terminate the link */ lr = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG); lr |= LDT_LINKCTRL_EOC; pci_conf_write32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG, lr); lr |= LDT_LINKCTRL_TXOFF; pci_conf_write32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG, lr); } show_ldt_status();}/* * Called to initialise IOB0 and the host bridges at the beginning of time. */intpci_hwinit (int port, pci_flags_t flags){ int i; int rev017; unsigned linkfreq, buffctl; uint64_t syscfg; const char *str; /* define the address spaces and capabilities */ if (port != 0) return -1; pci_set_root(); /* initialise global data */ syscfg = SBREADCSR(A_SCD_SYSTEM_CFG); sb1250_in_device_mode = ((syscfg & M_SYS_PCI_HOST) == 0); if (cfe_startflags & CFE_LDT_SLAVE) sb1250_ldt_slave_mode = 1; else sb1250_ldt_slave_mode = 0; eoi_implemented = 0; /* conservative default */ /* Check for any relevant environment variables. */ rev017 = ((flags & PCI_FLG_LDT_REV_017) != 0); /* Choose the LDT link frequency. [C]SWARM boards are now set for 400 MHz by default */ str = env_getenv("LDT_LINKFREQ"); linkfreq = (str ? atoi(str) : 400); /* Choose the buffer allocation (favor posted writes by default) */ str = env_getenv("LDT_BUFFERS"); buffctl = (str ? atoi(str) & 0xFFFF : 0x2525); _pci_bus[_pci_nbus] = sb1250_pci_bus; _pci_bus[_pci_nbus].port = port; _pci_nbus++; for (i = _pci_nbus; i < MAXBUS; i++) _pci_bus[i] = secondary_pci_bus; /* stop the SB-1250 from servicing any further PCI or LDT requests */ pci_conf_write32(SB1250_PCI_BRIDGE, PCI_COMMAND_STATUS_REG, 0); pci_conf_write32(SB1250_LDT_BRIDGE, PCI_COMMAND_STATUS_REG, 0); /* initialize the PCI host bridge */ phb_init(); /* initialize the LDT host bridge */ lhb_init(rev017, linkfreq, buffctl); cfe_sleep(CFE_HZ); /* add some delay */ return 0;}/* * Called to update the host bridge after we've scanned each PCI device * and know what is possible. */voidpci_hwreinit (int port, pci_flags_t flags){ pcireg_t cmd; /* note: this is not officially supported by sb1250, perhaps no effect! */ if (_pci_bus[0].fast_b2b) { /* fast back-to-back is supported by all devices */ cmd = pci_conf_read32(SB1250_PCI_BRIDGE, PCI_COMMAND_STATUS_REG); cmd &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT); /* preserve status */ cmd |= PCI_COMMAND_BACKTOBACK_ENABLE; pci_conf_write32(SB1250_PCI_BRIDGE, PCI_COMMAND_STATUS_REG, cmd); } /* Latency timer, cache line size set by pci_setup_devices (pciconf.c) */ /* enable PCI read/write error interrupts */ /* XXX */}/* The following functions provide for device-specific setup required during configuration. There is nothing SiByte-specific about them, and it would be better to do the packaging and registration in a more modular way. */#if CFG_LDT#define PCI_VENDOR_ALSC 0x14D9#define PCI_PRODUCT_ALSC_SP1011 0x0010#define PCI_PRODUCT_ALSC_AS90L10208 0x9000extern void sp1011_setup(pcitag_t tag, pci_flags_t flags);extern void as90l10208_setup(pcitag_t tag, pci_flags_t flags);#define PCI_VENDOR_AMD 0x1022#define PCI_PRODUCT_PLX_HT7520 0x7450#define PCI_PRODUCT_PLX_HT7520_APIC 0x7451extern void ht7520apic_preset(pcitag_t tag);extern void ht7520apic_setup(pcitag_t tag);#define PCI_PRODUCT_AMD_8151 0x7454#endif /* CFG_LDT *//* Dispatch functions for device pre- and post-configuration hooks. *//* Called for each hostbridge, to discover and scan secondary buses */voidpci_businit_hostbridge (pcitag_t tag, pci_flags_t flags){}/* Called for each function prior to assigning PCI resources. */intpci_device_preset (pcitag_t tag){ pcireg_t id; int skip; skip = 0; id = pci_conf_read(tag, PCI_ID_REG); switch (PCI_VENDOR(id)) { case PCI_VENDOR_SIBYTE: /* Check for a host bridge seen internally, in which case we don't want to allocate any address space for its BARs. */ if (tag == SB1250_PCI_BRIDGE) skip = 1; break;#if CFG_LDT case PCI_VENDOR_AMD: switch (PCI_PRODUCT(id)) { case PCI_PRODUCT_PLX_HT7520_APIC: ht7520apic_preset (tag); break; case PCI_PRODUCT_AMD_8151: skip = 1; break; default: break; } break;#endif /* CFG_LDT */ default: break; } return skip;}/* Called for each non-bridge (Type 0) function after assigning the BAR and InterruptLine (XXX check this) resources.. */voidpci_device_setup (pcitag_t tag){ pcireg_t id = pci_conf_read(tag, PCI_ID_REG); switch (PCI_VENDOR(id)) {#if CFG_LDT case PCI_VENDOR_AMD: if (PCI_PRODUCT(id) == PCI_PRODUCT_PLX_HT7520_APIC) ht7520apic_setup (tag); break;#endif /* CFG_LDT */ default: break; }}/* Called for each bridge (Type 1) function after configuring the secondary bus, to allow device-specific initialization. */voidpci_bridge_setup (pcitag_t tag, pci_flags_t flags){ pcireg_t id = pci_conf_read(tag, PCI_ID_REG); switch (PCI_VENDOR(id)) {#if CFG_LDT case PCI_VENDOR_ALSC: switch (PCI_PRODUCT(id)) { case PCI_PRODUCT_ALSC_SP1011: sp1011_setup (tag, flags); break; case PCI_PRODUCT_ALSC_AS90L10208: as90l10208_setup (tag, flags); break; default: break; } break; case PCI_VENDOR_AMD: /* The PLX ht7520 requires configuration of the interrupt mapping, but it packages the IOAPIC as a separate function, registers of which will not yet have been initialized if the standard traversal order is followed. See pci_device_setup above. */ break;#endif /* CFG_LDT */ default: break; }}/* Machine dependent access primitives and utility functions */voidpci_flush (void){ /* note: this is a noop for the SB-1250. */}pcitag_tpci_make_tag (int port, int bus, int device, int function){ return SB1250_PCI_MAKE_TAG(bus, device, function);}voidpci_break_tag (pcitag_t tag, int *portp, int *busp, int *devicep, int *functionp){ if (portp) *portp = (tag >> 24) & PCI_PORTMAX; if (busp) *busp = (tag >> 16) & PCI_BUSMAX; if (devicep) *devicep = (tag >> 11) & PCI_DEVMAX; if (functionp) *functionp = (tag >> 8) & PCI_FUNCMAX;}intpci_canscan (pcitag_t tag){ int port, bus, device, function; pci_break_tag (tag, &port, &bus, &device, &function); if (port > PCI_PORTMAX || bus > PCI_BUSMAX || device > PCI_DEVMAX || function > PCI_FUNCMAX) return 0; if (bus == 0) { if (sb1250_in_device_mode) { /* Scan the LDT chain, but only the LDT host bridge on PCI. */ if (device != 1) return 0; } if (sb1250_ldt_slave_mode || !sb1250_ldt_init) { /* Scan the PCI devices but not the LDT chain. */ if (device == 1) return 0; } if (device > 20) { /* Chip bug: asserts IDSEL for device 20 for all devices > 20. */ return 0; } } return 1;}intpci_probe_tag(pcitag_t tag){ physaddr_t addrp; pcireg_t data; if (!pci_canscan(tag)) return 0; addrp = (physaddr_t) SB1250_CFG_ADDR(tag, PCI_ID_REG, 4); /* An earlier version of this code cleared the MasterAbort and TargetAbort bits in the PCI host bridge, did the read, and looked for those bits to be set. For the SB-1250, that's inappropriate because - it's the wrong host bridge for devices behind LDT. - PCI host bridge registers aren't readable in Device mode. - it loses status if testing the PCI host bridge itself. We rely on getting 0xffff when reading the vendor ID. Note that this still has side effects on the host bridge registers. */ data = phys_read32(addrp); /* device + vendor ID */ mips_wbflush(); /* if it returned all vendor id bits set, it's not a device */ return (PCI_VENDOR(data) != 0xFFFF);}/* Read/write access to PCI configuration registers. For most applications, pci_conf_read<N> and pci_conf_write<N> are deprecated unless N = 32. */static pcireg_tpci_conf_readn(pcitag_t tag, int reg, int width){ physaddr_t addrp; pcireg_t data;#if (PCI_DEBUG != 0) int port, bus, device, function; if (reg & (width-1) || reg < 0 || reg >= PCI_REGMAX) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_conf_readn: bad reg 0x%x\n", reg); return 0; } pci_break_tag(tag, &port, &bus, &device, &function); if (bus > PCI_BUSMAX || device > PCI_DEVMAX || function > PCI_FUNCMAX) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_conf_readn: bad tag 0x%x\n", tag); return 0; }#endif /* PCI_DEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -