diff options
author | jmallett <jmallett@FreeBSD.org> | 2011-01-11 02:37:58 +0000 |
---|---|---|
committer | jmallett <jmallett@FreeBSD.org> | 2011-01-11 02:37:58 +0000 |
commit | d204f90ffeee44ead70c0909b723dc89499d29c4 (patch) | |
tree | b8e956d1eded58f2aa519c54d14567a42b15f919 | |
parent | 3e5f77d5aa1822ec5f6d0c353c36a4c256d4aa7e (diff) | |
download | FreeBSD-src-d204f90ffeee44ead70c0909b723dc89499d29c4.zip FreeBSD-src-d204f90ffeee44ead70c0909b723dc89499d29c4.tar.gz |
Initialize PCIe buses and add preliminary support for 64-bit BARs.
-rw-r--r-- | sys/mips/cavium/octopci.c | 536 |
1 files changed, 321 insertions, 215 deletions
diff --git a/sys/mips/cavium/octopci.c b/sys/mips/cavium/octopci.c index d065ae3..8477321 100644 --- a/sys/mips/cavium/octopci.c +++ b/sys/mips/cavium/octopci.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org> + * Copyright (c) 2010-2011 Juli Mallett <jmallett@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <contrib/octeon-sdk/cvmx.h> #include <contrib/octeon-sdk/cvmx-interrupt.h> +#include <contrib/octeon-sdk/cvmx-pcie.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -70,9 +71,11 @@ struct octopci_softc { unsigned sc_domain; unsigned sc_bus; + bus_addr_t sc_io_base; unsigned sc_io_next; struct rman sc_io; + bus_addr_t sc_mem1_base; unsigned sc_mem1_next; struct rman sc_mem1; }; @@ -92,25 +95,33 @@ static void octopci_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int octopci_route_interrupt(device_t, device_t, int); -static void octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *); +static unsigned octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *); static unsigned octopci_init_device(device_t, unsigned, unsigned, unsigned, unsigned); static unsigned octopci_init_bus(device_t, unsigned); +static void octopci_init_pci(device_t); static uint64_t octopci_cs_addr(unsigned, unsigned, unsigned, unsigned); static void octopci_identify(driver_t *drv, device_t parent) { + /* XXX Check sysinfo flag. */ + BUS_ADD_CHILD(parent, 0, "pcib", 0); + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) + BUS_ADD_CHILD(parent, 0, "pcib", 1); } static int octopci_probe(device_t dev) { + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { + device_set_desc(dev, "Cavium Octeon PCIe bridge"); + return (0); + } + if (device_get_unit(dev) != 0) return (ENXIO); - if (octeon_has_feature(OCTEON_FEATURE_PCIE)) - return (ENXIO); - /* XXX Check sysinfo flag. */ + device_set_desc(dev, "Cavium Octeon PCI bridge"); return (0); } @@ -119,214 +130,47 @@ static int octopci_attach(device_t dev) { struct octopci_softc *sc; - cvmx_npi_mem_access_subid_t npi_mem_access_subid; - cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg; - cvmx_npi_ctl_status_t npi_ctl_status; - cvmx_pci_ctl_status_2_t pci_ctl_status_2; - cvmx_pci_cfg56_t pci_cfg56; - cvmx_pci_cfg22_t pci_cfg22; - cvmx_pci_cfg16_t pci_cfg16; - cvmx_pci_cfg19_t pci_cfg19; - cvmx_pci_cfg01_t pci_cfg01; unsigned subbus; - unsigned i; int error; - /* - * Reset the PCI bus. - */ - cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1); - cvmx_read_csr(CVMX_CIU_SOFT_PRST); - - DELAY(2000); - - npi_ctl_status.u64 = 0; - npi_ctl_status.s.max_word = 1; - npi_ctl_status.s.timer = 1; - cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64); - - /* - * Set host mode. - */ - switch (cvmx_sysinfo_get()->board_type) { -#if defined(OCTEON_VENDOR_LANNER) - case CVMX_BOARD_TYPE_CUST_LANNER_MR320: - case CVMX_BOARD_TYPE_CUST_LANNER_MR955: - /* 32-bit PCI-X */ - cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0); - break; -#endif - default: - /* 64-bit PCI-X */ - cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); - break; - } - cvmx_read_csr(CVMX_CIU_SOFT_PRST); - - DELAY(2000); - - /* - * Enable BARs and configure big BAR mode. - */ - pci_ctl_status_2.u32 = 0; - pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */ - pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */ - pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */ - pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */ - pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */ - pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */ - pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */ - pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */ - pci_ctl_status_2.s.tsr_hwm = 1; - pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */ - pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */ - pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */ + sc = device_get_softc(dev); + sc->sc_dev = dev; - NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32); + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { + sc->sc_domain = device_get_unit(dev); - DELAY(2000); + error = cvmx_pcie_rc_initialize(sc->sc_domain); + if (error != 0) { + device_printf(dev, "Failed to put PCIe bus in host mode.\n"); + return (ENXIO); + } - pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2); + /* + * In RC mode, the Simple Executive programs the first bus to + * be numbered as bus 1, because some IDT bridges used in + * Octeon systems object to being attached to bus 0. + */ + sc->sc_bus = 1; - device_printf(dev, "%u-bit PCI%s bus.\n", - pci_ctl_status_2.s.ap_64ad ? 64 : 32, - pci_ctl_status_2.s.ap_pcix ? "-X" : ""); + sc->sc_io_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(sc->sc_domain)); + sc->sc_io.rm_descr = "Cavium Octeon PCIe I/O Ports"; - /* - * Set up transaction splitting, etc., parameters. - */ - pci_cfg19.u32 = 0; - pci_cfg19.s.mrbcm = 1; - if (pci_ctl_status_2.s.ap_pcix) { - pci_cfg19.s.mdrrmc = 0; - pci_cfg19.s.tdomc = 4; + sc->sc_mem1_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_mem_base_address(sc->sc_domain)); + sc->sc_mem1.rm_descr = "Cavium Octeon PCIe Memory"; } else { - pci_cfg19.s.mdrrmc = 2; - pci_cfg19.s.tdomc = 1; - } - NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32); - NPI_READ(CVMX_NPI_PCI_CFG19); + octopci_init_pci(dev); - /* - * Set up PCI error handling and memory access. - */ - pci_cfg01.u32 = 0; - pci_cfg01.s.fbbe = 1; - pci_cfg01.s.see = 1; - pci_cfg01.s.pee = 1; - pci_cfg01.s.me = 1; - pci_cfg01.s.msae = 1; - if (pci_ctl_status_2.s.ap_pcix) { - pci_cfg01.s.fbb = 0; - } else { - pci_cfg01.s.fbb = 1; - } - NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32); - NPI_READ(CVMX_NPI_PCI_CFG01); - - /* - * Enable the Octeon bus arbiter. - */ - npi_pci_int_arb_cfg.u64 = 0; - npi_pci_int_arb_cfg.s.en = 1; - cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64); - - /* - * Disable master latency timer. - */ - pci_cfg16.u32 = 0; - pci_cfg16.s.mltd = 1; - NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32); - NPI_READ(CVMX_NPI_PCI_CFG16); - - /* - * Configure master arbiter. - */ - pci_cfg22.u32 = 0; - pci_cfg22.s.flush = 1; - pci_cfg22.s.mrv = 255; - NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32); - NPI_READ(CVMX_NPI_PCI_CFG22); - - /* - * Set up PCI-X capabilities. - */ - if (pci_ctl_status_2.s.ap_pcix) { - pci_cfg56.u32 = 0; - pci_cfg56.s.most = 3; - pci_cfg56.s.roe = 1; /* Enable relaxed ordering */ - pci_cfg56.s.dpere = 1; - pci_cfg56.s.ncp = 0xe8; - pci_cfg56.s.pxcid = 7; - NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32); - NPI_READ(CVMX_NPI_PCI_CFG56); - } - - NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22); - NPI_READ(CVMX_NPI_PCI_READ_CMD_6); - NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33); - NPI_READ(CVMX_NPI_PCI_READ_CMD_C); - NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33); - NPI_READ(CVMX_NPI_PCI_READ_CMD_E); - - /* - * Configure MEM1 sub-DID access. - */ - npi_mem_access_subid.u64 = 0; - npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */ - npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */ - switch (cvmx_sysinfo_get()->board_type) { -#if defined(OCTEON_VENDOR_LANNER) - case CVMX_BOARD_TYPE_CUST_LANNER_MR955: - npi_mem_access_subid.s.shortl = 1; - break; -#endif - default: - break; - } - cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64); + sc->sc_domain = 0; + sc->sc_bus = 0; - /* - * Configure BAR2. Linux says this has to come first. - */ - NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000); - NPI_READ(CVMX_NPI_PCI_CFG08); - NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080); - NPI_READ(CVMX_NPI_PCI_CFG09); + sc->sc_io_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO)); + sc->sc_io.rm_descr = "Cavium Octeon PCI I/O Ports"; - /* - * Disable BAR1 IndexX. - */ - for (i = 0; i < 32; i++) { - NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0); - NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i)); + sc->sc_mem1_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1)); + sc->sc_mem1.rm_descr = "Cavium Octeon PCI Memory"; } - /* - * Configure BAR0 and BAR1. - */ - NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000); - NPI_READ(CVMX_NPI_PCI_CFG04); - NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000); - NPI_READ(CVMX_NPI_PCI_CFG05); - - NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000); - NPI_READ(CVMX_NPI_PCI_CFG06); - NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000); - NPI_READ(CVMX_NPI_PCI_CFG07); - - /* - * Clear PCI interrupts. - */ - cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull); - - sc = device_get_softc(dev); - sc->sc_dev = dev; - sc->sc_domain = 0; - sc->sc_bus = 0; - sc->sc_io.rm_type = RMAN_ARRAY; - sc->sc_io.rm_descr = "Cavium Octeon PCI I/O Ports"; error = rman_init(&sc->sc_io); if (error != 0) return (error); @@ -337,7 +181,6 @@ octopci_attach(device_t dev) return (error); sc->sc_mem1.rm_type = RMAN_ARRAY; - sc->sc_mem1.rm_descr = "Cavium Octeon PCI Memory"; error = rman_init(&sc->sc_mem1); if (error != 0) return (error); @@ -356,11 +199,11 @@ octopci_attach(device_t dev) /* * Configure devices. */ - octopci_write_config(dev, 0, 0, 0, PCIR_SUBBUS_1, 0xff, 1); - subbus = octopci_init_bus(dev, 0); - octopci_write_config(dev, 0, 0, 0, PCIR_SUBBUS_1, subbus, 1); + octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, 0xff, 1); + subbus = octopci_init_bus(dev, sc->sc_bus); + octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, subbus, 1); - device_add_child(dev, "pci", 0); + device_add_child(dev, "pci", device_get_unit(dev)); return (bus_generic_attach(dev)); } @@ -421,10 +264,10 @@ octopci_alloc_resource(device_t bus, device_t child, int type, int *rid, switch (type) { case SYS_RES_MEMORY: - rman_set_bushandle(res, CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1)) + rman_get_start(res)); + rman_set_bushandle(res, sc->sc_mem1_base + rman_get_start(res)); break; case SYS_RES_IOPORT: - rman_set_bushandle(res, CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO)) + rman_get_start(res)); + rman_set_bushandle(res, sc->sc_io_base + rman_get_start(res)); #if __mips_n64 rman_set_virtual(res, (void *)rman_get_bushandle(res)); #else @@ -496,6 +339,22 @@ octopci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, sc = device_get_softc(dev); + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { + if (bus == 0 && slot == 0 && func == 0) + return ((uint32_t)-1); + + switch (bytes) { + case 4: + return (cvmx_pcie_config_read32(sc->sc_domain, bus, slot, func, reg)); + case 2: + return (cvmx_pcie_config_read16(sc->sc_domain, bus, slot, func, reg)); + case 1: + return (cvmx_pcie_config_read8(sc->sc_domain, bus, slot, func, reg)); + default: + return ((uint32_t)-1); + } + } + addr = octopci_cs_addr(bus, slot, func, reg); switch (bytes) { @@ -522,6 +381,22 @@ octopci_write_config(device_t dev, u_int bus, u_int slot, u_int func, sc = device_get_softc(dev); + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { + switch (bytes) { + case 4: + cvmx_pcie_config_write32(sc->sc_domain, bus, slot, func, reg, data); + return; + case 2: + cvmx_pcie_config_write16(sc->sc_domain, bus, slot, func, reg, data); + return; + case 1: + cvmx_pcie_config_write8(sc->sc_domain, bus, slot, func, reg, data); + return; + default: + return; + } + } + addr = octopci_cs_addr(bus, slot, func, reg); switch (bytes) { @@ -548,6 +423,9 @@ octopci_route_interrupt(device_t dev, device_t child, int pin) sc = device_get_softc(dev); + if (octeon_has_feature(OCTEON_FEATURE_PCIE)) + return (CVMX_IRQ_PCI_INT0 + pin - 1); + bus = pci_get_bus(child); slot = pci_get_slot(child); func = pci_get_function(child); @@ -586,12 +464,13 @@ octopci_route_interrupt(device_t dev, device_t child, int pin) return (CVMX_IRQ_PCI_INT0 + (irq & 3)); } -static void +static unsigned octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barnum, uint8_t *commandp) { struct octopci_softc *sc; - uint32_t bar; + uint64_t bar; unsigned size; + int barsize; sc = device_get_softc(dev); @@ -599,12 +478,10 @@ octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barn bar = octopci_read_config(dev, b, s, f, PCIR_BAR(barnum), 4); if (bar == 0) { - /* Bar not implemented. */ - return; + /* Bar not implemented; got to next bar. */ + return (barnum + 1); } - /* XXX Some of this is wrong for 64-bit busses. */ - if (PCI_BAR_IO(bar)) { size = ~(bar & PCIM_BAR_IO_BASE) + 1; @@ -612,7 +489,7 @@ octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barn if (sc->sc_io_next + size > CVMX_OCT_PCI_IO_SIZE) { device_printf(dev, "%02x.%02x:%02x: no ports for BAR%u.\n", b, s, f, barnum); - return; + return (barnum + 1); } octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), CVMX_OCT_PCI_IO_BASE + sc->sc_io_next, 4); @@ -622,14 +499,37 @@ octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barn * Enable I/O ports. */ *commandp |= PCIM_CMD_PORTEN; + + return (barnum + 1); } else { + if (PCIR_BAR(barnum) == PCIR_BIOS) { + /* + * ROM BAR is always 32-bit. + */ + barsize = 1; + } else { + switch (bar & PCIM_BAR_MEM_TYPE) { + case PCIM_BAR_MEM_64: + /* + * XXX + * High 32 bits are all zeroes for now. + */ + octopci_write_config(dev, b, s, f, PCIR_BAR(barnum + 1), 0, 4); + barsize = 2; + break; + default: + barsize = 1; + break; + } + } + size = ~(bar & (uint32_t)PCIM_BAR_MEM_BASE) + 1; sc->sc_mem1_next = (sc->sc_mem1_next + size - 1) & ~(size - 1); if (sc->sc_mem1_next + size > CVMX_OCT_PCI_MEM1_SIZE) { device_printf(dev, "%02x.%02x:%02x: no memory for BAR%u.\n", b, s, f, barnum); - return; + return (barnum + barsize); } octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), CVMX_OCT_PCI_MEM1_BASE + sc->sc_mem1_next, 4); @@ -639,6 +539,8 @@ octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barn * Enable memory access. */ *commandp |= PCIM_CMD_MEMEN; + + return (barnum + barsize); } } @@ -680,8 +582,9 @@ octopci_init_device(device_t dev, unsigned b, unsigned s, unsigned f, unsigned s return (secbus); } - for (barnum = 0; barnum < bars; barnum++) - octopci_init_bar(dev, b, s, f, barnum, &command); + barnum = 0; + while (barnum < bars) + barnum = octopci_init_bar(dev, b, s, f, barnum, &command); /* Enable bus mastering. */ command |= PCIM_CMD_BUSMASTEREN; @@ -848,6 +751,209 @@ octopci_cs_addr(unsigned bus, unsigned slot, unsigned func, unsigned reg) return (pci_addr.u64); } +static void +octopci_init_pci(device_t dev) +{ + cvmx_npi_mem_access_subid_t npi_mem_access_subid; + cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg; + cvmx_npi_ctl_status_t npi_ctl_status; + cvmx_pci_ctl_status_2_t pci_ctl_status_2; + cvmx_pci_cfg56_t pci_cfg56; + cvmx_pci_cfg22_t pci_cfg22; + cvmx_pci_cfg16_t pci_cfg16; + cvmx_pci_cfg19_t pci_cfg19; + cvmx_pci_cfg01_t pci_cfg01; + unsigned i; + + /* + * Reset the PCI bus. + */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1); + cvmx_read_csr(CVMX_CIU_SOFT_PRST); + + DELAY(2000); + + npi_ctl_status.u64 = 0; + npi_ctl_status.s.max_word = 1; + npi_ctl_status.s.timer = 1; + cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64); + + /* + * Set host mode. + */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR320: + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + /* 32-bit PCI-X */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0); + break; +#endif + default: + /* 64-bit PCI-X */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); + break; + } + cvmx_read_csr(CVMX_CIU_SOFT_PRST); + + DELAY(2000); + + /* + * Enable BARs and configure big BAR mode. + */ + pci_ctl_status_2.u32 = 0; + pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */ + pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */ + pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */ + pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */ + pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */ + pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */ + pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */ + pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */ + pci_ctl_status_2.s.tsr_hwm = 1; + pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */ + pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */ + pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */ + + NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32); + + DELAY(2000); + + pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2); + + device_printf(dev, "%u-bit PCI%s bus.\n", + pci_ctl_status_2.s.ap_64ad ? 64 : 32, + pci_ctl_status_2.s.ap_pcix ? "-X" : ""); + + /* + * Set up transaction splitting, etc., parameters. + */ + pci_cfg19.u32 = 0; + pci_cfg19.s.mrbcm = 1; + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg19.s.mdrrmc = 0; + pci_cfg19.s.tdomc = 4; + } else { + pci_cfg19.s.mdrrmc = 2; + pci_cfg19.s.tdomc = 1; + } + NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32); + NPI_READ(CVMX_NPI_PCI_CFG19); + + /* + * Set up PCI error handling and memory access. + */ + pci_cfg01.u32 = 0; + pci_cfg01.s.fbbe = 1; + pci_cfg01.s.see = 1; + pci_cfg01.s.pee = 1; + pci_cfg01.s.me = 1; + pci_cfg01.s.msae = 1; + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg01.s.fbb = 0; + } else { + pci_cfg01.s.fbb = 1; + } + NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32); + NPI_READ(CVMX_NPI_PCI_CFG01); + + /* + * Enable the Octeon bus arbiter. + */ + npi_pci_int_arb_cfg.u64 = 0; + npi_pci_int_arb_cfg.s.en = 1; + cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64); + + /* + * Disable master latency timer. + */ + pci_cfg16.u32 = 0; + pci_cfg16.s.mltd = 1; + NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32); + NPI_READ(CVMX_NPI_PCI_CFG16); + + /* + * Configure master arbiter. + */ + pci_cfg22.u32 = 0; + pci_cfg22.s.flush = 1; + pci_cfg22.s.mrv = 255; + NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32); + NPI_READ(CVMX_NPI_PCI_CFG22); + + /* + * Set up PCI-X capabilities. + */ + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg56.u32 = 0; + pci_cfg56.s.most = 3; + pci_cfg56.s.roe = 1; /* Enable relaxed ordering */ + pci_cfg56.s.dpere = 1; + pci_cfg56.s.ncp = 0xe8; + pci_cfg56.s.pxcid = 7; + NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32); + NPI_READ(CVMX_NPI_PCI_CFG56); + } + + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22); + NPI_READ(CVMX_NPI_PCI_READ_CMD_6); + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33); + NPI_READ(CVMX_NPI_PCI_READ_CMD_C); + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33); + NPI_READ(CVMX_NPI_PCI_READ_CMD_E); + + /* + * Configure MEM1 sub-DID access. + */ + npi_mem_access_subid.u64 = 0; + npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */ + npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + npi_mem_access_subid.s.shortl = 1; + break; +#endif + default: + break; + } + cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64); + + /* + * Configure BAR2. Linux says this has to come first. + */ + NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG08); + NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080); + NPI_READ(CVMX_NPI_PCI_CFG09); + + /* + * Disable BAR1 IndexX. + */ + for (i = 0; i < 32; i++) { + NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0); + NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i)); + } + + /* + * Configure BAR0 and BAR1. + */ + NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG04); + NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG05); + + NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000); + NPI_READ(CVMX_NPI_PCI_CFG06); + NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG07); + + /* + * Clear PCI interrupts. + */ + cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull); +} + static device_method_t octopci_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octopci_identify), |