📄 sb1250_pci_machdep.c
字号:
icr &=~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); icr |= (pci_int_line(pci_int_map_0(SB1250_PCI_BRIDGE)) << PCI_INTERRUPT_LINE_SHIFT); pci_conf_write32(SB1250_PCI_BRIDGE, PCI_BPARAM_INTERRUPT_REG, icr); /* PCI: push the writes */ t = pci_conf_read32(SB1250_PCI_BRIDGE, PCI_ID_REG); cr = pci_conf_read32(SB1250_PCI_BRIDGE, PCI_CLASS_REG); if (PCI_REVISION(cr) >= 2) { pcireg_t id; id = pci_conf_read32(SB1250_PCI_BRIDGE, PCI_ID_REG); pci_conf_write32(SB1250_PCI_BRIDGE, PHB_SUBSYSSET_REG, id); pci_conf_write32(SB1250_PCI_BRIDGE, PHB_READHOST_REG, PHB_READHOST_DISABLE); t = pci_conf_read32(SB1250_PCI_BRIDGE, PHB_READHOST_REG); /* push */ }}/* Implementation-specific registers for the LDT Host Bridge (LHB) */#define LHB_LINK_BASE 0x40#define LHB_LINKCMD_REG (LHB_LINK_BASE+LDT_COMMAND_CAP_OFF)#define LHB_LINKCTRL_REG (LHB_LINK_BASE+LDT_LINK_OFF(0))#define LHB_LINKCTRL_CRCERROR (1 << LDT_LINKCTRL_CRCERROR_SHIFT)#define LHB_LINKCTRL_ERRORS (LHB_LINKCTRL_CRCERROR | \ LDT_LINKCTRL_LINKFAIL)#define LHB_LINKFREQ_REG (LHB_LINK_BASE+LDT_FREQ_OFF)#define LHB_LFREQ_REG (LHB_LINKFREQ_REG+1)#define LHB_LFREQ_200 LDT_FREQ_200 /* 200 MHz */#define LHB_LFREQ_300 LDT_FREQ_300 /* 300 MHz */#define LHB_LFREQ_400 LDT_FREQ_400 /* 400 MHz */#define LHB_LFREQ_500 LDT_FREQ_500 /* 500 MHz */#define LHB_LFREQ_600 LDT_FREQ_600 /* 600 MHz */#define LHB_LFREQ_800 LDT_FREQ_800 /* 800 MHz */#define LHB_SRI_CMD_REG 0x50#define LHB_SRI_CMD_SIPREADY (1 << 16)#define LHB_SRI_CMD_SYNCPTRCTL (1 << 17)#define LHB_SRI_CMD_REDUCESYNCZERO (1 << 18)#define LHB_SRI_CMD_DISSTARVATIONCNT (1 << 19)#define LHB_SRI_CMD_RXMARGIN_SHIFT 20#define LHB_SRI_CMD_RXMARGIN_MASK (0x1F << LHB_SRI_CMD_RXMARGIN_SHIFT)#define LHB_SRI_CMD_PLLCOMPAT (1 << 25)#define LHB_SRI_CMD_TXOFFSET_SHIFT 28#define LHB_SRI_CMD_TXOFFSET_MASK (0x7 << LHB_SRI_CMD_TXOFFSET_SHIFT)#define LHB_SRI_CMD_LINKFREQDIRECT (1 << 31)#define LHB_SRI_TXNUM_REG 0x54#define LHB_SRI_RXNUM_REG 0x58#define LHB_ERR_CTRL_REG 0x68#define LHB_ERR_CTRL 0x00FFFFFF#define LHB_ERR_STATUS 0xFF000000#define LHB_SRI_CTRL_REG 0x6C#define LHB_ASTAT_REG 0x70#define LHB_ASTAT_TGTDONE_SHIFT 0#define LHB_ASTAT_TGTDONE_MASK (0xFF << LHB_ASTAT_TGTDONE_SHIFT)#define LHB_TXBUFCNT_REG 0xC8#if (LDT_DEBUG > 1)static voidshow_ldt_status (void){ pcireg_t cmd; cmd = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG); xprintf(" SriCmd %04x\n", (cmd >> 16) & 0xFFFF); xprintf(" TXNum %08x TxDen %02x RxNum %08x RxDen %02x ErrCtl %08x\n", pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_TXNUM_REG), cmd & 0xFF, pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_RXNUM_REG), (cmd >> 8) & 0xFF, pci_conf_read32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG)); xprintf(" LDTCmd %08x LDTCfg %08x LDTFreq %08x\n", pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCMD_REG), pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG), pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKFREQ_REG));}#else#define show_ldt_status() ((void)0)#endif /* LDT_DEBUG *//* * Assert warm reset for the given number of ticks. */static voidlhb_link_reset (int delay){ pcireg_t prev, cmd; pcireg_t brctrl; prev = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCMD_REG); cmd = prev | LDT_COMMAND_WARM_RESET; pci_conf_write32(SB1250_LDT_BRIDGE, LHB_LINKCMD_REG, cmd); brctrl = pci_conf_read32(SB1250_LDT_BRIDGE, PPB_BRCTL_INTERRUPT_REG); brctrl |= PPB_BRCTL_SECONDARY_RESET; pci_conf_write32(SB1250_LDT_BRIDGE, PPB_BRCTL_INTERRUPT_REG, brctrl); cfe_sleep(delay); brctrl &=~ PPB_BRCTL_SECONDARY_RESET; pci_conf_write32(SB1250_LDT_BRIDGE, PPB_BRCTL_INTERRUPT_REG, brctrl); brctrl = pci_conf_read32(SB1250_LDT_BRIDGE, PPB_BRCTL_INTERRUPT_REG); pci_conf_write32(SB1250_LDT_BRIDGE, LHB_LINKCMD_REG, prev);}/* * Poll for InitDone on LHB's outgoing link. */static intlhb_link_ready (int maxpoll){ volatile pcireg_t ctrl; int count; int linkerr; count = 0; linkerr = 0; ctrl = 0; while ((ctrl & (LDT_LINKCTRL_INITDONE | LDT_LINKCTRL_LINKFAIL)) == 0 && count < maxpoll) { ctrl = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG); count++; if ((ctrl & LHB_LINKCTRL_ERRORS) != 0 && !linkerr) { if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "LDT Err, count %d Err = 0x%04x\n", count, ctrl & 0xFFFF); linkerr = 1; } if (count == maxpoll) { if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "Link timeout\n"); linkerr = 1; } } if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "lhb_link_ready: count %d\n", count); return linkerr;}static voidlhb_null_config (void){ /* Even if the LDT fabric is not to be initialized by us, we must write the bus number, base and limit registers in the host bridge for proper operation (see 8.11.1) */ pcireg_t iodata; pcireg_t memdata; /* The primary bus is 0. Set secondary, subordinate to 0 also. */ pci_conf_write32(SB1250_LDT_BRIDGE, PPB_BUSINFO_REG, 0); iodata = pci_conf_read32(SB1250_LDT_BRIDGE, PPB_IO_STATUS_REG); iodata &=~ (PPB_IO_BASE_MASK | PPB_IO_LIMIT_MASK); iodata |= (1 << 4) | (0 << (8+4)); pci_conf_write32(SB1250_LDT_BRIDGE, PPB_IO_STATUS_REG, iodata); iodata = 0x0000F200; /* recommended value */ pci_conf_write32(SB1250_LDT_BRIDGE, PPB_IO_UPPER_REG, iodata); memdata = pci_conf_read32(SB1250_LDT_BRIDGE, PPB_MEM_REG); memdata &=~ (PPB_MEM_BASE_MASK | PPB_MEM_LIMIT_MASK); memdata |= (1 << 4) | (0 << (16+4)); /* empty window */ pci_conf_write32(SB1250_LDT_BRIDGE, PPB_MEM_REG, memdata);}/* * LDT host bridge initialization. */static voidlhb_init (int rev017, unsigned linkfreq, unsigned buffctl){ int i; pcireg_t cr; pcireg_t sri_cmd; volatile pcireg_t t; /* used for reads that push writes */ uint8_t ldt_freq; int linkerr; int retry; sb1250_ldt_init = 0; /* The most recent software advisory for working around PLL startup problems suggests setting LdtPLLCompat, then changing the link frequency to 400 MHz and back. The toggling is to be done "before accessing anything in the HT interface or on the bus (checking for link state, configuration, etc.)", since there is a small chance that a read while the clock is free running could fail with a system hang. Unfortunately, with some revisions of the silicon it's then impossible to test for SipReady already set and warn appropriately. In development environments, the latter seems more useful. In other environments, the following read should be replaced by a suitable constant (see below) and a cold system reset should be done if InitDone fails to set. */ sri_cmd = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG); if ((sri_cmd & LHB_SRI_CMD_SIPREADY) == 0) { /* To bring the PLL into lock, we must set the frequency to 400 MHz and back to 200 MHz in Compat mode before otherwise initializing any of the link registers. */ t = sri_cmd | LHB_SRI_CMD_PLLCOMPAT; pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG, t); cfe_usleep(100); /* Delay, since we don't want to read back. */ pci_conf_write8(SB1250_LDT_BRIDGE, LHB_LFREQ_REG, LHB_LFREQ_400); cfe_sleep (CFE_HZ/2); pci_conf_write8(SB1250_LDT_BRIDGE, LHB_LFREQ_REG, LHB_LFREQ_200); t = pci_conf_read8(SB1250_LDT_BRIDGE, LHB_LFREQ_REG); /* push */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG, sri_cmd); } /* 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 | LHB_ERR_STATUS); cr = pci_conf_read32(SB1250_LDT_BRIDGE, PCI_CLASS_REG); eoi_implemented = (PCI_REVISION(cr) >= 2); /* First set up System Reset Initialization registers (Table 8-12). This code is designed to be run following a full reset. After a chip warm reset (SipReady already set), most of it is skipped. Depending on previous history, that can leave things in an inconsistent state, but there's no recovery from that short of a chip cold reset. */ if (sri_cmd & LHB_SRI_CMD_SIPREADY) { pci_tagprintf(SB1250_LDT_BRIDGE, "Warning: SipReady already set\n"); /* Try just doing a warm reset. */ lhb_link_reset(CFE_HZ/10); goto finish; } if (rev017) { /* LDT 0.17 compatibility mode: SriCmd = (!LinkFreqDirect, LdtPLLCompat, [DisStarveCnt,] TxInitialOffset=5, RxMargin=2, !SipReady) */ sri_cmd = LHB_SRI_CMD_PLLCOMPAT; } else { /* LDT 1.0x partial compatibility mode: SriCmd = (!LinkFreqDirect, !LdtPLLCompat, [DisStarveCnt,] TxInitialOffset=5, RxMargin=2, !SipReady) */ sri_cmd = 0; } /* Empirically, RxMargin is not critical with a 200 MHz LDT clock but must be small (less than 15, and 0 seems reliable) with a 400 MHz LDT clock. Current default is 2. */ sri_cmd |= ((2 << LHB_SRI_CMD_RXMARGIN_SHIFT) | (5 << LHB_SRI_CMD_TXOFFSET_SHIFT) | 0x1010); /* Rx/TxDen defaults */ /* Setting DisStarveCnt is recommended for Pass 1 parts. */ if (PCI_REVISION(cr) == 1) sri_cmd |= LHB_SRI_CMD_DISSTARVATIONCNT; /* Map the link frequency to a supported value. Note: we assume that the CPU and IOB0 clocks are set high enough for the selected frequency. In LDT 0.17 compatibility mode, this is the final frequency. In LDT 1.0x partial compatibility mode, this becomes the target frequency for link sizing. */ if (linkfreq < 200) linkfreq = 200; else if (linkfreq > 800) linkfreq = 800; /* Passes 1 and 2 do not support LINKFREQDIRECT. Force a standard value. */ if (PCI_REVISION(cr) < 3) { linkfreq = ((linkfreq + (50-1))/100) * 100; if (linkfreq == 700) linkfreq = 600; /* No code point */ } else { linkfreq = ((linkfreq + (25-1))/50) * 50; } if (rev017) xprintf("HyperTransport: %d MHz\n", linkfreq); if (linkfreq % 100 == 0 && linkfreq != 700) { /* Encode supported standard values per the LDT spec. */ switch (linkfreq) { default: case 200: ldt_freq = LHB_LFREQ_200; break; case 300: ldt_freq = LHB_LFREQ_300; break; case 400: ldt_freq = LHB_LFREQ_400; break; case 500: ldt_freq = LHB_LFREQ_500; break; case 600: ldt_freq = LHB_LFREQ_600; break; case 800: ldt_freq = LHB_LFREQ_800; break; } } else { /* Compute PLL ratio for 100 MHz reference in 3b1 format (Table 23) */ sri_cmd |= LHB_SRI_CMD_LINKFREQDIRECT; ldt_freq = linkfreq / 50; } pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG, sri_cmd); /* Set the SRI dividers */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_TXNUM_REG, 0x0000FFFF); pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_RXNUM_REG, 0x0000FFFF); t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_RXNUM_REG); /* push */ /* Directed test: SPIN(10) here */ for (i = 0; i < 10; i++) t = pci_conf_read32(SB1250_LDT_BRIDGE, PCI_ID_REG); /* In previous versions of CFE, the Pass 1 workaround for 200 MHz PLL failure was here. See above for a more general solution applicable to all revisions. */ if (rev017) { pci_conf_write8(SB1250_LDT_BRIDGE, LHB_LFREQ_REG, ldt_freq); } /* Set the Error Control register (some fatal interrupts). */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG, 0x00001209); /* Set the SRI Xmit Control register. */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_CTRL_REG, 0x00040000 | buffctl); if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "BuffCtl = 0x%08x\n", pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_CTRL_REG)); /* Set the Tx buffer size (16 buffers each). */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_TXBUFCNT_REG, 0x00FFFFFF); /* Push the writes */ t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_TXBUFCNT_REG); /* push */ /* Indicate SIP Ready */ sri_cmd |= LHB_SRI_CMD_SIPREADY; pci_conf_write32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG, sri_cmd); t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_SRI_CMD_REG); /* push */ retry = (sb1250_ldt_slave_mode ? 4 : 1); for (;;) { /* wait for LinkFail or InitDone */ linkerr = lhb_link_ready(1<<20); /* empirical delay */ t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG); if ((t & LHB_ERR_STATUS) != 0) { linkerr = 1; if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "ErrStat = 0x%02x\n", t >> 24); pci_conf_write32(SB1250_LDT_BRIDGE, LHB_ERR_CTRL_REG, t | LHB_ERR_STATUS); } t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG); if ((t & LHB_LINKCTRL_ERRORS) != 0) { linkerr = 1; if (_pciverbose > PCI_FLG_NORMAL) pci_tagprintf(SB1250_LDT_BRIDGE, "LinkCtrl CRCErr = 0x%01x\n", (t >> 8) & 0xF); } if (!linkerr || retry == 0) break; /* Clear errors in preparation for another try. Delay long enough (below) for CRC errors to reappear; otherwise, the link can look good, but subsequent non-posted transactions will hang. */ t = pci_conf_read32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG); t |= LDT_LINKCTRL_CRCERROR_MASK; /* Clear CrcErr bits */ pci_conf_write32(SB1250_LDT_BRIDGE, LHB_LINKCTRL_REG, t);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -