126abae3fSMichal Meloun /*- 226abae3fSMichal Meloun * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 326abae3fSMichal Meloun * 426abae3fSMichal Meloun * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> 526abae3fSMichal Meloun * 626abae3fSMichal Meloun * Redistribution and use in source and binary forms, with or without 726abae3fSMichal Meloun * modification, are permitted provided that the following conditions 826abae3fSMichal Meloun * are met: 926abae3fSMichal Meloun * 1. Redistributions of source code must retain the above copyright 1026abae3fSMichal Meloun * notice, this list of conditions and the following disclaimer. 1126abae3fSMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 1226abae3fSMichal Meloun * notice, this list of conditions and the following disclaimer in the 1326abae3fSMichal Meloun * documentation and/or other materials provided with the distribution. 1426abae3fSMichal Meloun * 1526abae3fSMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1626abae3fSMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1726abae3fSMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1826abae3fSMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1926abae3fSMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2026abae3fSMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2126abae3fSMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2226abae3fSMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2326abae3fSMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2426abae3fSMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2526abae3fSMichal Meloun * SUCH DAMAGE. 2626abae3fSMichal Meloun * 2726abae3fSMichal Meloun */ 2826abae3fSMichal Meloun 2926abae3fSMichal Meloun /* Base class for all Synopsys DesignWare PCI/PCIe drivers */ 3026abae3fSMichal Meloun 3126abae3fSMichal Meloun #include <sys/cdefs.h> 3226abae3fSMichal Meloun __FBSDID("$FreeBSD$"); 3326abae3fSMichal Meloun 3426abae3fSMichal Meloun #include <sys/param.h> 3526abae3fSMichal Meloun #include <sys/systm.h> 3626abae3fSMichal Meloun #include <sys/bus.h> 3726abae3fSMichal Meloun #include <sys/devmap.h> 3826abae3fSMichal Meloun #include <sys/proc.h> 3926abae3fSMichal Meloun #include <sys/kernel.h> 4026abae3fSMichal Meloun #include <sys/lock.h> 4126abae3fSMichal Meloun #include <sys/malloc.h> 4226abae3fSMichal Meloun #include <sys/module.h> 4326abae3fSMichal Meloun #include <sys/mutex.h> 4426abae3fSMichal Meloun #include <sys/rman.h> 4526abae3fSMichal Meloun 4626abae3fSMichal Meloun #include <machine/bus.h> 4726abae3fSMichal Meloun #include <machine/intr.h> 4826abae3fSMichal Meloun #include <machine/resource.h> 4926abae3fSMichal Meloun 5026abae3fSMichal Meloun #include <dev/ofw/ofw_bus.h> 5126abae3fSMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 5226abae3fSMichal Meloun #include <dev/ofw/ofw_pci.h> 5326abae3fSMichal Meloun #include <dev/ofw/ofwpci.h> 5426abae3fSMichal Meloun #include <dev/pci/pcivar.h> 5526abae3fSMichal Meloun #include <dev/pci/pcireg.h> 5626abae3fSMichal Meloun #include <dev/pci/pcib_private.h> 5726abae3fSMichal Meloun #include <dev/pci/pci_dw.h> 5826abae3fSMichal Meloun 5926abae3fSMichal Meloun #include "pcib_if.h" 6026abae3fSMichal Meloun #include "pci_dw_if.h" 6126abae3fSMichal Meloun 6226abae3fSMichal Meloun #define DEBUG 6326abae3fSMichal Meloun #ifdef DEBUG 6426abae3fSMichal Meloun #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 6526abae3fSMichal Meloun #else 6626abae3fSMichal Meloun #define debugf(fmt, args...) 6726abae3fSMichal Meloun #endif 6826abae3fSMichal Meloun 6926abae3fSMichal Meloun #define DBI_WR1(sc, reg, val) pci_dw_dbi_wr1((sc)->dev, reg, val) 7026abae3fSMichal Meloun #define DBI_WR2(sc, reg, val) pci_dw_dbi_wr2((sc)->dev, reg, val) 7126abae3fSMichal Meloun #define DBI_WR4(sc, reg, val) pci_dw_dbi_wr4((sc)->dev, reg, val) 7226abae3fSMichal Meloun #define DBI_RD1(sc, reg) pci_dw_dbi_rd1((sc)->dev, reg) 7326abae3fSMichal Meloun #define DBI_RD2(sc, reg) pci_dw_dbi_rd2((sc)->dev, reg) 7426abae3fSMichal Meloun #define DBI_RD4(sc, reg) pci_dw_dbi_rd4((sc)->dev, reg) 7526abae3fSMichal Meloun 76*f240dfffSJessica Clarke #define IATU_UR_WR4(sc, reg, val) \ 77*f240dfffSJessica Clarke bus_write_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg), (val)) 78*f240dfffSJessica Clarke #define IATU_UR_RD4(sc, reg) \ 79*f240dfffSJessica Clarke bus_read_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg)) 80*f240dfffSJessica Clarke 8126abae3fSMichal Meloun #define PCI_BUS_SHIFT 20 8226abae3fSMichal Meloun #define PCI_SLOT_SHIFT 15 8326abae3fSMichal Meloun #define PCI_FUNC_SHIFT 12 8426abae3fSMichal Meloun #define PCI_BUS_MASK 0xFF 8526abae3fSMichal Meloun #define PCI_SLOT_MASK 0x1F 8626abae3fSMichal Meloun #define PCI_FUNC_MASK 0x07 8726abae3fSMichal Meloun #define PCI_REG_MASK 0xFFF 8826abae3fSMichal Meloun 8926abae3fSMichal Meloun #define IATU_CFG_BUS(bus) ((uint64_t)((bus) & 0xff) << 24) 9026abae3fSMichal Meloun #define IATU_CFG_SLOT(slot) ((uint64_t)((slot) & 0x1f) << 19) 9126abae3fSMichal Meloun #define IATU_CFG_FUNC(func) ((uint64_t)((func) & 0x07) << 16) 9226abae3fSMichal Meloun 9326abae3fSMichal Meloun static uint32_t 9426abae3fSMichal Meloun pci_dw_dbi_read(device_t dev, u_int reg, int width) 9526abae3fSMichal Meloun { 9626abae3fSMichal Meloun struct pci_dw_softc *sc; 9726abae3fSMichal Meloun 9826abae3fSMichal Meloun sc = device_get_softc(dev); 9926abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 10026abae3fSMichal Meloun 10126abae3fSMichal Meloun switch (width) { 10226abae3fSMichal Meloun case 4: 10326abae3fSMichal Meloun return (bus_read_4(sc->dbi_res, reg)); 10426abae3fSMichal Meloun case 2: 10526abae3fSMichal Meloun return (bus_read_2(sc->dbi_res, reg)); 10626abae3fSMichal Meloun case 1: 10726abae3fSMichal Meloun return (bus_read_1(sc->dbi_res, reg)); 10826abae3fSMichal Meloun default: 10926abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 11026abae3fSMichal Meloun return (0xFFFFFFFF); 11126abae3fSMichal Meloun } 11226abae3fSMichal Meloun } 11326abae3fSMichal Meloun 11426abae3fSMichal Meloun static void 11526abae3fSMichal Meloun pci_dw_dbi_write(device_t dev, u_int reg, uint32_t val, int width) 11626abae3fSMichal Meloun { 11726abae3fSMichal Meloun struct pci_dw_softc *sc; 11826abae3fSMichal Meloun 11926abae3fSMichal Meloun sc = device_get_softc(dev); 12026abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 12126abae3fSMichal Meloun 12226abae3fSMichal Meloun switch (width) { 12326abae3fSMichal Meloun case 4: 12426abae3fSMichal Meloun bus_write_4(sc->dbi_res, reg, val); 12526abae3fSMichal Meloun break; 12626abae3fSMichal Meloun case 2: 12726abae3fSMichal Meloun bus_write_2(sc->dbi_res, reg, val); 12826abae3fSMichal Meloun break; 12926abae3fSMichal Meloun case 1: 13026abae3fSMichal Meloun bus_write_1(sc->dbi_res, reg, val); 13126abae3fSMichal Meloun break; 13226abae3fSMichal Meloun default: 13326abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 13426abae3fSMichal Meloun break; 13526abae3fSMichal Meloun } 13626abae3fSMichal Meloun } 13726abae3fSMichal Meloun 13826abae3fSMichal Meloun static void 13926abae3fSMichal Meloun pci_dw_dbi_protect(struct pci_dw_softc *sc, bool protect) 14026abae3fSMichal Meloun { 14126abae3fSMichal Meloun uint32_t reg; 14226abae3fSMichal Meloun 14326abae3fSMichal Meloun reg = DBI_RD4(sc, DW_MISC_CONTROL_1); 14426abae3fSMichal Meloun if (protect) 14526abae3fSMichal Meloun reg &= ~DBI_RO_WR_EN; 14626abae3fSMichal Meloun else 14726abae3fSMichal Meloun reg |= DBI_RO_WR_EN; 14826abae3fSMichal Meloun DBI_WR4(sc, DW_MISC_CONTROL_1, reg); 14926abae3fSMichal Meloun } 15026abae3fSMichal Meloun 15126abae3fSMichal Meloun static bool 15226abae3fSMichal Meloun pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int slot, u_int func, 15326abae3fSMichal Meloun u_int reg) 15426abae3fSMichal Meloun { 15526abae3fSMichal Meloun bool status; 15626abae3fSMichal Meloun int rv; 15726abae3fSMichal Meloun 15826abae3fSMichal Meloun if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX || 1591f446a11SMichal Meloun func > PCI_FUNCMAX || reg > PCIE_REGMAX) 16026abae3fSMichal Meloun return (false); 16126abae3fSMichal Meloun 16226abae3fSMichal Meloun /* link is needed for access to all non-root busses */ 16326abae3fSMichal Meloun if (bus != sc->root_bus) { 16426abae3fSMichal Meloun rv = PCI_DW_GET_LINK(sc->dev, &status); 16526abae3fSMichal Meloun if (rv != 0 || !status) 16626abae3fSMichal Meloun return (false); 16726abae3fSMichal Meloun return (true); 16826abae3fSMichal Meloun } 16926abae3fSMichal Meloun 17026abae3fSMichal Meloun /* we have only 1 device with 1 function root port */ 17126abae3fSMichal Meloun if (slot > 0 || func > 0) 17226abae3fSMichal Meloun return (false); 17326abae3fSMichal Meloun return (true); 17426abae3fSMichal Meloun } 17526abae3fSMichal Meloun 176*f240dfffSJessica Clarke static bool 177*f240dfffSJessica Clarke pci_dw_detect_atu_unroll(struct pci_dw_softc *sc) 178*f240dfffSJessica Clarke { 179*f240dfffSJessica Clarke return (DBI_RD4(sc, DW_IATU_VIEWPORT) == 0xFFFFFFFFU); 180*f240dfffSJessica Clarke } 181*f240dfffSJessica Clarke 18226abae3fSMichal Meloun static int 183*f240dfffSJessica Clarke pci_dw_map_out_atu_unroll(struct pci_dw_softc *sc, int idx, int type, 184*f240dfffSJessica Clarke uint64_t pa, uint64_t pci_addr, uint32_t size) 185*f240dfffSJessica Clarke { 186*f240dfffSJessica Clarke uint32_t reg; 187*f240dfffSJessica Clarke int i; 188*f240dfffSJessica Clarke 189*f240dfffSJessica Clarke if (size == 0) 190*f240dfffSJessica Clarke return (0); 191*f240dfffSJessica Clarke 192*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_BASE_ADDR), 193*f240dfffSJessica Clarke pa & 0xFFFFFFFF); 194*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_BASE_ADDR), 195*f240dfffSJessica Clarke (pa >> 32) & 0xFFFFFFFF); 196*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LIMIT_ADDR), 197*f240dfffSJessica Clarke (pa + size - 1) & 0xFFFFFFFF); 198*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_TARGET_ADDR), 199*f240dfffSJessica Clarke pci_addr & 0xFFFFFFFF); 200*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_TARGET_ADDR), 201*f240dfffSJessica Clarke (pci_addr >> 32) & 0xFFFFFFFF); 202*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL1), 203*f240dfffSJessica Clarke IATU_CTRL1_TYPE(type)); 204*f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL2), 205*f240dfffSJessica Clarke IATU_CTRL2_REGION_EN); 206*f240dfffSJessica Clarke 207*f240dfffSJessica Clarke /* Wait until setup becomes valid */ 208*f240dfffSJessica Clarke for (i = 10; i > 0; i--) { 209*f240dfffSJessica Clarke reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(idx, CTRL2)); 210*f240dfffSJessica Clarke if (reg & IATU_CTRL2_REGION_EN) 211*f240dfffSJessica Clarke return (0); 212*f240dfffSJessica Clarke DELAY(5); 213*f240dfffSJessica Clarke } 214*f240dfffSJessica Clarke 215*f240dfffSJessica Clarke device_printf(sc->dev, 216*f240dfffSJessica Clarke "Cannot map outbound region %d in unroll mode iATU\n", idx); 217*f240dfffSJessica Clarke return (ETIMEDOUT); 218*f240dfffSJessica Clarke } 219*f240dfffSJessica Clarke 220*f240dfffSJessica Clarke static int 221*f240dfffSJessica Clarke pci_dw_map_out_atu_legacy(struct pci_dw_softc *sc, int idx, int type, 22226abae3fSMichal Meloun uint64_t pa, uint64_t pci_addr, uint32_t size) 22326abae3fSMichal Meloun { 22426abae3fSMichal Meloun uint32_t reg; 22526abae3fSMichal Meloun int i; 22626abae3fSMichal Meloun 22726abae3fSMichal Meloun if (size == 0) 22826abae3fSMichal Meloun return (0); 22926abae3fSMichal Meloun 23026abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(idx)); 23126abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_BASE_ADDR, pa & 0xFFFFFFFF); 23226abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_BASE_ADDR, (pa >> 32) & 0xFFFFFFFF); 23326abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LIMIT_ADDR, (pa + size - 1) & 0xFFFFFFFF); 23426abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, pci_addr & 0xFFFFFFFF); 23526abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_TARGET_ADDR, (pci_addr >> 32) & 0xFFFFFFFF); 23626abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL1, IATU_CTRL1_TYPE(type)); 23726abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL2, IATU_CTRL2_REGION_EN); 23826abae3fSMichal Meloun 23926abae3fSMichal Meloun /* Wait until setup becomes valid */ 24026abae3fSMichal Meloun for (i = 10; i > 0; i--) { 24126abae3fSMichal Meloun reg = DBI_RD4(sc, DW_IATU_CTRL2); 24226abae3fSMichal Meloun if (reg & IATU_CTRL2_REGION_EN) 24326abae3fSMichal Meloun return (0); 24426abae3fSMichal Meloun DELAY(5); 24526abae3fSMichal Meloun } 246*f240dfffSJessica Clarke 24726abae3fSMichal Meloun device_printf(sc->dev, 248*f240dfffSJessica Clarke "Cannot map outbound region %d in legacy mode iATU\n", idx); 24926abae3fSMichal Meloun return (ETIMEDOUT); 25026abae3fSMichal Meloun } 25126abae3fSMichal Meloun 252*f240dfffSJessica Clarke /* Map one outbound ATU region */ 253*f240dfffSJessica Clarke static int 254*f240dfffSJessica Clarke pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type, 255*f240dfffSJessica Clarke uint64_t pa, uint64_t pci_addr, uint32_t size) 256*f240dfffSJessica Clarke { 257*f240dfffSJessica Clarke if (sc->iatu_ur_res) 258*f240dfffSJessica Clarke return (pci_dw_map_out_atu_unroll(sc, idx, type, pa, 259*f240dfffSJessica Clarke pci_addr, size)); 260*f240dfffSJessica Clarke else 261*f240dfffSJessica Clarke return (pci_dw_map_out_atu_legacy(sc, idx, type, pa, 262*f240dfffSJessica Clarke pci_addr, size)); 263*f240dfffSJessica Clarke } 264*f240dfffSJessica Clarke 26526abae3fSMichal Meloun static int 26626abae3fSMichal Meloun pci_dw_setup_hw(struct pci_dw_softc *sc) 26726abae3fSMichal Meloun { 26826abae3fSMichal Meloun uint32_t reg; 269f8c1701fSJessica Clarke int rv, i; 27026abae3fSMichal Meloun 27126abae3fSMichal Meloun pci_dw_dbi_protect(sc, false); 27226abae3fSMichal Meloun 27326abae3fSMichal Meloun /* Setup config registers */ 27426abae3fSMichal Meloun DBI_WR1(sc, PCIR_CLASS, PCIC_BRIDGE); 27526abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); 27626abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(0), 4); 27726abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(1), 0); 27826abae3fSMichal Meloun DBI_WR1(sc, PCIR_INTPIN, 1); 27926abae3fSMichal Meloun DBI_WR1(sc, PCIR_PRIBUS_1, sc->root_bus); 28026abae3fSMichal Meloun DBI_WR1(sc, PCIR_SECBUS_1, sc->sub_bus); 28126abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBBUS_1, sc->bus_end); 28226abae3fSMichal Meloun DBI_WR2(sc, PCIR_COMMAND, 28326abae3fSMichal Meloun PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | 28426abae3fSMichal Meloun PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN); 28526abae3fSMichal Meloun pci_dw_dbi_protect(sc, true); 28626abae3fSMichal Meloun 287f8c1701fSJessica Clarke /* Setup outbound memory windows */ 288f8c1701fSJessica Clarke for (i = 0; i < min(sc->num_mem_ranges, sc->num_viewport - 1); ++i) { 289f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, i + 1, IATU_CTRL1_TYPE_MEM, 290f8c1701fSJessica Clarke sc->mem_ranges[i].host, sc->mem_ranges[i].pci, 291f8c1701fSJessica Clarke sc->mem_ranges[i].size); 29226abae3fSMichal Meloun if (rv != 0) 29326abae3fSMichal Meloun return (rv); 29426abae3fSMichal Meloun } 295f8c1701fSJessica Clarke 296f8c1701fSJessica Clarke /* If we have enough viewports ..*/ 297f8c1701fSJessica Clarke if (sc->num_mem_ranges + 1 < sc->num_viewport && 298f8c1701fSJessica Clarke sc->io_range.size != 0) { 299f8c1701fSJessica Clarke /* Setup outbound I/O window */ 300f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, sc->num_mem_ranges + 1, 301f8c1701fSJessica Clarke IATU_CTRL1_TYPE_IO, sc->io_range.host, sc->io_range.pci, 302f8c1701fSJessica Clarke sc->io_range.size); 303f8c1701fSJessica Clarke if (rv != 0) 304f8c1701fSJessica Clarke return (rv); 305f8c1701fSJessica Clarke } 30626abae3fSMichal Meloun 30726abae3fSMichal Meloun /* Adjust number of lanes */ 30826abae3fSMichal Meloun reg = DBI_RD4(sc, DW_PORT_LINK_CTRL); 30926abae3fSMichal Meloun reg &= ~PORT_LINK_CAPABLE(~0); 31026abae3fSMichal Meloun switch (sc->num_lanes) { 31126abae3fSMichal Meloun case 1: 31226abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_1); 31326abae3fSMichal Meloun break; 31426abae3fSMichal Meloun case 2: 31526abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_2); 31626abae3fSMichal Meloun break; 31726abae3fSMichal Meloun case 4: 31826abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_4); 31926abae3fSMichal Meloun break; 32026abae3fSMichal Meloun case 8: 32126abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_8); 32226abae3fSMichal Meloun break; 32326abae3fSMichal Meloun case 16: 32426abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_16); 32526abae3fSMichal Meloun break; 32626abae3fSMichal Meloun case 32: 32726abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_32); 32826abae3fSMichal Meloun break; 32926abae3fSMichal Meloun default: 33026abae3fSMichal Meloun device_printf(sc->dev, 33126abae3fSMichal Meloun "'num-lanes' property have invalid value: %d\n", 33226abae3fSMichal Meloun sc->num_lanes); 33326abae3fSMichal Meloun return (EINVAL); 33426abae3fSMichal Meloun } 33526abae3fSMichal Meloun DBI_WR4(sc, DW_PORT_LINK_CTRL, reg); 33626abae3fSMichal Meloun 33726abae3fSMichal Meloun /* And link width */ 33826abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 33926abae3fSMichal Meloun reg &= ~GEN2_CTRL_NUM_OF_LANES(~0); 34026abae3fSMichal Meloun switch (sc->num_lanes) { 34126abae3fSMichal Meloun case 1: 34226abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_1); 34326abae3fSMichal Meloun break; 34426abae3fSMichal Meloun case 2: 34526abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_2); 34626abae3fSMichal Meloun break; 34726abae3fSMichal Meloun case 4: 34826abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_4); 34926abae3fSMichal Meloun break; 35026abae3fSMichal Meloun case 8: 35126abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_8); 35226abae3fSMichal Meloun break; 35326abae3fSMichal Meloun case 16: 35426abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_16); 35526abae3fSMichal Meloun break; 35626abae3fSMichal Meloun case 32: 35726abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_32); 35826abae3fSMichal Meloun break; 35926abae3fSMichal Meloun } 36026abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 36126abae3fSMichal Meloun 36226abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 36326abae3fSMichal Meloun reg |= DIRECT_SPEED_CHANGE; 36426abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 36526abae3fSMichal Meloun 36626abae3fSMichal Meloun return (0); 36726abae3fSMichal Meloun } 36826abae3fSMichal Meloun 36926abae3fSMichal Meloun static int 37026abae3fSMichal Meloun pci_dw_decode_ranges(struct pci_dw_softc *sc, struct ofw_pci_range *ranges, 37126abae3fSMichal Meloun int nranges) 37226abae3fSMichal Meloun { 373f8c1701fSJessica Clarke int i, nmem, rv; 37426abae3fSMichal Meloun 375f8c1701fSJessica Clarke nmem = 0; 376f8c1701fSJessica Clarke for (i = 0; i < nranges; i++) { 377f8c1701fSJessica Clarke if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 378f8c1701fSJessica Clarke OFW_PCI_PHYS_HI_SPACE_MEM32) 379f8c1701fSJessica Clarke ++nmem; 380f8c1701fSJessica Clarke } 381f8c1701fSJessica Clarke 382f8c1701fSJessica Clarke sc->mem_ranges = malloc(nmem * sizeof(*sc->mem_ranges), M_DEVBUF, 383f8c1701fSJessica Clarke M_WAITOK); 384f8c1701fSJessica Clarke sc->num_mem_ranges = nmem; 385f8c1701fSJessica Clarke 386f8c1701fSJessica Clarke nmem = 0; 38726abae3fSMichal Meloun for (i = 0; i < nranges; i++) { 38826abae3fSMichal Meloun if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 38926abae3fSMichal Meloun OFW_PCI_PHYS_HI_SPACE_IO) { 39026abae3fSMichal Meloun if (sc->io_range.size != 0) { 39126abae3fSMichal Meloun device_printf(sc->dev, 39226abae3fSMichal Meloun "Duplicated IO range found in DT\n"); 393f8c1701fSJessica Clarke rv = ENXIO; 394f8c1701fSJessica Clarke goto out; 39526abae3fSMichal Meloun } 396f8c1701fSJessica Clarke 39726abae3fSMichal Meloun sc->io_range = ranges[i]; 398243000b1SWojciech Macek if (sc->io_range.size > UINT32_MAX) { 399243000b1SWojciech Macek device_printf(sc->dev, 400f8c1701fSJessica Clarke "ATU IO window size is too large. " 401f8c1701fSJessica Clarke "Up to 4GB windows are supported, " 402f8c1701fSJessica Clarke "trimming window size to 4GB\n"); 403243000b1SWojciech Macek sc->io_range.size = UINT32_MAX; 404243000b1SWojciech Macek } 405243000b1SWojciech Macek } 406f8c1701fSJessica Clarke if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 407f8c1701fSJessica Clarke OFW_PCI_PHYS_HI_SPACE_MEM32) { 408f8c1701fSJessica Clarke MPASS(nmem < sc->num_mem_ranges); 409f8c1701fSJessica Clarke sc->mem_ranges[nmem] = ranges[i]; 410f8c1701fSJessica Clarke if (sc->mem_ranges[nmem].size > UINT32_MAX) { 411f8c1701fSJessica Clarke device_printf(sc->dev, 412f8c1701fSJessica Clarke "ATU MEM window size is too large. " 413f8c1701fSJessica Clarke "Up to 4GB windows are supported, " 414f8c1701fSJessica Clarke "trimming window size to 4GB\n"); 415f8c1701fSJessica Clarke sc->mem_ranges[nmem].size = UINT32_MAX; 416f8c1701fSJessica Clarke } 417f8c1701fSJessica Clarke ++nmem; 418f8c1701fSJessica Clarke } 419f8c1701fSJessica Clarke } 420f8c1701fSJessica Clarke 421f8c1701fSJessica Clarke MPASS(nmem == sc->num_mem_ranges); 422f8c1701fSJessica Clarke 423f8c1701fSJessica Clarke if (nmem == 0) { 424f8c1701fSJessica Clarke device_printf(sc->dev, 425f8c1701fSJessica Clarke "Missing required memory range in DT\n"); 426f8c1701fSJessica Clarke return (ENXIO); 427f8c1701fSJessica Clarke } 428f8c1701fSJessica Clarke 42926abae3fSMichal Meloun return (0); 430f8c1701fSJessica Clarke 431f8c1701fSJessica Clarke out: 432f8c1701fSJessica Clarke free(sc->mem_ranges, M_DEVBUF); 433f8c1701fSJessica Clarke return (rv); 43426abae3fSMichal Meloun } 43526abae3fSMichal Meloun 43626abae3fSMichal Meloun /*----------------------------------------------------------------------------- 43726abae3fSMichal Meloun * 43826abae3fSMichal Meloun * P C I B I N T E R F A C E 43926abae3fSMichal Meloun */ 44026abae3fSMichal Meloun 44126abae3fSMichal Meloun static uint32_t 44226abae3fSMichal Meloun pci_dw_read_config(device_t dev, u_int bus, u_int slot, 44326abae3fSMichal Meloun u_int func, u_int reg, int bytes) 44426abae3fSMichal Meloun { 44526abae3fSMichal Meloun struct pci_dw_softc *sc; 44626abae3fSMichal Meloun struct resource *res; 44726abae3fSMichal Meloun uint32_t data; 44826abae3fSMichal Meloun uint64_t addr; 44926abae3fSMichal Meloun int type, rv; 45026abae3fSMichal Meloun 45126abae3fSMichal Meloun sc = device_get_softc(dev); 45226abae3fSMichal Meloun 45326abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 45426abae3fSMichal Meloun return (0xFFFFFFFFU); 45526abae3fSMichal Meloun 45626abae3fSMichal Meloun if (bus == sc->root_bus) { 45726abae3fSMichal Meloun res = (sc->dbi_res); 45826abae3fSMichal Meloun } else { 45926abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 46026abae3fSMichal Meloun IATU_CFG_FUNC(func); 46126abae3fSMichal Meloun if (bus == sc->sub_bus) 46226abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 46326abae3fSMichal Meloun else 46426abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 465f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, 0, type, 46626abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 46726abae3fSMichal Meloun if (rv != 0) 46826abae3fSMichal Meloun return (0xFFFFFFFFU); 46926abae3fSMichal Meloun res = sc->cfg_res; 47026abae3fSMichal Meloun } 47126abae3fSMichal Meloun 47226abae3fSMichal Meloun switch (bytes) { 47326abae3fSMichal Meloun case 1: 47426abae3fSMichal Meloun data = bus_read_1(res, reg); 47526abae3fSMichal Meloun break; 47626abae3fSMichal Meloun case 2: 47726abae3fSMichal Meloun data = bus_read_2(res, reg); 47826abae3fSMichal Meloun break; 47926abae3fSMichal Meloun case 4: 48026abae3fSMichal Meloun data = bus_read_4(res, reg); 48126abae3fSMichal Meloun break; 48226abae3fSMichal Meloun default: 48326abae3fSMichal Meloun data = 0xFFFFFFFFU; 48426abae3fSMichal Meloun } 48526abae3fSMichal Meloun 48626abae3fSMichal Meloun return (data); 48726abae3fSMichal Meloun 48826abae3fSMichal Meloun } 48926abae3fSMichal Meloun 49026abae3fSMichal Meloun static void 49126abae3fSMichal Meloun pci_dw_write_config(device_t dev, u_int bus, u_int slot, 49226abae3fSMichal Meloun u_int func, u_int reg, uint32_t val, int bytes) 49326abae3fSMichal Meloun { 49426abae3fSMichal Meloun struct pci_dw_softc *sc; 49526abae3fSMichal Meloun struct resource *res; 49626abae3fSMichal Meloun uint64_t addr; 49726abae3fSMichal Meloun int type, rv; 49826abae3fSMichal Meloun 49926abae3fSMichal Meloun sc = device_get_softc(dev); 50026abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 50126abae3fSMichal Meloun return; 50226abae3fSMichal Meloun 50326abae3fSMichal Meloun if (bus == sc->root_bus) { 50426abae3fSMichal Meloun res = (sc->dbi_res); 50526abae3fSMichal Meloun } else { 50626abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 50726abae3fSMichal Meloun IATU_CFG_FUNC(func); 50826abae3fSMichal Meloun if (bus == sc->sub_bus) 50926abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 51026abae3fSMichal Meloun else 51126abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 512f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, 0, type, 51326abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 51426abae3fSMichal Meloun if (rv != 0) 51526abae3fSMichal Meloun return ; 51626abae3fSMichal Meloun res = sc->cfg_res; 51726abae3fSMichal Meloun } 51826abae3fSMichal Meloun 51926abae3fSMichal Meloun switch (bytes) { 52026abae3fSMichal Meloun case 1: 52126abae3fSMichal Meloun bus_write_1(res, reg, val); 52226abae3fSMichal Meloun break; 52326abae3fSMichal Meloun case 2: 52426abae3fSMichal Meloun bus_write_2(res, reg, val); 52526abae3fSMichal Meloun break; 52626abae3fSMichal Meloun case 4: 52726abae3fSMichal Meloun bus_write_4(res, reg, val); 52826abae3fSMichal Meloun break; 52926abae3fSMichal Meloun default: 53026abae3fSMichal Meloun break; 53126abae3fSMichal Meloun } 53226abae3fSMichal Meloun } 53326abae3fSMichal Meloun 53426abae3fSMichal Meloun static int 53526abae3fSMichal Meloun pci_dw_alloc_msi(device_t pci, device_t child, int count, 53626abae3fSMichal Meloun int maxcount, int *irqs) 53726abae3fSMichal Meloun { 53826abae3fSMichal Meloun phandle_t msi_parent; 53926abae3fSMichal Meloun int rv; 54026abae3fSMichal Meloun 54126abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 54226abae3fSMichal Meloun &msi_parent, NULL); 54326abae3fSMichal Meloun if (rv != 0) 54426abae3fSMichal Meloun return (rv); 54526abae3fSMichal Meloun 54626abae3fSMichal Meloun return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 54726abae3fSMichal Meloun irqs)); 54826abae3fSMichal Meloun } 54926abae3fSMichal Meloun 55026abae3fSMichal Meloun static int 55126abae3fSMichal Meloun pci_dw_release_msi(device_t pci, device_t child, int count, int *irqs) 55226abae3fSMichal Meloun { 55326abae3fSMichal Meloun phandle_t msi_parent; 55426abae3fSMichal Meloun int rv; 55526abae3fSMichal Meloun 55626abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 55726abae3fSMichal Meloun &msi_parent, NULL); 55826abae3fSMichal Meloun if (rv != 0) 55926abae3fSMichal Meloun return (rv); 56026abae3fSMichal Meloun return (intr_release_msi(pci, child, msi_parent, count, irqs)); 56126abae3fSMichal Meloun } 56226abae3fSMichal Meloun 56326abae3fSMichal Meloun static int 56426abae3fSMichal Meloun pci_dw_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 56526abae3fSMichal Meloun uint32_t *data) 56626abae3fSMichal Meloun { 56726abae3fSMichal Meloun phandle_t msi_parent; 56826abae3fSMichal Meloun int rv; 56926abae3fSMichal Meloun 57026abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 57126abae3fSMichal Meloun &msi_parent, NULL); 57226abae3fSMichal Meloun if (rv != 0) 57326abae3fSMichal Meloun return (rv); 57426abae3fSMichal Meloun 57526abae3fSMichal Meloun return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 57626abae3fSMichal Meloun } 57726abae3fSMichal Meloun 57826abae3fSMichal Meloun static int 57926abae3fSMichal Meloun pci_dw_alloc_msix(device_t pci, device_t child, int *irq) 58026abae3fSMichal Meloun { 58126abae3fSMichal Meloun phandle_t msi_parent; 58226abae3fSMichal Meloun int rv; 58326abae3fSMichal Meloun 58426abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 58526abae3fSMichal Meloun &msi_parent, NULL); 58626abae3fSMichal Meloun if (rv != 0) 58726abae3fSMichal Meloun return (rv); 58826abae3fSMichal Meloun return (intr_alloc_msix(pci, child, msi_parent, irq)); 58926abae3fSMichal Meloun } 59026abae3fSMichal Meloun 59126abae3fSMichal Meloun static int 59226abae3fSMichal Meloun pci_dw_release_msix(device_t pci, device_t child, int irq) 59326abae3fSMichal Meloun { 59426abae3fSMichal Meloun phandle_t msi_parent; 59526abae3fSMichal Meloun int rv; 59626abae3fSMichal Meloun 59726abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 59826abae3fSMichal Meloun &msi_parent, NULL); 59926abae3fSMichal Meloun if (rv != 0) 60026abae3fSMichal Meloun return (rv); 60126abae3fSMichal Meloun return (intr_release_msix(pci, child, msi_parent, irq)); 60226abae3fSMichal Meloun } 60326abae3fSMichal Meloun 60426abae3fSMichal Meloun static int 60526abae3fSMichal Meloun pci_dw_get_id(device_t pci, device_t child, enum pci_id_type type, 60626abae3fSMichal Meloun uintptr_t *id) 60726abae3fSMichal Meloun { 60826abae3fSMichal Meloun phandle_t node; 60926abae3fSMichal Meloun int rv; 61026abae3fSMichal Meloun uint32_t rid; 61126abae3fSMichal Meloun uint16_t pci_rid; 61226abae3fSMichal Meloun 61326abae3fSMichal Meloun if (type != PCI_ID_MSI) 61426abae3fSMichal Meloun return (pcib_get_id(pci, child, type, id)); 61526abae3fSMichal Meloun 61626abae3fSMichal Meloun node = ofw_bus_get_node(pci); 61726abae3fSMichal Meloun pci_rid = pci_get_rid(child); 61826abae3fSMichal Meloun 61926abae3fSMichal Meloun rv = ofw_bus_msimap(node, pci_rid, NULL, &rid); 62026abae3fSMichal Meloun if (rv != 0) 62126abae3fSMichal Meloun return (rv); 62226abae3fSMichal Meloun *id = rid; 62326abae3fSMichal Meloun 62426abae3fSMichal Meloun return (0); 62526abae3fSMichal Meloun } 62626abae3fSMichal Meloun 62726abae3fSMichal Meloun /*----------------------------------------------------------------------------- 62826abae3fSMichal Meloun * 62926abae3fSMichal Meloun * B U S / D E V I C E I N T E R F A C E 63026abae3fSMichal Meloun */ 63126abae3fSMichal Meloun static bus_dma_tag_t 63226abae3fSMichal Meloun pci_dw_get_dma_tag(device_t dev, device_t child) 63326abae3fSMichal Meloun { 63426abae3fSMichal Meloun struct pci_dw_softc *sc; 63526abae3fSMichal Meloun 63626abae3fSMichal Meloun sc = device_get_softc(dev); 63726abae3fSMichal Meloun return (sc->dmat); 63826abae3fSMichal Meloun } 63926abae3fSMichal Meloun 64026abae3fSMichal Meloun int 64126abae3fSMichal Meloun pci_dw_init(device_t dev) 64226abae3fSMichal Meloun { 64326abae3fSMichal Meloun struct pci_dw_softc *sc; 64426abae3fSMichal Meloun int rv, rid; 645*f240dfffSJessica Clarke bool unroll_mode; 64626abae3fSMichal Meloun 64726abae3fSMichal Meloun sc = device_get_softc(dev); 64826abae3fSMichal Meloun sc->dev = dev; 64926abae3fSMichal Meloun sc->node = ofw_bus_get_node(dev); 65026abae3fSMichal Meloun 65126abae3fSMichal Meloun mtx_init(&sc->mtx, "pci_dw_mtx", NULL, MTX_DEF); 65226abae3fSMichal Meloun 65326abae3fSMichal Meloun /* XXXn Should not be this configurable ? */ 65426abae3fSMichal Meloun sc->bus_start = 0; 65526abae3fSMichal Meloun sc->bus_end = 255; 65626abae3fSMichal Meloun sc->root_bus = 0; 65726abae3fSMichal Meloun sc->sub_bus = 1; 65826abae3fSMichal Meloun 65926abae3fSMichal Meloun /* Read FDT properties */ 66026abae3fSMichal Meloun if (!sc->coherent) 66126abae3fSMichal Meloun sc->coherent = OF_hasprop(sc->node, "dma-coherent"); 66226abae3fSMichal Meloun 66326abae3fSMichal Meloun rv = OF_getencprop(sc->node, "num-viewport", &sc->num_viewport, 66426abae3fSMichal Meloun sizeof(sc->num_viewport)); 66526abae3fSMichal Meloun if (rv != sizeof(sc->num_viewport)) 66626abae3fSMichal Meloun sc->num_viewport = 2; 66726abae3fSMichal Meloun 66826abae3fSMichal Meloun rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes, 66926abae3fSMichal Meloun sizeof(sc->num_viewport)); 67026abae3fSMichal Meloun if (rv != sizeof(sc->num_lanes)) 67126abae3fSMichal Meloun sc->num_lanes = 1; 67226abae3fSMichal Meloun if (sc->num_lanes != 1 && sc->num_lanes != 2 && 67326abae3fSMichal Meloun sc->num_lanes != 4 && sc->num_lanes != 8) { 67426abae3fSMichal Meloun device_printf(dev, 67526abae3fSMichal Meloun "invalid number of lanes: %d\n",sc->num_lanes); 67626abae3fSMichal Meloun sc->num_lanes = 0; 67726abae3fSMichal Meloun rv = ENXIO; 67826abae3fSMichal Meloun goto out; 67926abae3fSMichal Meloun } 68026abae3fSMichal Meloun 68126abae3fSMichal Meloun rid = 0; 68226abae3fSMichal Meloun rv = ofw_bus_find_string_index(sc->node, "reg-names", "config", &rid); 68326abae3fSMichal Meloun if (rv != 0) { 68426abae3fSMichal Meloun device_printf(dev, "Cannot get config space memory\n"); 68526abae3fSMichal Meloun rv = ENXIO; 68626abae3fSMichal Meloun goto out; 68726abae3fSMichal Meloun } 68826abae3fSMichal Meloun sc->cfg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 68926abae3fSMichal Meloun RF_ACTIVE); 69026abae3fSMichal Meloun if (sc->cfg_res == NULL) { 69126abae3fSMichal Meloun device_printf(dev, "Cannot allocate config space(rid: %d)\n", 69226abae3fSMichal Meloun rid); 69326abae3fSMichal Meloun rv = ENXIO; 69426abae3fSMichal Meloun goto out; 69526abae3fSMichal Meloun } 69626abae3fSMichal Meloun 69726abae3fSMichal Meloun /* Fill up config region related variables */ 69826abae3fSMichal Meloun sc->cfg_size = rman_get_size(sc->cfg_res); 69926abae3fSMichal Meloun sc->cfg_pa = rman_get_start(sc->cfg_res) ; 70026abae3fSMichal Meloun 70126abae3fSMichal Meloun if (bootverbose) 70226abae3fSMichal Meloun device_printf(dev, "Bus is%s cache-coherent\n", 70326abae3fSMichal Meloun sc->coherent ? "" : " not"); 70426abae3fSMichal Meloun rv = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 70526abae3fSMichal Meloun 1, 0, /* alignment, bounds */ 70626abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* lowaddr */ 70726abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* highaddr */ 70826abae3fSMichal Meloun NULL, NULL, /* filter, filterarg */ 70926abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsize */ 71026abae3fSMichal Meloun BUS_SPACE_UNRESTRICTED, /* nsegments */ 71126abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsegsize */ 71226abae3fSMichal Meloun sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ 71326abae3fSMichal Meloun NULL, NULL, /* lockfunc, lockarg */ 71426abae3fSMichal Meloun &sc->dmat); 71526abae3fSMichal Meloun if (rv != 0) 71626abae3fSMichal Meloun goto out; 71726abae3fSMichal Meloun 71824042910SMarcin Wojtas rv = ofw_pcib_init(dev); 71926abae3fSMichal Meloun if (rv != 0) 72026abae3fSMichal Meloun goto out; 72126abae3fSMichal Meloun rv = pci_dw_decode_ranges(sc, sc->ofw_pci.sc_range, 72226abae3fSMichal Meloun sc->ofw_pci.sc_nrange); 72326abae3fSMichal Meloun if (rv != 0) 72426abae3fSMichal Meloun goto out; 72526abae3fSMichal Meloun 726*f240dfffSJessica Clarke unroll_mode = pci_dw_detect_atu_unroll(sc); 727*f240dfffSJessica Clarke if (bootverbose) 728*f240dfffSJessica Clarke device_printf(dev, "Using iATU %s mode\n", 729*f240dfffSJessica Clarke unroll_mode ? "unroll" : "legacy"); 730*f240dfffSJessica Clarke if (unroll_mode) { 731*f240dfffSJessica Clarke rid = 0; 732*f240dfffSJessica Clarke rv = ofw_bus_find_string_index(sc->node, "reg-names", "atu", &rid); 733*f240dfffSJessica Clarke if (rv == 0) { 734*f240dfffSJessica Clarke sc->iatu_ur_res = bus_alloc_resource_any(dev, 735*f240dfffSJessica Clarke SYS_RES_MEMORY, &rid, RF_ACTIVE); 736*f240dfffSJessica Clarke if (sc->iatu_ur_res == NULL) { 737*f240dfffSJessica Clarke device_printf(dev, 738*f240dfffSJessica Clarke "Cannot allocate iATU space (rid: %d)\n", 739*f240dfffSJessica Clarke rid); 740*f240dfffSJessica Clarke rv = ENXIO; 741*f240dfffSJessica Clarke goto out; 742*f240dfffSJessica Clarke } 743*f240dfffSJessica Clarke sc->iatu_ur_offset = 0; 744*f240dfffSJessica Clarke sc->iatu_ur_size = rman_get_size(sc->iatu_ur_res); 745*f240dfffSJessica Clarke } else if (rv == ENOENT) { 746*f240dfffSJessica Clarke sc->iatu_ur_res = sc->dbi_res; 747*f240dfffSJessica Clarke sc->iatu_ur_offset = DW_DEFAULT_IATU_UR_DBI_OFFSET; 748*f240dfffSJessica Clarke sc->iatu_ur_size = DW_DEFAULT_IATU_UR_DBI_SIZE; 749*f240dfffSJessica Clarke } else { 750*f240dfffSJessica Clarke device_printf(dev, "Cannot get iATU space memory\n"); 751*f240dfffSJessica Clarke rv = ENXIO; 752*f240dfffSJessica Clarke goto out; 753*f240dfffSJessica Clarke } 754*f240dfffSJessica Clarke } 755*f240dfffSJessica Clarke 75626abae3fSMichal Meloun rv = pci_dw_setup_hw(sc); 75726abae3fSMichal Meloun if (rv != 0) 75826abae3fSMichal Meloun goto out; 75926abae3fSMichal Meloun 76026abae3fSMichal Meloun device_add_child(dev, "pci", -1); 76126abae3fSMichal Meloun 762cc2eaa04SMichal Meloun return (0); 76326abae3fSMichal Meloun out: 76426abae3fSMichal Meloun /* XXX Cleanup */ 76526abae3fSMichal Meloun return (rv); 76626abae3fSMichal Meloun } 76726abae3fSMichal Meloun 76826abae3fSMichal Meloun static device_method_t pci_dw_methods[] = { 76926abae3fSMichal Meloun /* Bus interface */ 77026abae3fSMichal Meloun DEVMETHOD(bus_get_dma_tag, pci_dw_get_dma_tag), 77126abae3fSMichal Meloun 77226abae3fSMichal Meloun /* pcib interface */ 77326abae3fSMichal Meloun DEVMETHOD(pcib_read_config, pci_dw_read_config), 77426abae3fSMichal Meloun DEVMETHOD(pcib_write_config, pci_dw_write_config), 77526abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msi, pci_dw_alloc_msi), 77626abae3fSMichal Meloun DEVMETHOD(pcib_release_msi, pci_dw_release_msi), 77726abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msix, pci_dw_alloc_msix), 77826abae3fSMichal Meloun DEVMETHOD(pcib_release_msix, pci_dw_release_msix), 77926abae3fSMichal Meloun DEVMETHOD(pcib_map_msi, pci_dw_map_msi), 78026abae3fSMichal Meloun DEVMETHOD(pcib_get_id, pci_dw_get_id), 78126abae3fSMichal Meloun 78226abae3fSMichal Meloun /* OFW bus interface */ 78326abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 78426abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 78526abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 78626abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 78726abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 78826abae3fSMichal Meloun 78926abae3fSMichal Meloun /* PCI DW interface */ 79026abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_read, pci_dw_dbi_read), 79126abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_write, pci_dw_dbi_write), 79226abae3fSMichal Meloun DEVMETHOD_END 79326abae3fSMichal Meloun }; 79426abae3fSMichal Meloun 79526abae3fSMichal Meloun DEFINE_CLASS_1(pcib, pci_dw_driver, pci_dw_methods, 79624042910SMarcin Wojtas sizeof(struct pci_dw_softc), ofw_pcib_driver); 797