📄 bcm1480_pci_machdep.c
字号:
M_BCM1480_PHB_FCTRL_MEM_EN); /* PCI: enable bridge to PCI and PCI memory accesses, including write-invalidate, plus error handling */ csr = PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_INVALIDATE_ENABLE | PCI_COMMAND_SERR_ENABLE | PCI_COMMAND_PARITY_ENABLE; pci_conf_write32(BCM1400_PCI_BRIDGE, PCI_COMMAND_STATUS_REG, csr); /* PCI: clear errors */ csr = pci_conf_read32(BCM1400_PCI_BRIDGE, PCI_COMMAND_STATUS_REG); csr |= PCI_STATUS_PARITY_ERROR | PCI_STATUS_SYSTEM_ERROR | PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT | PCI_STATUS_TARGET_TARGET_ABORT | PCI_STATUS_PARITY_DETECT; pci_conf_write32(BCM1400_PCI_BRIDGE, PCI_COMMAND_STATUS_REG, csr); /* PCI: set up interrupt mapping */ icr = pci_conf_read(BCM1400_PCI_BRIDGE, PCI_BPARAM_INTERRUPT_REG); icr &=~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); icr |= (pci_int_line(pci_int_map_0(BCM1400_PCI_BRIDGE)) << PCI_INTERRUPT_LINE_SHIFT); pci_conf_write(BCM1400_PCI_BRIDGE, PCI_BPARAM_INTERRUPT_REG, icr); /* PCI: push the writes */ t = pci_conf_read32(BCM1400_PCI_BRIDGE, PCI_ID_REG); /* PCI: set subsystem id */ id = (PCI_VENDOR_SIBYTE << PCI_VENDOR_SHIFT)|(0x1280 << PCI_PRODUCT_SHIFT); pci_conf_write32(BCM1400_PCI_BRIDGE, R_BCM1480_PHB_SUBSYSSET, id); /* PCI: enable bus-side access */ pci_conf_write32(BCM1400_PCI_BRIDGE, R_BCM1480_PHB_EXTCONFIGDIS, V_BCM1480_PHB_READHOST_DISABLE); t = pci_conf_read32(BCM1400_PCI_BRIDGE, R_BCM1480_PHB_EXTCONFIGDIS);}/* * HT port initialization. See Section 13, pp. 479-480. * * For now, this is minimal initialization copied from csrBackdoors.i * used in DV for HT tests. Rationale for the specific values is * unknown. */#define PORT_MODE_HT(map,port) (((map) & (1 << (port))) != 0)static voidhsp_ram_alloc (int i){ /* HSP: Allocate RX and TX buffers. */ /* NB: Initial silicon has a bug that swaps floor and ceiling in all ramalloc registers. */ /* per the errata */ phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_0), (V_BCM1480_HSP_RX_NPC_CMD_FLOOR(0xA0) | V_BCM1480_HSP_RX_NPC_CMD_CEILING(0xA9))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_1), (V_BCM1480_HSP_RX_PC_CMD_FLOOR(0xC8) | V_BCM1480_HSP_RX_PC_CMD_CEILING(0xD1))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_2), 0); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_3), 0); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_4), (V_BCM1480_HSP_RX_NPC_DAT_FLOOR(0xAA) | V_BCM1480_HSP_RX_NPC_DAT_CEILING(0xB3) | V_BCM1480_HSP_RX_RSP_DAT_FLOOR(0xB4) | V_BCM1480_HSP_RX_RSP_DAT_CEILING(0xC7))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_HT_RAMALLOC_5), (V_BCM1480_HSP_RX_PC_DAT_FLOOR(0xD2) | V_BCM1480_HSP_RX_PC_DAT_CEILING(0xDB))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_NPC_RAMALLOC), V_BCM1480_HSP_TX_NPC_FLOOR(0xA0) | V_BCM1480_HSP_TX_NPC_CEILING(0xB3)); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_RSP_RAMALLOC), V_BCM1480_HSP_TX_RSP_FLOOR(0xB4) | V_BCM1480_HSP_TX_RSP_CEILING(0xC7)); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_PC_RAMALLOC), V_BCM1480_HSP_TX_PC_FLOOR(0xC8) | V_BCM1480_HSP_TX_PC_CEILING(0xDB));}static voidhsp_flow_alloc (int i){ /* HSP: Program the flow control registers. */ phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_HTIO_RXPHITCNT), (V_BCM1480_HSP_RX_NPC_CMD_PHITCNT(0x0A) | V_BCM1480_HSP_RX_NPC_DAT_PHITCNT(0x02) | V_BCM1480_HSP_RX_RSP_DAT_PHITCNT(0x05) | V_BCM1480_HSP_RX_PC_CMD_PHITCNT(0x0A) | V_BCM1480_HSP_RX_PC_DAT_PHITCNT(0x02))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_HTCC_RXPHITCNT), 0); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_HTIO_TXPHITCNT), (V_BCM1480_HSP_TX_NPC_PHITCNT(0x14) | V_BCM1480_HSP_TX_RSP_PHITCNT(0x14) | V_BCM1480_HSP_TX_PC_PHITCNT(0x14))); phys_write64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_TX_HTCC_TXPHITCNT), 0); /* mpl: setting POHT up here */ phys_write64(A_BCM1480_HSP_REGISTER(i,R_BCM1480_HSP_RX_PKT_RAMALLOC(0)), V_BCM1480_HSP_RX_RAMCEILING_0(15)| V_BCM1480_HSP_RX_RAMFLOOR_0(0)); phys_write64(A_BCM1480_HSP_REGISTER(i,R_BCM1480_HSP_TX_PKT_RAMALLOC(0)), V_BCM1480_HSP_TX_RAMCEILING_0(15)| V_BCM1480_HSP_TX_RAMFLOOR_0(0)); phys_write64(A_BCM1480_HSP_REGISTER(i,R_BCM1480_HSP_TX_PKT_RXPHITCNT(0)), V_BCM1480_HSP_RX_PHITCNT_0(16)); phys_write64(A_BCM1480_HSP_REGISTER(i,R_BCM1480_HSP_TX_PKT_TXPHITCNT(0)), V_BCM1480_HSP_TX_PHITCNT_0(16));}static unsigned inthsp_init (void){ int i; unsigned int ht_map; uint64_t cfg; /* HSP: Discover the ports in HT mode. */ ht_map = 0; for (i = 0; i < BCM1480_HT_NUM_PORTS; i++) { cfg = phys_read64(A_BCM1480_HSP_REGISTER(i, R_BCM1480_HSP_RX_SPI4_CFG_0)); if (G_BCM1480_HSP_LINK_MODE(cfg) == K_BCM1480_HSP_LINK_MODE_HT) ht_map |= (1 << i); } /* HSP: Allocate RX and TX buffers. */ for (i = 0; i < BCM1480_HT_NUM_PORTS; i++) { if (PORT_MODE_HT(ht_map, i)) hsp_ram_alloc(i); } /* HSP: Program the flow control registers. */ for (i = 0; i < BCM1480_HT_NUM_PORTS; i++) { if (PORT_MODE_HT(ht_map, i)) hsp_flow_alloc(i); } return ht_map;}/* Implementation-specific definitions for the HT Host Bridge (HTD) Note that this is a bridge to the internal bus and logically appears as a PCI Host Bridge (no HT capabilities) */#define M_BCM1480_HTD_ALL_PORTS(bit) (V_BCM1480_HTD_PORTCTRL_PORT0(bit) | \ V_BCM1480_HTD_PORTCTRL_PORT1(bit) | \ V_BCM1480_HTD_PORTCTRL_PORT2(bit))#define M_BCM1480_HTD_PORTS_ACTIVE (M_BCM1480_HTD_ALL_PORTS(M_BCM1480_HTD_PORT_ACTIVE))#define M_BCM1480_HTD_PORTS_PRIMARY (M_BCM1480_HTD_ALL_PORTS(M_BCM1480_HTD_PORT_IS_PRIMARY))#define M_BCM1480_HTD_PORTS_RESET (M_BCM1480_HTD_ALL_PORTS(M_BCM1480_HTD_PORT_LINK_RESET))#define M_BCM1480_HTD_PORTS_LINKRESET (M_BCM1480_HTD_ALL_PORTS(M_BCM1480_HTD_PORT_LINKRESET_STATUS))static const uint32_t ht_masks[8] = { 0, V_BCM1480_HTD_PORTCTRL_PORT0(0xFF), V_BCM1480_HTD_PORTCTRL_PORT1(0xFF), V_BCM1480_HTD_PORTCTRL_PORT1(0xFF) | V_BCM1480_HTD_PORTCTRL_PORT0(0xFF), V_BCM1480_HTD_PORTCTRL_PORT2(0xFF), V_BCM1480_HTD_PORTCTRL_PORT2(0xFF) | V_BCM1480_HTD_PORTCTRL_PORT0(0xFF), V_BCM1480_HTD_PORTCTRL_PORT2(0xFF) | V_BCM1480_HTD_PORTCTRL_PORT1(0xFF), M_BCM1480_HTD_ALL_PORTS(0xFF)};/* * HT host device initialization. */static unsigned inthtd_init (void){ unsigned int ht_map; int i; int slave_mode; uint32_t ht_mask; pcireg_t csr, icr, id; pcireg_t port_ctl; volatile pcireg_t t; /* used for reads that push writes */ eoi_implemented = 1; /* No EOI bug on the 1400 */ /* HT: configure the high-speed ports. */ ht_map = hsp_init(); /* Convert the bitmap to a register mask. */ ht_mask = ht_masks[ht_map]; /* For now, only port 0 is supported in HT slave mode. */ slave_mode = (bcm1400_ldt_slave_mode && PORT_MODE_HT(ht_map, 0)); /* HT: configure the external bridges. The mode for each is Active, Secondary unless slave mode is selected, in which case bridge 0 is programmed as Active, Primary. */ port_ctl = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL); port_ctl &=~ M_BCM1480_HTD_PORTS_ACTIVE; port_ctl |= ((M_BCM1480_HTD_PORTS_ACTIVE | M_BCM1480_HTD_PORTS_RESET) & ht_mask); port_ctl &=~ (M_BCM1480_HTD_PORTS_PRIMARY & ht_mask); if (slave_mode) port_ctl |= V_BCM1480_HTD_PORTCTRL_PORT0(M_BCM1480_HTD_PORT_IS_PRIMARY); pci_conf_write(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL, port_ctl); t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL); /* HT: set subsystem id */ id = (PCI_VENDOR_SIBYTE << PCI_VENDOR_SHIFT)|(0x1280 << PCI_PRODUCT_SHIFT); pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_SUBSYSSET, id); /* HT: deassert secondary port resets */ port_ctl &=~ (M_BCM1480_HTD_PORTS_RESET & ht_mask); if (slave_mode) port_ctl |= V_BCM1480_HTD_PORTCTRL_PORT0(M_BCM1480_HTD_PORT_LINK_RESET); pci_conf_write(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL, port_ctl); t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL); /* HT: deassert internal bus reset */ t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL); t &=~ (M_BCM1480_HTD_INTBUS_RESET | M_BCM1480_HTD_INTBUS_WARM_R); pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL, t); t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL); /* HT: deassert primary port reset, if any. */ if (slave_mode) { port_ctl &=~ V_BCM1480_HTD_PORTCTRL_PORT0(M_BCM1480_HTD_PORT_LINK_RESET); pci_conf_write(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL, port_ctl); t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL); } /* HT: wait for resets to complete. */ for (i = 1000; i > 0; i--) { t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_PORTSCTRL); if ((t & (M_BCM1480_HTD_PORTS_LINKRESET & ht_mask)) == 0) break; cfe_usleep(1000); } /* check for failure. */ if (i == 0) xprintf("port reset(s) failed to deassert (%08x).\n", t); for (i = 1000; i > 0; i--) { t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL); if ((t & M_BCM1480_HTD_INTBUS_RESET_STATUS) == 0) break; cfe_usleep(100); } /* check for failure. */ if (i == 0) xprintf("internal bus reset(s) failed to deassert (%08x).\n", t); /* HT: disable and clear the BAR0 MAP registers */ for (i = 0; i < HTD_MAPENTRIES; i++) pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_MAP(i), 0); /* HT: XXX Set up the BARs. These are placeholders */ pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_MAPREG(0), 0x60000000); pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_MAPREG(1), 0x00000000); /* POHT */ pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_MAPREG(2), 0x70000000); pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_MAPREG(4), 0x00000000); pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_MAPREG(5), 0x00000000); /* HT: enable a split Low Access Range. */ pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_SPECCMDSTAT, M_BCM1480_HTD_CMD_LOW_RANGE_EN | M_BCM1480_HTD_CMD_LOW_RANGE_SPLIT); /* HT: clear any pending specific error bits (XXX revisit) */ t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL); pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL, t); /* Clear reset to enable programming of BARs. */ t &=~ (M_BCM1480_HTD_INTBUS_RESET | M_BCM1480_HTD_INTBUS_WARM_R); pci_conf_write32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL, t); t = pci_conf_read32(BCM1400_LDT_BRIDGE, R_BCM1480_HTD_INTBUSCTRL); /* HT: null interrupt mapping */ icr = pci_conf_read(BCM1400_LDT_BRIDGE, PCI_BPARAM_INTERRUPT_REG); icr &=~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); icr |= (pci_int_line(0) << PCI_INTERRUPT_LINE_SHIFT); pci_conf_write(BCM1400_LDT_BRIDGE, PCI_BPARAM_INTERRUPT_REG, icr); /* HT: clear errors */ csr = pci_conf_read32(BCM1400_LDT_BRIDGE, PCI_COMMAND_STATUS_REG); csr |= PCI_STATUS_MASTER_ABORT | PCI_STATUS_MASTER_TARGET_ABORT | PCI_STATUS_TARGET_TARGET_ABORT; pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_COMMAND_STATUS_REG, csr); /* HT: enable bridge to internal bus */ csr = PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_COMMAND_STATUS_REG, csr); /* HT: push the writes */ t = pci_conf_read32(BCM1400_LDT_BRIDGE, PCI_ID_REG); return ht_map;}/* * HT external bridge initialization. */static voidhtb_init (unsigned int ht_map, unsigned linkfreq){ unsigned freq_cap; /* bit mask of advertised frequencies */ pcireg_t cap; /* capability register image */ /* Upgrade the frequency capabilities of the external bridges. */ /* Map the maximum requested link frequency to a standard value. */ if (linkfreq < 200) linkfreq = 200; else if (linkfreq > 800) linkfreq = 800; linkfreq = ((linkfreq + (50-1))/100) * 100; /* Encode the capabilities as a bit vector (see Table 171) */ freq_cap = 0x8000; /* Vendor specific (compat mode) */ switch (linkfreq) { /* fall-through logic */ case 800: freq_cap |= (1 << LDT_FREQ_800); case 700: case 600: freq_cap |= (1 << LDT_FREQ_600); case 500: freq_cap |= (1 << LDT_FREQ_500); case 400: freq_cap |= (1 << LDT_FREQ_400); case 300: freq_cap |= (1 << LDT_FREQ_300); default: case 200: freq_cap |= (1 << LDT_FREQ_200); } cap = (V_BCM1480_HTB_SPLINKFREQ_PLLFREQ(0) | V_BCM1480_HTB_SPLINKFREQ_FREQCAPSET(freq_cap)); if (PORT_MODE_HT(ht_map, 0)) pci_conf_write(BCM1400_EXT0_BRIDGE, R_BCM1480_HTB_SPECLINKFREQ, cap); if (PORT_MODE_HT(ht_map, 1)) pci_conf_write(BCM1400_EXT1_BRIDGE, R_BCM1480_HTB_SPECLINKFREQ, cap); if (PORT_MODE_HT(ht_map, 2)) pci_conf_write(BCM1400_EXT2_BRIDGE, R_BCM1480_HTB_SPECLINKFREQ, cap);}/* * Called to initialise the host bridges at the beginning of time. */intpci_hwinit (int port, pci_flags_t flags){ struct host_port *p; int i; unsigned linkfreq, maxfreq; uint64_t syscfg; unsigned pll_div, sw_div; const char *str; unsigned int ht_map; if (port != 0 && port != 1) return -1; p = pci_select_root(port); /* initialise global data */ syscfg = SBREADCSR(A_SCD_SYSTEM_CFG); bcm1400_in_device_mode = ((syscfg & M_BCM1480_SYS_PCI_HOST) == 0); bcm1400_ldt_slave_mode = ((cfe_startflags & CFE_LDT_SLAVE) != 0); /* Check for any relevant environment variables. */ /* Choose the HT link frequency, defaulting to 800 MHz */ str = env_getenv("LDT_LINKFREQ"); linkfreq = (str ? atoi(str) : 800); /* Reduce the default if necessary to the maximum compatible with the CPU and SCLK frequencies (Table 9). */ pll_div = G_BCM1480_SYS_PLL_DIV(syscfg); sw_div = G_BCM1480_SYS_SW_DIV(syscfg); if (pll_div == 0 || sw_div == 0) maxfreq = 200; /* Undefined in Table 9; use HT minimum. */ else { /* See Table 9 for computation of SCLK from the CPU clock. The maximum link frequency is limited to twice SCLK, where. SCLK = (100 * (pll_div/2)) / (sw_div/2) = 100*pll_div/sw_div. */ maxfreq = 2*(100*pll_div)/sw_div; } if (linkfreq > maxfreq) linkfreq = maxfreq; _pci_nbus = 0; _pci_bus[_pci_nbus] = bcm1400_pci_bus; _pci_bus[_pci_nbus].port = port; _pci_nbus++; for (i = _pci_nbus; i < MAXBUS; i++) _pci_bus[i] = secondary_pci_bus; if (port == 0) { /* stop the BCM1400 from servicing any further PCI requests */ pci_conf_write32(BCM1400_PCI_BRIDGE, PCI_COMMAND_STATUS_REG, 0); /* initialize the PCI host bridge */ phb_init(); } else { /* stop the BCM1400 from servicing any further HT requests */ pci_conf_write32(BCM1400_LDT_BRIDGE, PCI_COMMAND_STATUS_REG, 0); /* initialize the HT host bridge */ ht_map = htd_init(); /* initialize the internal HT bridges */ htb_init(ht_map, linkfreq); } 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 bcm1400, perhaps no effect! */ if (port == 0 && _pci_bus[0].fast_b2b) { /* fast back-to-back is supported by all devices */ cmd = pci_conf_read32(BCM1400_PCI_BRIDGE, PCI_COMMAND_STATUS_REG); cmd &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT); /* preserve status */ cmd |= PCI_COMMAND_BACKTOBACK_ENABLE; pci_conf_write32(BCM1400_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. */#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);/* 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. Non-zero return means that no resource assignment should be
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -