/*- * Copyright (c) 2019 - 2020 Soren Schmidt * All rights reseresed. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$Id$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct a37x0_pcie_softc { struct ofw_pci_softc ofw_pci; // must be first struct ofw_pci_range mem_range; struct ofw_pci_range io_range; device_t dev; int ctrl_rid; struct resource *ctrl_res; int irq_rid; struct resource *irq_res; void *irq_handle; }; static struct ofw_compat_data compat_data[] = { {"marvell,armada-3700-pcie", 1}, {NULL, 0} }; // PCIE bus handling stuff #define PCIE_CONF_BUS(bus) (((bus) & PCI_BUSMAX) << 20) #define PCIE_CONF_SLOT(slot) (((slot) & PCI_SLOTMAX) << 15) #define PCIE_CONF_FUNC(func) (((func) & PCI_FUNCMAX) << 12) #define PCIE_CONF_REG(reg) ((reg) & PCIE_REGMAX) #define PCIE_CONF_ADDR(bus, slot, func, reg) \ (PCIE_CONF_BUS(bus) | PCIE_CONF_SLOT(slot) | \ PCIE_CONF_FUNC(func) | PCIE_CONF_REG(reg)) // PCIE config registers #define PCIE_CONFIG_RD_TYPE0 0x8 #define PCIE_CONFIG_RD_TYPE1 0x9 #define PCIE_CONFIG_WR_TYPE0 0xa #define PCIE_CONFIG_WR_TYPE1 0xb // PCIe core registers #define PCIE_CORE_DEV_ID_REG 0x0 #define PCIE_CORE_CMD_STAT_REG 0x4 #define PCIE_CORE_CMD_IO_ACCESS_EN (1<<0) #define PCIE_CORE_CMD_MEM_ACCESS_EN (1<<1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN (1<<2) #define PCIE_CORE_DEV_STAT_REG 0x8 #define PCIE_CORE_PCIEXP_CAP 0xc0 #define PCIE_DEV_CTRL_STATS 0xc8 #define PCIE_DEV_CTRL_STATS_SNOOP (1<<1) #define PCIE_DEV_CTRL_STATS_RELAX_ORDER (1<<4) #define PCIE_DEV_CTRL_STATS_MAX_PAYLOAD (7<<5) #define PCIE_DEV_CTRL_STATS_MAX_RD_REQ_SZ (2<<12) #define PCIE_CORE_LINK_STAT_REG 0xd0 #define PCIE_CORE_ERR_CAPCTL_REG 0x118 #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX (1<<5) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN (1<<6) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK (1<<7) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV (1<<8) #define PCIE_CORE_INT_A_ASSERT_ENABLE 1 #define PCIE_CORE_INT_B_ASSERT_ENABLE 2 #define PCIE_CORE_INT_C_ASSERT_ENABLE 3 #define PCIE_CORE_INT_D_ASSERT_ENABLE 4 // PIO registers #define PIO_BASE_ADDR 0x4000 #define PIO_CTRL (PIO_BASE_ADDR + 0x00) #define PIO_CTRL_TYPE_MASK 0x00000003 #define PIO_CTRL_ADDR_WIN_DISABLE (1<<24) #define PIO_STAT (PIO_BASE_ADDR + 0x04) #define PIO_NON_POSTED_REQ (1<<0) #define PIO_STATUS_MASK ((1<<7) | (1<<8) | (1<<9)) #define PIO_STATUS_OK 0 #define PIO_STATUS_UR (1<<7) #define PIO_STATUS_CRS (1<<8) #define PIO_STATUS_CA (1<<9) #define PIO_ADDR_LS (PIO_BASE_ADDR + 0x08) #define PIO_ADDR_MS (PIO_BASE_ADDR + 0x0c) #define PIO_WR_DATA (PIO_BASE_ADDR + 0x10) #define PIO_WR_DATA_STRB (PIO_BASE_ADDR + 0x14) #define PIO_RD_DATA (PIO_BASE_ADDR + 0x18) #define PIO_START (PIO_BASE_ADDR + 0x1c) #define PIO_ISR (PIO_BASE_ADDR + 0x20) #define PIO_ISRM (PIO_BASE_ADDR + 0x24) // PCIe engine control registers #define CONTROL_BASE_ADDR 0x4800 #define PCIE_CORE_CTRL0_REG (CONTROL_BASE_ADDR + 0x00) #define PCIE_CORE_CTRL0_GEN_1 (0<<0) #define PCIE_CORE_CTRL0_GEN_2 (1<<0) #define PCIE_CORE_CTRL0_GEN_3 (2<<0) #define PCIE_CORE_CTRL0_GEN_MASK (3<<0) #define PCIE_CORE_CTRL0_IS_RC (1<<2) #define PCIE_CORE_CTRL0_LANE_1 (0<<3) #define PCIE_CORE_CTRL0_LANE_2 (1<<3) #define PCIE_CORE_CTRL0_LANE_4 (2<<3) #define PCIE_CORE_CTRL0_LANE_8 (3<<3) #define PCIE_CORE_CTRL0_LANE_MASK (3<<3) #define PCIE_CORE_CTRL0_LINK_TRAINING (1<<6) #define PCIE_CORE_CTRL1_REG (CONTROL_BASE_ADDR + 0x04) #define HOT_RESET_GEN (1<<0) #define PCIE_CORE_CTRL2_REG (CONTROL_BASE_ADDR + 0x08) #define PCIE_CORE_CTRL2_RESERVED (7<<0) #define PCIE_CORE_CTRL2_TD_ENABLE (1<<4) #define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE (1<<5) #define PCIE_CORE_CTRL2_OB_WIN_ENABLE (1<<6) #define PCIE_CORE_CTRL2_MSI_ENABLE (1<<10) #define PCIE_CORE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) #define PCIE_CORE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44) #define PCIE_CORE_ISR0_MASK_MSI_INT (1<<24) #define PCIE_CORE_ISR0_MASK_ALL 0x07ffffff #define PCIE_CORE_ISR0_INTX_ASSERT(x) (i<<((x)+16)) #define PCIE_CORE_ISR0_INTX_DEASSERT(x) (i<<((x)+20)) #define PCIE_CORE_ISR1_REG (CONTROL_BASE_ADDR + 0x48) #define PCIE_CORE_ISR1_MASK_REG (CONTROL_BASE_ADDR + 0x4C) #define PCIE_CORE_ISR1_MASK_ALL 0x00000ff0 #define PCIE_CORE_ISR1_INTX_ASSERT(x) (1<<((x)+8)) #define PCIE_CORE_MSI_ADDR_LOW (CONTROL_BASE_ADDR + 0x50) #define PCIE_CORE_MSI_ADDR_HIGH (CONTROL_BASE_ADDR + 0x54) #define PCIE_CORE_MSI_STAT_REG (CONTROL_BASE_ADDR + 0x58) #define PCIE_CORE_MSI_MASK_REG (CONTROL_BASE_ADDR + 0x5C) #define PCIE_CORE_PAYLOAD_REG (CONTROL_BASE_ADDR + 0x9C) // LMI registers #define LMI_BASE_ADDR 0x6000 #define CFG_REG LMI_BASE_ADDR + 0x0 #define LTSSM_MASK 0x3f000000 #define LTSSM_L0 0x10000000 // PCIe core controller registers #define CTRL_CORE_BASE_ADDR 0x18000 #define CTRL_CONFIG_REG (CTRL_CORE_BASE_ADDR + 0x00) #define CTRL_MODE_SHIFT 0x0 #define CTRL_MODE_MASK 0x1 #define PCIE_CORE_MODE_DIRECT 0x0 #define PCIE_CORE_MODE_COMMAND 0x1 // PCIe Central Interrupt registers #define CENTRAL_INT_BASE_ADDR 0x1b000 #define HOST_CTRL_INT_STAT_REG (CENTRAL_INT_BASE_ADDR + 0x0) #define HOST_CTRL_INT_MASK_REG (CENTRAL_INT_BASE_ADDR + 0x4) #define PCIE_IRQ_CMDQ_INT (1<<0) #define PCIE_IRQ_MSI_STATUS_INT (1<<1) #define PCIE_IRQ_CMD_SENT_DONE (1<<3) #define PCIE_IRQ_DMA_INT (1<<4) #define PCIE_IRQ_IB_DXFERDONE (1<<5) #define PCIE_IRQ_OB_DXFERDONE (1<<6) #define PCIE_IRQ_OB_RXFERDONE (1<<7) #define PCIE_IRQ_COMPQ_INT (1<<12) #define PCIE_IRQ_DIR_RD_DDR_DET (1<<13) #define PCIE_IRQ_DIR_WR_DDR_DET (1<<14) #define PCIE_IRQ_CORE_INT (1<<16) #define PCIE_IRQ_CORE_INT_PIO (1<<17) #define PCIE_IRQ_DPMU_INT (1<<18) #define PCIE_IRQ_PCIE_MIS_INT (1<<19) #define PCIE_IRQ_MSI_INT1_DET (1<<20) #define PCIE_IRQ_MSI_INT2_DET (1<<21) #define PCIE_IRQ_RC_DBELL_DET (1<<22) #define PCIE_IRQ_EP_STATUS (1<<23) #define PCIE_IRQ_ALL_MASK 0xfff0fb #define PCIE_IRQ_ENABLE_INTS_MASK PCIE_IRQ_CORE_INT static int a37x0_pcie_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return ENXIO; if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return ENXIO; device_set_desc(dev, "Marvell Armada 37x0 PCI-express controller"); return BUS_PROBE_DEFAULT; } static void a37x0_intr(void *data) { struct a37x0_pcie_softc *sc = data; uint32_t status; status = bus_read_4(sc->ctrl_res, HOST_CTRL_INT_STAT_REG); if (!(status & PCIE_IRQ_ENABLE_INTS_MASK)) return; // Clear (all) interrupts bus_write_4(sc->ctrl_res, PCIE_CORE_ISR0_REG, PCIE_CORE_ISR0_MASK_ALL); bus_write_4(sc->ctrl_res, PCIE_CORE_ISR1_REG, PCIE_CORE_ISR1_MASK_ALL); bus_write_4(sc->ctrl_res, HOST_CTRL_INT_STAT_REG, status); } static int a37x0_pcie_attach(device_t dev) { struct a37x0_pcie_softc *sc = device_get_softc(dev); uint32_t reg; int i, res = 0; sc->dev = dev; // Setup access to memory mapped controller registers sc->ctrl_rid = 0; if (!(sc->ctrl_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->ctrl_rid, RF_ACTIVE))) { device_printf(dev, "could not map controller memory\n"); return ENXIO; } // Setup controller interrupt sc->irq_rid = 0; if (!(sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE))) { device_printf(dev, "could not map controller interrupt\n"); bus_release_resource(dev, SYS_RES_MEMORY, sc->ctrl_rid, sc->ctrl_res); return ENXIO; } if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, a37x0_intr, sc, &sc->irq_handle))) { device_printf(dev, "unable to setup interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); bus_release_resource(dev, SYS_RES_MEMORY, sc->ctrl_rid, sc->ctrl_res); return ENXIO; } if ((res = ofw_pci_init(dev))) goto out; // Look for the ranges we need/support for (i = 0; i < sc->ofw_pci.sc_nrange; i++) { if ((sc->ofw_pci.sc_range[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == OFW_PCI_PHYS_HI_SPACE_IO) { if (sc->io_range.size != 0) { device_printf(sc->dev, "Only 1 IO range supported\n"); res = ENXIO; goto out; } sc->io_range = sc->ofw_pci.sc_range[i]; if (bootverbose) device_printf(dev, "IO pci_addr=0x%jx cpu_addr=0x%jx size=0x%jx\n", sc->io_range.pci, sc->io_range.host, sc->io_range.size); } else { if (sc->mem_range.size != 0) { device_printf(dev, "Only 1 memory range supported\n"); res = ENXIO; goto out; } sc->mem_range = sc->ofw_pci.sc_range[i]; if (bootverbose) device_printf(dev, "MEM pci_addr=0x%jx cpu_addr=0x%jx size=0x%jx\n", sc->mem_range.pci, sc->mem_range.host, sc->mem_range.size); } } if (!sc->mem_range.size && !sc->io_range.size) { device_printf(dev, "io & memory range not defined in FDT\n"); res = ENXIO; goto out; } // Set direct mode reg = bus_read_4(sc->ctrl_res, CTRL_CONFIG_REG); reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT); reg |= ((PCIE_CORE_MODE_DIRECT & CTRL_MODE_MASK) << CTRL_MODE_SHIFT); bus_write_4(sc->ctrl_res, CTRL_CONFIG_REG, reg); // Set PCI global control register to RC mode reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG); reg |= PCIE_CORE_CTRL0_IS_RC; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG, reg); // Set Advanced Error Capabilities and Control PF0 register reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX | PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN | PCIE_CORE_ERR_CAPCTL_ECRC_CHCK | PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV; bus_write_4(sc->ctrl_res, PCIE_CORE_ERR_CAPCTL_REG, reg); // Set PCIe Device Control register reg = PCIE_DEV_CTRL_STATS_MAX_PAYLOAD; reg |= PCIE_DEV_CTRL_STATS_MAX_RD_REQ_SZ; bus_write_4(sc->ctrl_res, PCIE_DEV_CTRL_STATS, reg); // Program PCIe Control 2 to disable strict ordering reg = PCIE_CORE_CTRL2_RESERVED | PCIE_CORE_CTRL2_TD_ENABLE; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL2_REG, reg); // Set lane GEN2/X1 reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG); reg &= ~PCIE_CORE_CTRL0_GEN_MASK; reg |= PCIE_CORE_CTRL0_GEN_2; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG, reg); reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG); reg &= ~PCIE_CORE_CTRL0_LANE_MASK; reg |= PCIE_CORE_CTRL0_LANE_1; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL0_REG, reg); // Disable MSI reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CTRL2_REG); reg &= ~PCIE_CORE_CTRL2_MSI_ENABLE; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL2_REG, reg); // Clear all interrupts bus_write_4(sc->ctrl_res, PCIE_CORE_ISR0_REG, PCIE_CORE_ISR0_MASK_ALL); bus_write_4(sc->ctrl_res, PCIE_CORE_ISR1_REG, PCIE_CORE_ISR1_MASK_ALL); bus_write_4(sc->ctrl_res, HOST_CTRL_INT_STAT_REG, PCIE_IRQ_ALL_MASK); // Enable all ISR0/1 sources // mayhabs just interrupts that we need ? bus_write_4(sc->ctrl_res, PCIE_CORE_ISR0_MASK_REG, 0); bus_write_4(sc->ctrl_res, PCIE_CORE_ISR1_MASK_REG, 0); // Mask all MSI sources bus_write_4(sc->ctrl_res, PCIE_CORE_MSI_MASK_REG, ~0); // Enable summary interrupt for GIC SPI sources reg = PCIE_IRQ_ALL_MASK & ~PCIE_IRQ_ENABLE_INTS_MASK; bus_write_4(sc->ctrl_res, HOST_CTRL_INT_MASK_REG, reg); // Bypass the address window mapping for PIO reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CTRL2_REG); reg |= PCIE_CORE_CTRL2_OB_WIN_ENABLE; bus_write_4(sc->ctrl_res, PCIE_CORE_CTRL2_REG, reg); reg = bus_read_4(sc->ctrl_res, PIO_CTRL); reg |= PIO_CTRL_ADDR_WIN_DISABLE; bus_write_4(sc->ctrl_res, PIO_CTRL, reg); // Enable IO/MEM access reg = bus_read_4(sc->ctrl_res, PCIE_CORE_CMD_STAT_REG); reg |= PCIE_CORE_CMD_MEM_ACCESS_EN | PCIE_CORE_CMD_IO_ACCESS_EN | PCIE_CORE_CMD_MEM_IO_REQ_EN; bus_write_4(sc->ctrl_res, PCIE_CORE_CMD_STAT_REG, reg); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); out: return res; } static struct resource * a37x0_pcie_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct a37x0_pcie_softc *sc = device_get_softc(dev); struct ofw_pci_range *pr = NULL; struct rman *rm = NULL; struct resource *res; switch (type) { case SYS_RES_IRQ: return sc->irq_res; case SYS_RES_IOPORT: rm = &sc->ofw_pci.sc_io_rman; pr = &sc->io_range; break; case SYS_RES_MEMORY: rm = &sc->ofw_pci.sc_mem_rman; pr = &sc->mem_range; break; #ifdef PCI_RES_BUS case PCI_RES_BUS: return (pci_domain_alloc_bus(0, child, rid, start, end, count, flags)); #endif default: return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid, start, end, count, flags); } if (RMAN_IS_DEFAULT_RANGE(start, end)) { start = pr->pci; end = pr->pci + pr->size - 1; count = pr->size; } if ((start < pr->pci) || (start + count - 1 != end) || (end > pr->pci + pr->size - 1)) return NULL; if (!(res = rman_reserve_resource(rm, start, end, count, flags, child))) return NULL; rman_set_rid(res, *rid); if (flags & RF_ACTIVE && bus_activate_resource(child, type, *rid, res)) { rman_release_resource(res); return NULL; } return res; } static int a37x0_pcie_release_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { #ifdef PCI_RES_BUS if (type == PCI_RES_BUS) return (pci_domain_release_bus(0, child, rid, res)); #endif if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, res)); return rman_release_resource(res); } static int a37x0_pcie_maxslots(device_t dev) { return 1; } static int a37x0_pcie_wait_pio(struct a37x0_pcie_softc *sc) { uint32_t start, isr; int i; for (i = 0; i < 100; i++) { start = bus_read_4(sc->ctrl_res, PIO_START); isr = bus_read_4(sc->ctrl_res, PIO_ISR); if (!start && isr) return 0; DELAY(10); } device_printf(sc->dev, "config read/write timed out\n"); return -1; } static void a37x0_pcie_pio_status(struct a37x0_pcie_softc *sc) { uint32_t val; char *strcomp_status, *str_posted; val = bus_read_4(sc->ctrl_res, PIO_STAT); switch (val & PIO_STATUS_MASK) { case PIO_STATUS_OK: return; case PIO_STATUS_UR: strcomp_status = "UR"; break; case PIO_STATUS_CRS: strcomp_status = "CRS"; break; case PIO_STATUS_CA: strcomp_status = "CA"; break; default: strcomp_status = "Unknown"; break; } if (val & PIO_NON_POSTED_REQ) str_posted = "Non-posted"; else str_posted = "Posted"; device_printf(sc->dev, "%s PIO response status %s reg=%#x @%#x\n", str_posted, strcomp_status, val, bus_read_4(sc->ctrl_res, PIO_ADDR_LS)); } static uint32_t a37x0_pcie_hw_cfgread(struct a37x0_pcie_softc *sc, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { uint32_t val; // Start PIO process bus_write_4(sc->ctrl_res, PIO_START, 0); bus_write_4(sc->ctrl_res, PIO_ISR, 1); // Set the control register val = bus_read_4(sc->ctrl_res, PIO_CTRL); val &= ~PIO_CTRL_TYPE_MASK; val |= PCIE_CONFIG_RD_TYPE0; bus_write_4(sc->ctrl_res, PIO_CTRL, val); // Program the address registers val = PCIE_CONF_ADDR(bus, slot, func, reg); bus_write_4(sc->ctrl_res, PIO_ADDR_LS, val); bus_write_4(sc->ctrl_res, PIO_ADDR_MS, 0); // Set data strobe bus_write_4(sc->ctrl_res, PIO_WR_DATA_STRB, 0x0000000f); // Start the transfer bus_write_4(sc->ctrl_res, PIO_START, 1); if (a37x0_pcie_wait_pio(sc) < 0) return ~0; if (1 || bootverbose) a37x0_pcie_pio_status(sc); // Translate result val = bus_read_4(sc->ctrl_res, PIO_RD_DATA); if (bytes == 1) return (val >> ((reg & 3) << 3)) & 0xff; else if (bytes == 2) return (val >> ((reg & 3) << 3)) & 0xffff; else return val; } static void a37x0_pcie_hw_cfgwrite(struct a37x0_pcie_softc *sc, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { uint32_t val; // Start PIO process bus_write_4(sc->ctrl_res, PIO_START, 0); bus_write_4(sc->ctrl_res, PIO_ISR, 1); // Set control register val = bus_read_4(sc->ctrl_res, PIO_CTRL); val &= ~PIO_CTRL_TYPE_MASK; val |= PCIE_CONFIG_RD_TYPE0; bus_write_4(sc->ctrl_res, PIO_CTRL, val); // Set address registers val = PCIE_CONF_ADDR(bus, slot, func, reg); bus_write_4(sc->ctrl_res, PIO_ADDR_LS, val); bus_write_4(sc->ctrl_res, PIO_ADDR_MS, 0); // Set data register contents bus_write_4(sc->ctrl_res, PIO_WR_DATA, data << ((reg & 0x3) << 3)); // Set data strobe if (bytes == 1) val = 0xff; else if (bytes == 2) val = 0xffff; else val = 0xffffffff; bus_write_4(sc->ctrl_res, PIO_WR_DATA_STRB, val << ((reg & 0x3) << 3)); // Start the transfer bus_write_4(sc->ctrl_res, PIO_START, 1); if (a37x0_pcie_wait_pio(sc) < 0) device_printf(sc->dev, "hw_cfgwrite failed\n"); if (1 || bootverbose) a37x0_pcie_pio_status(sc); } static uint32_t a37x0_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct a37x0_pcie_softc *sc = device_get_softc(dev); // Return ~0 if link is inactive or trying to read from root if (((bus_read_4(sc->ctrl_res, CFG_REG) & LTSSM_MASK) < LTSSM_L0) || !slot) return ~0; return (a37x0_pcie_hw_cfgread(sc, bus, slot, func, reg, bytes)); } static void a37x0_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { struct a37x0_pcie_softc *sc = device_get_softc(dev); // Return if link is inactive or trying to write to root if (((bus_read_4(sc->ctrl_res, CFG_REG) & LTSSM_MASK) < LTSSM_L0) || !slot) return; a37x0_pcie_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes); } // Device method table. static device_method_t a37x0_pcie_methods[] = { // device interface DEVMETHOD(device_probe, a37x0_pcie_probe), DEVMETHOD(device_attach, a37x0_pcie_attach), //DEVMETHOD(device_release, a37x0_pcie_release), // bus interface DEVMETHOD(bus_alloc_resource, a37x0_pcie_alloc_resource), DEVMETHOD(bus_release_resource, a37x0_pcie_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), // pcib interface DEVMETHOD(pcib_maxslots, a37x0_pcie_maxslots), DEVMETHOD(pcib_read_config, a37x0_pcie_read_config), DEVMETHOD(pcib_write_config, a37x0_pcie_write_config), DEVMETHOD_END }; DEFINE_CLASS_1(pcib, a37x0_pcie_driver, a37x0_pcie_methods, sizeof(struct a37x0_pcie_softc), ofw_pci_driver); static devclass_t a37x0_pcie_devclass; DRIVER_MODULE(mv_pcie, simplebus, a37x0_pcie_driver, a37x0_pcie_devclass, NULL, NULL);