126abae3fSMichal Meloun /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 3226abae3fSMichal Meloun #include <sys/systm.h> 3326abae3fSMichal Meloun #include <sys/bus.h> 3426abae3fSMichal Meloun #include <sys/devmap.h> 3526abae3fSMichal Meloun #include <sys/proc.h> 3626abae3fSMichal Meloun #include <sys/kernel.h> 3726abae3fSMichal Meloun #include <sys/lock.h> 3826abae3fSMichal Meloun #include <sys/malloc.h> 3926abae3fSMichal Meloun #include <sys/module.h> 4026abae3fSMichal Meloun #include <sys/mutex.h> 4126abae3fSMichal Meloun #include <sys/rman.h> 4226abae3fSMichal Meloun 4326abae3fSMichal Meloun #include <machine/bus.h> 4426abae3fSMichal Meloun #include <machine/intr.h> 4526abae3fSMichal Meloun #include <machine/resource.h> 4626abae3fSMichal Meloun 4726abae3fSMichal Meloun #include <dev/ofw/ofw_bus.h> 4826abae3fSMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 4926abae3fSMichal Meloun #include <dev/ofw/ofw_pci.h> 5026abae3fSMichal Meloun #include <dev/ofw/ofwpci.h> 5126abae3fSMichal Meloun #include <dev/pci/pcivar.h> 5226abae3fSMichal Meloun #include <dev/pci/pcireg.h> 5326abae3fSMichal Meloun #include <dev/pci/pcib_private.h> 5426abae3fSMichal Meloun #include <dev/pci/pci_dw.h> 5526abae3fSMichal Meloun 5626abae3fSMichal Meloun #include "pcib_if.h" 5726abae3fSMichal Meloun #include "pci_dw_if.h" 5826abae3fSMichal Meloun 5926abae3fSMichal Meloun #ifdef DEBUG 6026abae3fSMichal Meloun #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 6126abae3fSMichal Meloun #else 6226abae3fSMichal Meloun #define debugf(fmt, args...) 6326abae3fSMichal Meloun #endif 6426abae3fSMichal Meloun 6526abae3fSMichal Meloun #define DBI_WR1(sc, reg, val) pci_dw_dbi_wr1((sc)->dev, reg, val) 6626abae3fSMichal Meloun #define DBI_WR2(sc, reg, val) pci_dw_dbi_wr2((sc)->dev, reg, val) 6726abae3fSMichal Meloun #define DBI_WR4(sc, reg, val) pci_dw_dbi_wr4((sc)->dev, reg, val) 6826abae3fSMichal Meloun #define DBI_RD1(sc, reg) pci_dw_dbi_rd1((sc)->dev, reg) 6926abae3fSMichal Meloun #define DBI_RD2(sc, reg) pci_dw_dbi_rd2((sc)->dev, reg) 7026abae3fSMichal Meloun #define DBI_RD4(sc, reg) pci_dw_dbi_rd4((sc)->dev, reg) 7126abae3fSMichal Meloun 72f240dfffSJessica Clarke #define IATU_UR_WR4(sc, reg, val) \ 73f240dfffSJessica Clarke bus_write_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg), (val)) 74f240dfffSJessica Clarke #define IATU_UR_RD4(sc, reg) \ 75f240dfffSJessica Clarke bus_read_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg)) 76f240dfffSJessica Clarke 7726abae3fSMichal Meloun #define PCI_BUS_SHIFT 20 7826abae3fSMichal Meloun #define PCI_SLOT_SHIFT 15 7926abae3fSMichal Meloun #define PCI_FUNC_SHIFT 12 8026abae3fSMichal Meloun #define PCI_BUS_MASK 0xFF 8126abae3fSMichal Meloun #define PCI_SLOT_MASK 0x1F 8226abae3fSMichal Meloun #define PCI_FUNC_MASK 0x07 8326abae3fSMichal Meloun #define PCI_REG_MASK 0xFFF 8426abae3fSMichal Meloun 8526abae3fSMichal Meloun #define IATU_CFG_BUS(bus) ((uint64_t)((bus) & 0xff) << 24) 8626abae3fSMichal Meloun #define IATU_CFG_SLOT(slot) ((uint64_t)((slot) & 0x1f) << 19) 8726abae3fSMichal Meloun #define IATU_CFG_FUNC(func) ((uint64_t)((func) & 0x07) << 16) 8826abae3fSMichal Meloun 8926abae3fSMichal Meloun static uint32_t 9026abae3fSMichal Meloun pci_dw_dbi_read(device_t dev, u_int reg, int width) 9126abae3fSMichal Meloun { 9226abae3fSMichal Meloun struct pci_dw_softc *sc; 9326abae3fSMichal Meloun 9426abae3fSMichal Meloun sc = device_get_softc(dev); 9526abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 9626abae3fSMichal Meloun 9726abae3fSMichal Meloun switch (width) { 9826abae3fSMichal Meloun case 4: 9926abae3fSMichal Meloun return (bus_read_4(sc->dbi_res, reg)); 10026abae3fSMichal Meloun case 2: 10126abae3fSMichal Meloun return (bus_read_2(sc->dbi_res, reg)); 10226abae3fSMichal Meloun case 1: 10326abae3fSMichal Meloun return (bus_read_1(sc->dbi_res, reg)); 10426abae3fSMichal Meloun default: 10526abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 10626abae3fSMichal Meloun return (0xFFFFFFFF); 10726abae3fSMichal Meloun } 10826abae3fSMichal Meloun } 10926abae3fSMichal Meloun 11026abae3fSMichal Meloun static void 11126abae3fSMichal Meloun pci_dw_dbi_write(device_t dev, u_int reg, uint32_t val, int width) 11226abae3fSMichal Meloun { 11326abae3fSMichal Meloun struct pci_dw_softc *sc; 11426abae3fSMichal Meloun 11526abae3fSMichal Meloun sc = device_get_softc(dev); 11626abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 11726abae3fSMichal Meloun 11826abae3fSMichal Meloun switch (width) { 11926abae3fSMichal Meloun case 4: 12026abae3fSMichal Meloun bus_write_4(sc->dbi_res, reg, val); 12126abae3fSMichal Meloun break; 12226abae3fSMichal Meloun case 2: 12326abae3fSMichal Meloun bus_write_2(sc->dbi_res, reg, val); 12426abae3fSMichal Meloun break; 12526abae3fSMichal Meloun case 1: 12626abae3fSMichal Meloun bus_write_1(sc->dbi_res, reg, val); 12726abae3fSMichal Meloun break; 12826abae3fSMichal Meloun default: 12926abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 13026abae3fSMichal Meloun break; 13126abae3fSMichal Meloun } 13226abae3fSMichal Meloun } 13326abae3fSMichal Meloun 13426abae3fSMichal Meloun static void 13526abae3fSMichal Meloun pci_dw_dbi_protect(struct pci_dw_softc *sc, bool protect) 13626abae3fSMichal Meloun { 13726abae3fSMichal Meloun uint32_t reg; 13826abae3fSMichal Meloun 13926abae3fSMichal Meloun reg = DBI_RD4(sc, DW_MISC_CONTROL_1); 14026abae3fSMichal Meloun if (protect) 14126abae3fSMichal Meloun reg &= ~DBI_RO_WR_EN; 14226abae3fSMichal Meloun else 14326abae3fSMichal Meloun reg |= DBI_RO_WR_EN; 14426abae3fSMichal Meloun DBI_WR4(sc, DW_MISC_CONTROL_1, reg); 14526abae3fSMichal Meloun } 14626abae3fSMichal Meloun 14726abae3fSMichal Meloun static bool 14826abae3fSMichal Meloun pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int slot, u_int func, 14926abae3fSMichal Meloun u_int reg) 15026abae3fSMichal Meloun { 15126abae3fSMichal Meloun bool status; 15226abae3fSMichal Meloun int rv; 15326abae3fSMichal Meloun 15426abae3fSMichal Meloun if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX || 1551f446a11SMichal Meloun func > PCI_FUNCMAX || reg > PCIE_REGMAX) 15626abae3fSMichal Meloun return (false); 15726abae3fSMichal Meloun 15826abae3fSMichal Meloun /* link is needed for access to all non-root busses */ 15926abae3fSMichal Meloun if (bus != sc->root_bus) { 16026abae3fSMichal Meloun rv = PCI_DW_GET_LINK(sc->dev, &status); 16126abae3fSMichal Meloun if (rv != 0 || !status) 16226abae3fSMichal Meloun return (false); 16326abae3fSMichal Meloun return (true); 16426abae3fSMichal Meloun } 16526abae3fSMichal Meloun 16626abae3fSMichal Meloun /* we have only 1 device with 1 function root port */ 16726abae3fSMichal Meloun if (slot > 0 || func > 0) 16826abae3fSMichal Meloun return (false); 16926abae3fSMichal Meloun return (true); 17026abae3fSMichal Meloun } 17126abae3fSMichal Meloun 172f240dfffSJessica Clarke static bool 173f240dfffSJessica Clarke pci_dw_detect_atu_unroll(struct pci_dw_softc *sc) 174f240dfffSJessica Clarke { 175f240dfffSJessica Clarke return (DBI_RD4(sc, DW_IATU_VIEWPORT) == 0xFFFFFFFFU); 176f240dfffSJessica Clarke } 177f240dfffSJessica Clarke 17826abae3fSMichal Meloun static int 1794707bb04SJessica Clarke pci_dw_detect_out_atu_regions_unroll(struct pci_dw_softc *sc) 1804707bb04SJessica Clarke { 1814707bb04SJessica Clarke int num_regions, i; 1824707bb04SJessica Clarke uint32_t reg; 1834707bb04SJessica Clarke 1844707bb04SJessica Clarke num_regions = sc->iatu_ur_size / DW_IATU_UR_STEP; 1854707bb04SJessica Clarke 1864707bb04SJessica Clarke for (i = 0; i < num_regions; ++i) { 1874707bb04SJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(i, LWR_TARGET_ADDR), 1884707bb04SJessica Clarke 0x12340000); 1894707bb04SJessica Clarke reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(i, LWR_TARGET_ADDR)); 1904707bb04SJessica Clarke if (reg != 0x12340000) 1914707bb04SJessica Clarke break; 1924707bb04SJessica Clarke } 1934707bb04SJessica Clarke 1944707bb04SJessica Clarke sc->num_out_regions = i; 1954707bb04SJessica Clarke 1964707bb04SJessica Clarke return (0); 1974707bb04SJessica Clarke } 1984707bb04SJessica Clarke 1994707bb04SJessica Clarke static int 2004707bb04SJessica Clarke pci_dw_detect_out_atu_regions_legacy(struct pci_dw_softc *sc) 2014707bb04SJessica Clarke { 2024707bb04SJessica Clarke int num_viewports, i; 2034707bb04SJessica Clarke uint32_t reg; 2044707bb04SJessica Clarke 2054707bb04SJessica Clarke /* Find out how many viewports there are in total */ 2064707bb04SJessica Clarke DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(~0U)); 2074707bb04SJessica Clarke reg = DBI_RD4(sc, DW_IATU_VIEWPORT); 2084707bb04SJessica Clarke if (reg > IATU_REGION_INDEX(~0U)) { 2094707bb04SJessica Clarke device_printf(sc->dev, 2104707bb04SJessica Clarke "Cannot detect number of output iATU regions; read %#x\n", 2114707bb04SJessica Clarke reg); 2124707bb04SJessica Clarke return (ENXIO); 2134707bb04SJessica Clarke } 2144707bb04SJessica Clarke 2154707bb04SJessica Clarke num_viewports = reg + 1; 2164707bb04SJessica Clarke 2174707bb04SJessica Clarke /* 2184707bb04SJessica Clarke * Find out how many of them are outbound by seeing whether a dummy 2194707bb04SJessica Clarke * page-aligned address sticks. 2204707bb04SJessica Clarke */ 2214707bb04SJessica Clarke for (i = 0; i < num_viewports; ++i) { 2224707bb04SJessica Clarke DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(i)); 2234707bb04SJessica Clarke DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, 0x12340000); 2244707bb04SJessica Clarke reg = DBI_RD4(sc, DW_IATU_LWR_TARGET_ADDR); 2254707bb04SJessica Clarke if (reg != 0x12340000) 2264707bb04SJessica Clarke break; 2274707bb04SJessica Clarke } 2284707bb04SJessica Clarke 2294707bb04SJessica Clarke sc->num_out_regions = i; 2304707bb04SJessica Clarke 2314707bb04SJessica Clarke return (0); 2324707bb04SJessica Clarke } 2334707bb04SJessica Clarke 2344707bb04SJessica Clarke static int 2354707bb04SJessica Clarke pci_dw_detect_out_atu_regions(struct pci_dw_softc *sc) 2364707bb04SJessica Clarke { 2374707bb04SJessica Clarke if (sc->iatu_ur_res) 2384707bb04SJessica Clarke return (pci_dw_detect_out_atu_regions_unroll(sc)); 2394707bb04SJessica Clarke else 2404707bb04SJessica Clarke return (pci_dw_detect_out_atu_regions_legacy(sc)); 2414707bb04SJessica Clarke } 2424707bb04SJessica Clarke 2434707bb04SJessica Clarke static int 244f240dfffSJessica Clarke pci_dw_map_out_atu_unroll(struct pci_dw_softc *sc, int idx, int type, 245f240dfffSJessica Clarke uint64_t pa, uint64_t pci_addr, uint32_t size) 246f240dfffSJessica Clarke { 247f240dfffSJessica Clarke uint32_t reg; 248f240dfffSJessica Clarke int i; 249f240dfffSJessica Clarke 250f240dfffSJessica Clarke if (size == 0) 251f240dfffSJessica Clarke return (0); 252f240dfffSJessica Clarke 253f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_BASE_ADDR), 254f240dfffSJessica Clarke pa & 0xFFFFFFFF); 255f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_BASE_ADDR), 256f240dfffSJessica Clarke (pa >> 32) & 0xFFFFFFFF); 257f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LIMIT_ADDR), 258f240dfffSJessica Clarke (pa + size - 1) & 0xFFFFFFFF); 259f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_TARGET_ADDR), 260f240dfffSJessica Clarke pci_addr & 0xFFFFFFFF); 261f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_TARGET_ADDR), 262f240dfffSJessica Clarke (pci_addr >> 32) & 0xFFFFFFFF); 263f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL1), 264f240dfffSJessica Clarke IATU_CTRL1_TYPE(type)); 265f240dfffSJessica Clarke IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL2), 266f240dfffSJessica Clarke IATU_CTRL2_REGION_EN); 267f240dfffSJessica Clarke 268f240dfffSJessica Clarke /* Wait until setup becomes valid */ 269f240dfffSJessica Clarke for (i = 10; i > 0; i--) { 270f240dfffSJessica Clarke reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(idx, CTRL2)); 271f240dfffSJessica Clarke if (reg & IATU_CTRL2_REGION_EN) 272f240dfffSJessica Clarke return (0); 273f240dfffSJessica Clarke DELAY(5); 274f240dfffSJessica Clarke } 275f240dfffSJessica Clarke 276f240dfffSJessica Clarke device_printf(sc->dev, 277f240dfffSJessica Clarke "Cannot map outbound region %d in unroll mode iATU\n", idx); 278f240dfffSJessica Clarke return (ETIMEDOUT); 279f240dfffSJessica Clarke } 280f240dfffSJessica Clarke 281f240dfffSJessica Clarke static int 282f240dfffSJessica Clarke pci_dw_map_out_atu_legacy(struct pci_dw_softc *sc, int idx, int type, 28326abae3fSMichal Meloun uint64_t pa, uint64_t pci_addr, uint32_t size) 28426abae3fSMichal Meloun { 28526abae3fSMichal Meloun uint32_t reg; 28626abae3fSMichal Meloun int i; 28726abae3fSMichal Meloun 28826abae3fSMichal Meloun if (size == 0) 28926abae3fSMichal Meloun return (0); 29026abae3fSMichal Meloun 29126abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(idx)); 29226abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_BASE_ADDR, pa & 0xFFFFFFFF); 29326abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_BASE_ADDR, (pa >> 32) & 0xFFFFFFFF); 29426abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LIMIT_ADDR, (pa + size - 1) & 0xFFFFFFFF); 29526abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, pci_addr & 0xFFFFFFFF); 29626abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_TARGET_ADDR, (pci_addr >> 32) & 0xFFFFFFFF); 29726abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL1, IATU_CTRL1_TYPE(type)); 29826abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL2, IATU_CTRL2_REGION_EN); 29926abae3fSMichal Meloun 30026abae3fSMichal Meloun /* Wait until setup becomes valid */ 30126abae3fSMichal Meloun for (i = 10; i > 0; i--) { 30226abae3fSMichal Meloun reg = DBI_RD4(sc, DW_IATU_CTRL2); 30326abae3fSMichal Meloun if (reg & IATU_CTRL2_REGION_EN) 30426abae3fSMichal Meloun return (0); 30526abae3fSMichal Meloun DELAY(5); 30626abae3fSMichal Meloun } 307f240dfffSJessica Clarke 30826abae3fSMichal Meloun device_printf(sc->dev, 309f240dfffSJessica Clarke "Cannot map outbound region %d in legacy mode iATU\n", idx); 31026abae3fSMichal Meloun return (ETIMEDOUT); 31126abae3fSMichal Meloun } 31226abae3fSMichal Meloun 313f240dfffSJessica Clarke /* Map one outbound ATU region */ 314f240dfffSJessica Clarke static int 315f240dfffSJessica Clarke pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type, 316f240dfffSJessica Clarke uint64_t pa, uint64_t pci_addr, uint32_t size) 317f240dfffSJessica Clarke { 318f240dfffSJessica Clarke if (sc->iatu_ur_res) 319f240dfffSJessica Clarke return (pci_dw_map_out_atu_unroll(sc, idx, type, pa, 320f240dfffSJessica Clarke pci_addr, size)); 321f240dfffSJessica Clarke else 322f240dfffSJessica Clarke return (pci_dw_map_out_atu_legacy(sc, idx, type, pa, 323f240dfffSJessica Clarke pci_addr, size)); 324f240dfffSJessica Clarke } 325f240dfffSJessica Clarke 32626abae3fSMichal Meloun static int 32726abae3fSMichal Meloun pci_dw_setup_hw(struct pci_dw_softc *sc) 32826abae3fSMichal Meloun { 32926abae3fSMichal Meloun uint32_t reg; 330f8c1701fSJessica Clarke int rv, i; 33126abae3fSMichal Meloun 33226abae3fSMichal Meloun pci_dw_dbi_protect(sc, false); 33326abae3fSMichal Meloun 33426abae3fSMichal Meloun /* Setup config registers */ 33526abae3fSMichal Meloun DBI_WR1(sc, PCIR_CLASS, PCIC_BRIDGE); 33626abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); 33726abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(0), 4); 33826abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(1), 0); 33926abae3fSMichal Meloun DBI_WR1(sc, PCIR_INTPIN, 1); 34026abae3fSMichal Meloun DBI_WR1(sc, PCIR_PRIBUS_1, sc->root_bus); 34126abae3fSMichal Meloun DBI_WR1(sc, PCIR_SECBUS_1, sc->sub_bus); 34226abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBBUS_1, sc->bus_end); 34326abae3fSMichal Meloun DBI_WR2(sc, PCIR_COMMAND, 34426abae3fSMichal Meloun PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | 34526abae3fSMichal Meloun PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN); 34626abae3fSMichal Meloun pci_dw_dbi_protect(sc, true); 34726abae3fSMichal Meloun 348f8c1701fSJessica Clarke /* Setup outbound memory windows */ 3494707bb04SJessica Clarke for (i = 0; i < min(sc->num_mem_ranges, sc->num_out_regions - 1); ++i) { 350f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, i + 1, IATU_CTRL1_TYPE_MEM, 351f8c1701fSJessica Clarke sc->mem_ranges[i].host, sc->mem_ranges[i].pci, 352f8c1701fSJessica Clarke sc->mem_ranges[i].size); 35326abae3fSMichal Meloun if (rv != 0) 35426abae3fSMichal Meloun return (rv); 35526abae3fSMichal Meloun } 356f8c1701fSJessica Clarke 3574707bb04SJessica Clarke /* If we have enough regions ... */ 3584707bb04SJessica Clarke if (sc->num_mem_ranges + 1 < sc->num_out_regions && 359f8c1701fSJessica Clarke sc->io_range.size != 0) { 360f8c1701fSJessica Clarke /* Setup outbound I/O window */ 361f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, sc->num_mem_ranges + 1, 362f8c1701fSJessica Clarke IATU_CTRL1_TYPE_IO, sc->io_range.host, sc->io_range.pci, 363f8c1701fSJessica Clarke sc->io_range.size); 364f8c1701fSJessica Clarke if (rv != 0) 365f8c1701fSJessica Clarke return (rv); 366f8c1701fSJessica Clarke } 36726abae3fSMichal Meloun 36826abae3fSMichal Meloun /* Adjust number of lanes */ 36926abae3fSMichal Meloun reg = DBI_RD4(sc, DW_PORT_LINK_CTRL); 37026abae3fSMichal Meloun reg &= ~PORT_LINK_CAPABLE(~0); 37126abae3fSMichal Meloun switch (sc->num_lanes) { 37226abae3fSMichal Meloun case 1: 37326abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_1); 37426abae3fSMichal Meloun break; 37526abae3fSMichal Meloun case 2: 37626abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_2); 37726abae3fSMichal Meloun break; 37826abae3fSMichal Meloun case 4: 37926abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_4); 38026abae3fSMichal Meloun break; 38126abae3fSMichal Meloun case 8: 38226abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_8); 38326abae3fSMichal Meloun break; 38426abae3fSMichal Meloun case 16: 38526abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_16); 38626abae3fSMichal Meloun break; 38726abae3fSMichal Meloun case 32: 38826abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_32); 38926abae3fSMichal Meloun break; 39026abae3fSMichal Meloun default: 39126abae3fSMichal Meloun device_printf(sc->dev, 39226abae3fSMichal Meloun "'num-lanes' property have invalid value: %d\n", 39326abae3fSMichal Meloun sc->num_lanes); 39426abae3fSMichal Meloun return (EINVAL); 39526abae3fSMichal Meloun } 39626abae3fSMichal Meloun DBI_WR4(sc, DW_PORT_LINK_CTRL, reg); 39726abae3fSMichal Meloun 39826abae3fSMichal Meloun /* And link width */ 39926abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 40026abae3fSMichal Meloun reg &= ~GEN2_CTRL_NUM_OF_LANES(~0); 40126abae3fSMichal Meloun switch (sc->num_lanes) { 40226abae3fSMichal Meloun case 1: 40326abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_1); 40426abae3fSMichal Meloun break; 40526abae3fSMichal Meloun case 2: 40626abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_2); 40726abae3fSMichal Meloun break; 40826abae3fSMichal Meloun case 4: 40926abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_4); 41026abae3fSMichal Meloun break; 41126abae3fSMichal Meloun case 8: 41226abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_8); 41326abae3fSMichal Meloun break; 41426abae3fSMichal Meloun case 16: 41526abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_16); 41626abae3fSMichal Meloun break; 41726abae3fSMichal Meloun case 32: 41826abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_32); 41926abae3fSMichal Meloun break; 42026abae3fSMichal Meloun } 42126abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 42226abae3fSMichal Meloun 42326abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 42426abae3fSMichal Meloun reg |= DIRECT_SPEED_CHANGE; 42526abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 42626abae3fSMichal Meloun 42726abae3fSMichal Meloun return (0); 42826abae3fSMichal Meloun } 42926abae3fSMichal Meloun 43026abae3fSMichal Meloun static int 43126abae3fSMichal Meloun pci_dw_decode_ranges(struct pci_dw_softc *sc, struct ofw_pci_range *ranges, 43226abae3fSMichal Meloun int nranges) 43326abae3fSMichal Meloun { 434f8c1701fSJessica Clarke int i, nmem, rv; 43526abae3fSMichal Meloun 436f8c1701fSJessica Clarke nmem = 0; 437f8c1701fSJessica Clarke for (i = 0; i < nranges; i++) { 438f8c1701fSJessica Clarke if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 439f8c1701fSJessica Clarke OFW_PCI_PHYS_HI_SPACE_MEM32) 440f8c1701fSJessica Clarke ++nmem; 441f8c1701fSJessica Clarke } 442f8c1701fSJessica Clarke 443f8c1701fSJessica Clarke sc->mem_ranges = malloc(nmem * sizeof(*sc->mem_ranges), M_DEVBUF, 444f8c1701fSJessica Clarke M_WAITOK); 445f8c1701fSJessica Clarke sc->num_mem_ranges = nmem; 446f8c1701fSJessica Clarke 447f8c1701fSJessica Clarke nmem = 0; 44826abae3fSMichal Meloun for (i = 0; i < nranges; i++) { 44926abae3fSMichal Meloun if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 45026abae3fSMichal Meloun OFW_PCI_PHYS_HI_SPACE_IO) { 45126abae3fSMichal Meloun if (sc->io_range.size != 0) { 45226abae3fSMichal Meloun device_printf(sc->dev, 45326abae3fSMichal Meloun "Duplicated IO range found in DT\n"); 454f8c1701fSJessica Clarke rv = ENXIO; 455f8c1701fSJessica Clarke goto out; 45626abae3fSMichal Meloun } 457f8c1701fSJessica Clarke 45826abae3fSMichal Meloun sc->io_range = ranges[i]; 459243000b1SWojciech Macek if (sc->io_range.size > UINT32_MAX) { 460243000b1SWojciech Macek device_printf(sc->dev, 461f8c1701fSJessica Clarke "ATU IO window size is too large. " 462f8c1701fSJessica Clarke "Up to 4GB windows are supported, " 463f8c1701fSJessica Clarke "trimming window size to 4GB\n"); 464243000b1SWojciech Macek sc->io_range.size = UINT32_MAX; 465243000b1SWojciech Macek } 466243000b1SWojciech Macek } 467f8c1701fSJessica Clarke if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 468f8c1701fSJessica Clarke OFW_PCI_PHYS_HI_SPACE_MEM32) { 469f8c1701fSJessica Clarke MPASS(nmem < sc->num_mem_ranges); 470f8c1701fSJessica Clarke sc->mem_ranges[nmem] = ranges[i]; 471f8c1701fSJessica Clarke if (sc->mem_ranges[nmem].size > UINT32_MAX) { 472f8c1701fSJessica Clarke device_printf(sc->dev, 473f8c1701fSJessica Clarke "ATU MEM window size is too large. " 474f8c1701fSJessica Clarke "Up to 4GB windows are supported, " 475f8c1701fSJessica Clarke "trimming window size to 4GB\n"); 476f8c1701fSJessica Clarke sc->mem_ranges[nmem].size = UINT32_MAX; 477f8c1701fSJessica Clarke } 478f8c1701fSJessica Clarke ++nmem; 479f8c1701fSJessica Clarke } 480f8c1701fSJessica Clarke } 481f8c1701fSJessica Clarke 482f8c1701fSJessica Clarke MPASS(nmem == sc->num_mem_ranges); 483f8c1701fSJessica Clarke 484f8c1701fSJessica Clarke if (nmem == 0) { 485f8c1701fSJessica Clarke device_printf(sc->dev, 486f8c1701fSJessica Clarke "Missing required memory range in DT\n"); 487f8c1701fSJessica Clarke return (ENXIO); 488f8c1701fSJessica Clarke } 489f8c1701fSJessica Clarke 49026abae3fSMichal Meloun return (0); 491f8c1701fSJessica Clarke 492f8c1701fSJessica Clarke out: 493f8c1701fSJessica Clarke free(sc->mem_ranges, M_DEVBUF); 494f8c1701fSJessica Clarke return (rv); 49526abae3fSMichal Meloun } 49626abae3fSMichal Meloun 49726abae3fSMichal Meloun /*----------------------------------------------------------------------------- 49826abae3fSMichal Meloun * 49926abae3fSMichal Meloun * P C I B I N T E R F A C E 50026abae3fSMichal Meloun */ 50126abae3fSMichal Meloun 50226abae3fSMichal Meloun static uint32_t 50326abae3fSMichal Meloun pci_dw_read_config(device_t dev, u_int bus, u_int slot, 50426abae3fSMichal Meloun u_int func, u_int reg, int bytes) 50526abae3fSMichal Meloun { 50626abae3fSMichal Meloun struct pci_dw_softc *sc; 50726abae3fSMichal Meloun struct resource *res; 50826abae3fSMichal Meloun uint32_t data; 50926abae3fSMichal Meloun uint64_t addr; 51026abae3fSMichal Meloun int type, rv; 51126abae3fSMichal Meloun 51226abae3fSMichal Meloun sc = device_get_softc(dev); 51326abae3fSMichal Meloun 51426abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 51526abae3fSMichal Meloun return (0xFFFFFFFFU); 51626abae3fSMichal Meloun 51726abae3fSMichal Meloun if (bus == sc->root_bus) { 51826abae3fSMichal Meloun res = (sc->dbi_res); 51926abae3fSMichal Meloun } else { 52026abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 52126abae3fSMichal Meloun IATU_CFG_FUNC(func); 52226abae3fSMichal Meloun if (bus == sc->sub_bus) 52326abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 52426abae3fSMichal Meloun else 52526abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 526f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, 0, type, 52726abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 52826abae3fSMichal Meloun if (rv != 0) 52926abae3fSMichal Meloun return (0xFFFFFFFFU); 53026abae3fSMichal Meloun res = sc->cfg_res; 53126abae3fSMichal Meloun } 53226abae3fSMichal Meloun 53326abae3fSMichal Meloun switch (bytes) { 53426abae3fSMichal Meloun case 1: 53526abae3fSMichal Meloun data = bus_read_1(res, reg); 53626abae3fSMichal Meloun break; 53726abae3fSMichal Meloun case 2: 53826abae3fSMichal Meloun data = bus_read_2(res, reg); 53926abae3fSMichal Meloun break; 54026abae3fSMichal Meloun case 4: 54126abae3fSMichal Meloun data = bus_read_4(res, reg); 54226abae3fSMichal Meloun break; 54326abae3fSMichal Meloun default: 54426abae3fSMichal Meloun data = 0xFFFFFFFFU; 54526abae3fSMichal Meloun } 54626abae3fSMichal Meloun 54726abae3fSMichal Meloun return (data); 54826abae3fSMichal Meloun 54926abae3fSMichal Meloun } 55026abae3fSMichal Meloun 55126abae3fSMichal Meloun static void 55226abae3fSMichal Meloun pci_dw_write_config(device_t dev, u_int bus, u_int slot, 55326abae3fSMichal Meloun u_int func, u_int reg, uint32_t val, int bytes) 55426abae3fSMichal Meloun { 55526abae3fSMichal Meloun struct pci_dw_softc *sc; 55626abae3fSMichal Meloun struct resource *res; 55726abae3fSMichal Meloun uint64_t addr; 55826abae3fSMichal Meloun int type, rv; 55926abae3fSMichal Meloun 56026abae3fSMichal Meloun sc = device_get_softc(dev); 56126abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 56226abae3fSMichal Meloun return; 56326abae3fSMichal Meloun 56426abae3fSMichal Meloun if (bus == sc->root_bus) { 56526abae3fSMichal Meloun res = (sc->dbi_res); 56626abae3fSMichal Meloun } else { 56726abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 56826abae3fSMichal Meloun IATU_CFG_FUNC(func); 56926abae3fSMichal Meloun if (bus == sc->sub_bus) 57026abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 57126abae3fSMichal Meloun else 57226abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 573f8c1701fSJessica Clarke rv = pci_dw_map_out_atu(sc, 0, type, 57426abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 57526abae3fSMichal Meloun if (rv != 0) 57626abae3fSMichal Meloun return ; 57726abae3fSMichal Meloun res = sc->cfg_res; 57826abae3fSMichal Meloun } 57926abae3fSMichal Meloun 58026abae3fSMichal Meloun switch (bytes) { 58126abae3fSMichal Meloun case 1: 58226abae3fSMichal Meloun bus_write_1(res, reg, val); 58326abae3fSMichal Meloun break; 58426abae3fSMichal Meloun case 2: 58526abae3fSMichal Meloun bus_write_2(res, reg, val); 58626abae3fSMichal Meloun break; 58726abae3fSMichal Meloun case 4: 58826abae3fSMichal Meloun bus_write_4(res, reg, val); 58926abae3fSMichal Meloun break; 59026abae3fSMichal Meloun default: 59126abae3fSMichal Meloun break; 59226abae3fSMichal Meloun } 59326abae3fSMichal Meloun } 59426abae3fSMichal Meloun 59526abae3fSMichal Meloun static int 59626abae3fSMichal Meloun pci_dw_alloc_msi(device_t pci, device_t child, int count, 59726abae3fSMichal Meloun int maxcount, int *irqs) 59826abae3fSMichal Meloun { 59926abae3fSMichal Meloun phandle_t msi_parent; 60026abae3fSMichal Meloun int rv; 60126abae3fSMichal Meloun 60226abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 60326abae3fSMichal Meloun &msi_parent, NULL); 60426abae3fSMichal Meloun if (rv != 0) 60526abae3fSMichal Meloun return (rv); 60626abae3fSMichal Meloun 60726abae3fSMichal Meloun return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 60826abae3fSMichal Meloun irqs)); 60926abae3fSMichal Meloun } 61026abae3fSMichal Meloun 61126abae3fSMichal Meloun static int 61226abae3fSMichal Meloun pci_dw_release_msi(device_t pci, device_t child, int count, int *irqs) 61326abae3fSMichal Meloun { 61426abae3fSMichal Meloun phandle_t msi_parent; 61526abae3fSMichal Meloun int rv; 61626abae3fSMichal Meloun 61726abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 61826abae3fSMichal Meloun &msi_parent, NULL); 61926abae3fSMichal Meloun if (rv != 0) 62026abae3fSMichal Meloun return (rv); 62126abae3fSMichal Meloun return (intr_release_msi(pci, child, msi_parent, count, irqs)); 62226abae3fSMichal Meloun } 62326abae3fSMichal Meloun 62426abae3fSMichal Meloun static int 62526abae3fSMichal Meloun pci_dw_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 62626abae3fSMichal Meloun uint32_t *data) 62726abae3fSMichal Meloun { 62826abae3fSMichal Meloun phandle_t msi_parent; 62926abae3fSMichal Meloun int rv; 63026abae3fSMichal Meloun 63126abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 63226abae3fSMichal Meloun &msi_parent, NULL); 63326abae3fSMichal Meloun if (rv != 0) 63426abae3fSMichal Meloun return (rv); 63526abae3fSMichal Meloun 63626abae3fSMichal Meloun return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 63726abae3fSMichal Meloun } 63826abae3fSMichal Meloun 63926abae3fSMichal Meloun static int 64026abae3fSMichal Meloun pci_dw_alloc_msix(device_t pci, device_t child, int *irq) 64126abae3fSMichal Meloun { 64226abae3fSMichal Meloun phandle_t msi_parent; 64326abae3fSMichal Meloun int rv; 64426abae3fSMichal Meloun 64526abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 64626abae3fSMichal Meloun &msi_parent, NULL); 64726abae3fSMichal Meloun if (rv != 0) 64826abae3fSMichal Meloun return (rv); 64926abae3fSMichal Meloun return (intr_alloc_msix(pci, child, msi_parent, irq)); 65026abae3fSMichal Meloun } 65126abae3fSMichal Meloun 65226abae3fSMichal Meloun static int 65326abae3fSMichal Meloun pci_dw_release_msix(device_t pci, device_t child, int irq) 65426abae3fSMichal Meloun { 65526abae3fSMichal Meloun phandle_t msi_parent; 65626abae3fSMichal Meloun int rv; 65726abae3fSMichal Meloun 65826abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 65926abae3fSMichal Meloun &msi_parent, NULL); 66026abae3fSMichal Meloun if (rv != 0) 66126abae3fSMichal Meloun return (rv); 66226abae3fSMichal Meloun return (intr_release_msix(pci, child, msi_parent, irq)); 66326abae3fSMichal Meloun } 66426abae3fSMichal Meloun 66526abae3fSMichal Meloun static int 66626abae3fSMichal Meloun pci_dw_get_id(device_t pci, device_t child, enum pci_id_type type, 66726abae3fSMichal Meloun uintptr_t *id) 66826abae3fSMichal Meloun { 66926abae3fSMichal Meloun phandle_t node; 67026abae3fSMichal Meloun int rv; 67126abae3fSMichal Meloun uint32_t rid; 67226abae3fSMichal Meloun uint16_t pci_rid; 67326abae3fSMichal Meloun 67426abae3fSMichal Meloun if (type != PCI_ID_MSI) 67526abae3fSMichal Meloun return (pcib_get_id(pci, child, type, id)); 67626abae3fSMichal Meloun 67726abae3fSMichal Meloun node = ofw_bus_get_node(pci); 67826abae3fSMichal Meloun pci_rid = pci_get_rid(child); 67926abae3fSMichal Meloun 68026abae3fSMichal Meloun rv = ofw_bus_msimap(node, pci_rid, NULL, &rid); 68126abae3fSMichal Meloun if (rv != 0) 68226abae3fSMichal Meloun return (rv); 68326abae3fSMichal Meloun *id = rid; 68426abae3fSMichal Meloun 68526abae3fSMichal Meloun return (0); 68626abae3fSMichal Meloun } 68726abae3fSMichal Meloun 68826abae3fSMichal Meloun /*----------------------------------------------------------------------------- 68926abae3fSMichal Meloun * 69026abae3fSMichal Meloun * B U S / D E V I C E I N T E R F A C E 69126abae3fSMichal Meloun */ 69226abae3fSMichal Meloun static bus_dma_tag_t 69326abae3fSMichal Meloun pci_dw_get_dma_tag(device_t dev, device_t child) 69426abae3fSMichal Meloun { 69526abae3fSMichal Meloun struct pci_dw_softc *sc; 69626abae3fSMichal Meloun 69726abae3fSMichal Meloun sc = device_get_softc(dev); 69826abae3fSMichal Meloun return (sc->dmat); 69926abae3fSMichal Meloun } 70026abae3fSMichal Meloun 70126abae3fSMichal Meloun int 70226abae3fSMichal Meloun pci_dw_init(device_t dev) 70326abae3fSMichal Meloun { 70426abae3fSMichal Meloun struct pci_dw_softc *sc; 70526abae3fSMichal Meloun int rv, rid; 706f240dfffSJessica Clarke bool unroll_mode; 70726abae3fSMichal Meloun 70826abae3fSMichal Meloun sc = device_get_softc(dev); 70926abae3fSMichal Meloun sc->dev = dev; 71026abae3fSMichal Meloun sc->node = ofw_bus_get_node(dev); 71126abae3fSMichal Meloun 71226abae3fSMichal Meloun mtx_init(&sc->mtx, "pci_dw_mtx", NULL, MTX_DEF); 71326abae3fSMichal Meloun 71426abae3fSMichal Meloun /* XXXn Should not be this configurable ? */ 71526abae3fSMichal Meloun sc->bus_start = 0; 71626abae3fSMichal Meloun sc->bus_end = 255; 71726abae3fSMichal Meloun sc->root_bus = 0; 71826abae3fSMichal Meloun sc->sub_bus = 1; 71926abae3fSMichal Meloun 72026abae3fSMichal Meloun /* Read FDT properties */ 72126abae3fSMichal Meloun if (!sc->coherent) 72226abae3fSMichal Meloun sc->coherent = OF_hasprop(sc->node, "dma-coherent"); 72326abae3fSMichal Meloun 72426abae3fSMichal Meloun rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes, 7254707bb04SJessica Clarke sizeof(sc->num_lanes)); 72626abae3fSMichal Meloun if (rv != sizeof(sc->num_lanes)) 72726abae3fSMichal Meloun sc->num_lanes = 1; 72826abae3fSMichal Meloun if (sc->num_lanes != 1 && sc->num_lanes != 2 && 72926abae3fSMichal Meloun sc->num_lanes != 4 && sc->num_lanes != 8) { 73026abae3fSMichal Meloun device_printf(dev, 73126abae3fSMichal Meloun "invalid number of lanes: %d\n",sc->num_lanes); 73226abae3fSMichal Meloun sc->num_lanes = 0; 73326abae3fSMichal Meloun rv = ENXIO; 73426abae3fSMichal Meloun goto out; 73526abae3fSMichal Meloun } 73626abae3fSMichal Meloun 73726abae3fSMichal Meloun rid = 0; 73826abae3fSMichal Meloun rv = ofw_bus_find_string_index(sc->node, "reg-names", "config", &rid); 73926abae3fSMichal Meloun if (rv != 0) { 74026abae3fSMichal Meloun device_printf(dev, "Cannot get config space memory\n"); 74126abae3fSMichal Meloun rv = ENXIO; 74226abae3fSMichal Meloun goto out; 74326abae3fSMichal Meloun } 74426abae3fSMichal Meloun sc->cfg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 74526abae3fSMichal Meloun RF_ACTIVE); 74626abae3fSMichal Meloun if (sc->cfg_res == NULL) { 74726abae3fSMichal Meloun device_printf(dev, "Cannot allocate config space(rid: %d)\n", 74826abae3fSMichal Meloun rid); 74926abae3fSMichal Meloun rv = ENXIO; 75026abae3fSMichal Meloun goto out; 75126abae3fSMichal Meloun } 75226abae3fSMichal Meloun 75326abae3fSMichal Meloun /* Fill up config region related variables */ 75426abae3fSMichal Meloun sc->cfg_size = rman_get_size(sc->cfg_res); 75526abae3fSMichal Meloun sc->cfg_pa = rman_get_start(sc->cfg_res) ; 75626abae3fSMichal Meloun 75726abae3fSMichal Meloun if (bootverbose) 75826abae3fSMichal Meloun device_printf(dev, "Bus is%s cache-coherent\n", 75926abae3fSMichal Meloun sc->coherent ? "" : " not"); 76026abae3fSMichal Meloun rv = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 76126abae3fSMichal Meloun 1, 0, /* alignment, bounds */ 76226abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* lowaddr */ 76326abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* highaddr */ 76426abae3fSMichal Meloun NULL, NULL, /* filter, filterarg */ 76526abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsize */ 76626abae3fSMichal Meloun BUS_SPACE_UNRESTRICTED, /* nsegments */ 76726abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsegsize */ 76826abae3fSMichal Meloun sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ 76926abae3fSMichal Meloun NULL, NULL, /* lockfunc, lockarg */ 77026abae3fSMichal Meloun &sc->dmat); 77126abae3fSMichal Meloun if (rv != 0) 77226abae3fSMichal Meloun goto out; 77326abae3fSMichal Meloun 77424042910SMarcin Wojtas rv = ofw_pcib_init(dev); 77526abae3fSMichal Meloun if (rv != 0) 77626abae3fSMichal Meloun goto out; 77726abae3fSMichal Meloun rv = pci_dw_decode_ranges(sc, sc->ofw_pci.sc_range, 77826abae3fSMichal Meloun sc->ofw_pci.sc_nrange); 77926abae3fSMichal Meloun if (rv != 0) 78026abae3fSMichal Meloun goto out; 78126abae3fSMichal Meloun 782f240dfffSJessica Clarke unroll_mode = pci_dw_detect_atu_unroll(sc); 783f240dfffSJessica Clarke if (bootverbose) 784f240dfffSJessica Clarke device_printf(dev, "Using iATU %s mode\n", 785f240dfffSJessica Clarke unroll_mode ? "unroll" : "legacy"); 786f240dfffSJessica Clarke if (unroll_mode) { 787f240dfffSJessica Clarke rid = 0; 788f240dfffSJessica Clarke rv = ofw_bus_find_string_index(sc->node, "reg-names", "atu", &rid); 789f240dfffSJessica Clarke if (rv == 0) { 790f240dfffSJessica Clarke sc->iatu_ur_res = bus_alloc_resource_any(dev, 791f240dfffSJessica Clarke SYS_RES_MEMORY, &rid, RF_ACTIVE); 792f240dfffSJessica Clarke if (sc->iatu_ur_res == NULL) { 793f240dfffSJessica Clarke device_printf(dev, 794f240dfffSJessica Clarke "Cannot allocate iATU space (rid: %d)\n", 795f240dfffSJessica Clarke rid); 796f240dfffSJessica Clarke rv = ENXIO; 797f240dfffSJessica Clarke goto out; 798f240dfffSJessica Clarke } 799f240dfffSJessica Clarke sc->iatu_ur_offset = 0; 800f240dfffSJessica Clarke sc->iatu_ur_size = rman_get_size(sc->iatu_ur_res); 801f240dfffSJessica Clarke } else if (rv == ENOENT) { 802f240dfffSJessica Clarke sc->iatu_ur_res = sc->dbi_res; 803f240dfffSJessica Clarke sc->iatu_ur_offset = DW_DEFAULT_IATU_UR_DBI_OFFSET; 804f240dfffSJessica Clarke sc->iatu_ur_size = DW_DEFAULT_IATU_UR_DBI_SIZE; 805f240dfffSJessica Clarke } else { 806f240dfffSJessica Clarke device_printf(dev, "Cannot get iATU space memory\n"); 807f240dfffSJessica Clarke rv = ENXIO; 808f240dfffSJessica Clarke goto out; 809f240dfffSJessica Clarke } 810f240dfffSJessica Clarke } 811f240dfffSJessica Clarke 8124707bb04SJessica Clarke rv = pci_dw_detect_out_atu_regions(sc); 8134707bb04SJessica Clarke if (rv != 0) 8144707bb04SJessica Clarke goto out; 8154707bb04SJessica Clarke 8164707bb04SJessica Clarke if (bootverbose) 8174707bb04SJessica Clarke device_printf(sc->dev, "Detected outbound iATU regions: %d\n", 8184707bb04SJessica Clarke sc->num_out_regions); 8194707bb04SJessica Clarke 82026abae3fSMichal Meloun rv = pci_dw_setup_hw(sc); 82126abae3fSMichal Meloun if (rv != 0) 82226abae3fSMichal Meloun goto out; 82326abae3fSMichal Meloun 824*5b56413dSWarner Losh device_add_child(dev, "pci", DEVICE_UNIT_ANY); 82526abae3fSMichal Meloun 826cc2eaa04SMichal Meloun return (0); 82726abae3fSMichal Meloun out: 82826abae3fSMichal Meloun /* XXX Cleanup */ 82926abae3fSMichal Meloun return (rv); 83026abae3fSMichal Meloun } 83126abae3fSMichal Meloun 83226abae3fSMichal Meloun static device_method_t pci_dw_methods[] = { 83326abae3fSMichal Meloun /* Bus interface */ 83426abae3fSMichal Meloun DEVMETHOD(bus_get_dma_tag, pci_dw_get_dma_tag), 83526abae3fSMichal Meloun 83626abae3fSMichal Meloun /* pcib interface */ 83726abae3fSMichal Meloun DEVMETHOD(pcib_read_config, pci_dw_read_config), 83826abae3fSMichal Meloun DEVMETHOD(pcib_write_config, pci_dw_write_config), 83926abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msi, pci_dw_alloc_msi), 84026abae3fSMichal Meloun DEVMETHOD(pcib_release_msi, pci_dw_release_msi), 84126abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msix, pci_dw_alloc_msix), 84226abae3fSMichal Meloun DEVMETHOD(pcib_release_msix, pci_dw_release_msix), 84326abae3fSMichal Meloun DEVMETHOD(pcib_map_msi, pci_dw_map_msi), 84426abae3fSMichal Meloun DEVMETHOD(pcib_get_id, pci_dw_get_id), 84526abae3fSMichal Meloun 84626abae3fSMichal Meloun /* OFW bus interface */ 84726abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 84826abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 84926abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 85026abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 85126abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 85226abae3fSMichal Meloun 85326abae3fSMichal Meloun /* PCI DW interface */ 85426abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_read, pci_dw_dbi_read), 85526abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_write, pci_dw_dbi_write), 85626abae3fSMichal Meloun DEVMETHOD_END 85726abae3fSMichal Meloun }; 85826abae3fSMichal Meloun 85926abae3fSMichal Meloun DEFINE_CLASS_1(pcib, pci_dw_driver, pci_dw_methods, 86024042910SMarcin Wojtas sizeof(struct pci_dw_softc), ofw_pcib_driver); 861