1*26abae3fSMichal Meloun /*- 2*26abae3fSMichal Meloun * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*26abae3fSMichal Meloun * 4*26abae3fSMichal Meloun * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> 5*26abae3fSMichal Meloun * 6*26abae3fSMichal Meloun * Redistribution and use in source and binary forms, with or without 7*26abae3fSMichal Meloun * modification, are permitted provided that the following conditions 8*26abae3fSMichal Meloun * are met: 9*26abae3fSMichal Meloun * 1. Redistributions of source code must retain the above copyright 10*26abae3fSMichal Meloun * notice, this list of conditions and the following disclaimer. 11*26abae3fSMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 12*26abae3fSMichal Meloun * notice, this list of conditions and the following disclaimer in the 13*26abae3fSMichal Meloun * documentation and/or other materials provided with the distribution. 14*26abae3fSMichal Meloun * 15*26abae3fSMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*26abae3fSMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*26abae3fSMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*26abae3fSMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*26abae3fSMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*26abae3fSMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*26abae3fSMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*26abae3fSMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*26abae3fSMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*26abae3fSMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*26abae3fSMichal Meloun * SUCH DAMAGE. 26*26abae3fSMichal Meloun * 27*26abae3fSMichal Meloun */ 28*26abae3fSMichal Meloun 29*26abae3fSMichal Meloun /* Base class for all Synopsys DesignWare PCI/PCIe drivers */ 30*26abae3fSMichal Meloun 31*26abae3fSMichal Meloun #include <sys/cdefs.h> 32*26abae3fSMichal Meloun __FBSDID("$FreeBSD$"); 33*26abae3fSMichal Meloun 34*26abae3fSMichal Meloun 35*26abae3fSMichal Meloun #include <sys/param.h> 36*26abae3fSMichal Meloun #include <sys/systm.h> 37*26abae3fSMichal Meloun #include <sys/bus.h> 38*26abae3fSMichal Meloun #include <sys/devmap.h> 39*26abae3fSMichal Meloun #include <sys/proc.h> 40*26abae3fSMichal Meloun #include <sys/kernel.h> 41*26abae3fSMichal Meloun #include <sys/lock.h> 42*26abae3fSMichal Meloun #include <sys/malloc.h> 43*26abae3fSMichal Meloun #include <sys/module.h> 44*26abae3fSMichal Meloun #include <sys/mutex.h> 45*26abae3fSMichal Meloun #include <sys/rman.h> 46*26abae3fSMichal Meloun 47*26abae3fSMichal Meloun #include <machine/bus.h> 48*26abae3fSMichal Meloun #include <machine/intr.h> 49*26abae3fSMichal Meloun #include <machine/resource.h> 50*26abae3fSMichal Meloun 51*26abae3fSMichal Meloun #include <dev/ofw/ofw_bus.h> 52*26abae3fSMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 53*26abae3fSMichal Meloun #include <dev/ofw/ofw_pci.h> 54*26abae3fSMichal Meloun #include <dev/ofw/ofwpci.h> 55*26abae3fSMichal Meloun #include <dev/pci/pcivar.h> 56*26abae3fSMichal Meloun #include <dev/pci/pcireg.h> 57*26abae3fSMichal Meloun #include <dev/pci/pcib_private.h> 58*26abae3fSMichal Meloun #include <dev/pci/pci_dw.h> 59*26abae3fSMichal Meloun 60*26abae3fSMichal Meloun #include "pcib_if.h" 61*26abae3fSMichal Meloun #include "pci_dw_if.h" 62*26abae3fSMichal Meloun 63*26abae3fSMichal Meloun #define DEBUG 64*26abae3fSMichal Meloun #ifdef DEBUG 65*26abae3fSMichal Meloun #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 66*26abae3fSMichal Meloun #else 67*26abae3fSMichal Meloun #define debugf(fmt, args...) 68*26abae3fSMichal Meloun #endif 69*26abae3fSMichal Meloun 70*26abae3fSMichal Meloun #define DBI_WR1(sc, reg, val) pci_dw_dbi_wr1((sc)->dev, reg, val) 71*26abae3fSMichal Meloun #define DBI_WR2(sc, reg, val) pci_dw_dbi_wr2((sc)->dev, reg, val) 72*26abae3fSMichal Meloun #define DBI_WR4(sc, reg, val) pci_dw_dbi_wr4((sc)->dev, reg, val) 73*26abae3fSMichal Meloun #define DBI_RD1(sc, reg) pci_dw_dbi_rd1((sc)->dev, reg) 74*26abae3fSMichal Meloun #define DBI_RD2(sc, reg) pci_dw_dbi_rd2((sc)->dev, reg) 75*26abae3fSMichal Meloun #define DBI_RD4(sc, reg) pci_dw_dbi_rd4((sc)->dev, reg) 76*26abae3fSMichal Meloun 77*26abae3fSMichal Meloun #define PCI_BUS_SHIFT 20 78*26abae3fSMichal Meloun #define PCI_SLOT_SHIFT 15 79*26abae3fSMichal Meloun #define PCI_FUNC_SHIFT 12 80*26abae3fSMichal Meloun #define PCI_BUS_MASK 0xFF 81*26abae3fSMichal Meloun #define PCI_SLOT_MASK 0x1F 82*26abae3fSMichal Meloun #define PCI_FUNC_MASK 0x07 83*26abae3fSMichal Meloun #define PCI_REG_MASK 0xFFF 84*26abae3fSMichal Meloun 85*26abae3fSMichal Meloun 86*26abae3fSMichal Meloun #define IATU_CFG_BUS(bus) ((uint64_t)((bus) & 0xff) << 24) 87*26abae3fSMichal Meloun #define IATU_CFG_SLOT(slot) ((uint64_t)((slot) & 0x1f) << 19) 88*26abae3fSMichal Meloun #define IATU_CFG_FUNC(func) ((uint64_t)((func) & 0x07) << 16) 89*26abae3fSMichal Meloun 90*26abae3fSMichal Meloun 91*26abae3fSMichal Meloun 92*26abae3fSMichal Meloun static uint32_t 93*26abae3fSMichal Meloun pci_dw_dbi_read(device_t dev, u_int reg, int width) 94*26abae3fSMichal Meloun { 95*26abae3fSMichal Meloun struct pci_dw_softc *sc; 96*26abae3fSMichal Meloun 97*26abae3fSMichal Meloun sc = device_get_softc(dev); 98*26abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 99*26abae3fSMichal Meloun 100*26abae3fSMichal Meloun switch (width) { 101*26abae3fSMichal Meloun case 4: 102*26abae3fSMichal Meloun return (bus_read_4(sc->dbi_res, reg)); 103*26abae3fSMichal Meloun case 2: 104*26abae3fSMichal Meloun return (bus_read_2(sc->dbi_res, reg)); 105*26abae3fSMichal Meloun case 1: 106*26abae3fSMichal Meloun return (bus_read_1(sc->dbi_res, reg)); 107*26abae3fSMichal Meloun default: 108*26abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 109*26abae3fSMichal Meloun return (0xFFFFFFFF); 110*26abae3fSMichal Meloun } 111*26abae3fSMichal Meloun } 112*26abae3fSMichal Meloun 113*26abae3fSMichal Meloun static void 114*26abae3fSMichal Meloun pci_dw_dbi_write(device_t dev, u_int reg, uint32_t val, int width) 115*26abae3fSMichal Meloun { 116*26abae3fSMichal Meloun struct pci_dw_softc *sc; 117*26abae3fSMichal Meloun 118*26abae3fSMichal Meloun sc = device_get_softc(dev); 119*26abae3fSMichal Meloun MPASS(sc->dbi_res != NULL); 120*26abae3fSMichal Meloun 121*26abae3fSMichal Meloun switch (width) { 122*26abae3fSMichal Meloun case 4: 123*26abae3fSMichal Meloun bus_write_4(sc->dbi_res, reg, val); 124*26abae3fSMichal Meloun break; 125*26abae3fSMichal Meloun case 2: 126*26abae3fSMichal Meloun bus_write_2(sc->dbi_res, reg, val); 127*26abae3fSMichal Meloun break; 128*26abae3fSMichal Meloun case 1: 129*26abae3fSMichal Meloun bus_write_1(sc->dbi_res, reg, val); 130*26abae3fSMichal Meloun break; 131*26abae3fSMichal Meloun default: 132*26abae3fSMichal Meloun device_printf(sc->dev, "Unsupported width: %d\n", width); 133*26abae3fSMichal Meloun break; 134*26abae3fSMichal Meloun } 135*26abae3fSMichal Meloun } 136*26abae3fSMichal Meloun 137*26abae3fSMichal Meloun 138*26abae3fSMichal Meloun static void 139*26abae3fSMichal Meloun pci_dw_dbi_protect(struct pci_dw_softc *sc, bool protect) 140*26abae3fSMichal Meloun { 141*26abae3fSMichal Meloun uint32_t reg; 142*26abae3fSMichal Meloun 143*26abae3fSMichal Meloun reg = DBI_RD4(sc, DW_MISC_CONTROL_1); 144*26abae3fSMichal Meloun if (protect) 145*26abae3fSMichal Meloun reg &= ~DBI_RO_WR_EN; 146*26abae3fSMichal Meloun else 147*26abae3fSMichal Meloun reg |= DBI_RO_WR_EN; 148*26abae3fSMichal Meloun DBI_WR4(sc, DW_MISC_CONTROL_1, reg); 149*26abae3fSMichal Meloun } 150*26abae3fSMichal Meloun 151*26abae3fSMichal Meloun static bool 152*26abae3fSMichal Meloun pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int slot, u_int func, 153*26abae3fSMichal Meloun u_int reg) 154*26abae3fSMichal Meloun { 155*26abae3fSMichal Meloun bool status; 156*26abae3fSMichal Meloun int rv; 157*26abae3fSMichal Meloun 158*26abae3fSMichal Meloun if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX || 159*26abae3fSMichal Meloun func > PCI_FUNCMAX || reg > PCI_REGMAX) 160*26abae3fSMichal Meloun return (false); 161*26abae3fSMichal Meloun 162*26abae3fSMichal Meloun /* link is needed for access to all non-root busses */ 163*26abae3fSMichal Meloun if (bus != sc->root_bus) { 164*26abae3fSMichal Meloun rv = PCI_DW_GET_LINK(sc->dev, &status); 165*26abae3fSMichal Meloun if (rv != 0 || !status) 166*26abae3fSMichal Meloun return (false); 167*26abae3fSMichal Meloun return (true); 168*26abae3fSMichal Meloun } 169*26abae3fSMichal Meloun 170*26abae3fSMichal Meloun /* we have only 1 device with 1 function root port */ 171*26abae3fSMichal Meloun if (slot > 0 || func > 0) 172*26abae3fSMichal Meloun return (false); 173*26abae3fSMichal Meloun return (true); 174*26abae3fSMichal Meloun } 175*26abae3fSMichal Meloun 176*26abae3fSMichal Meloun /* Map one uoutbound ATU region */ 177*26abae3fSMichal Meloun static int 178*26abae3fSMichal Meloun pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type, 179*26abae3fSMichal Meloun uint64_t pa, uint64_t pci_addr, uint32_t size) 180*26abae3fSMichal Meloun { 181*26abae3fSMichal Meloun uint32_t reg; 182*26abae3fSMichal Meloun int i; 183*26abae3fSMichal Meloun 184*26abae3fSMichal Meloun if (size == 0) 185*26abae3fSMichal Meloun return (0); 186*26abae3fSMichal Meloun 187*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(idx)); 188*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_BASE_ADDR, pa & 0xFFFFFFFF); 189*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_BASE_ADDR, (pa >> 32) & 0xFFFFFFFF); 190*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LIMIT_ADDR, (pa + size - 1) & 0xFFFFFFFF); 191*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, pci_addr & 0xFFFFFFFF); 192*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_UPPER_TARGET_ADDR, (pci_addr >> 32) & 0xFFFFFFFF); 193*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL1, IATU_CTRL1_TYPE(type)); 194*26abae3fSMichal Meloun DBI_WR4(sc, DW_IATU_CTRL2, IATU_CTRL2_REGION_EN); 195*26abae3fSMichal Meloun 196*26abae3fSMichal Meloun /* Wait until setup becomes valid */ 197*26abae3fSMichal Meloun for (i = 10; i > 0; i--) { 198*26abae3fSMichal Meloun reg = DBI_RD4(sc, DW_IATU_CTRL2); 199*26abae3fSMichal Meloun if (reg & IATU_CTRL2_REGION_EN) 200*26abae3fSMichal Meloun return (0); 201*26abae3fSMichal Meloun DELAY(5); 202*26abae3fSMichal Meloun } 203*26abae3fSMichal Meloun device_printf(sc->dev, 204*26abae3fSMichal Meloun "Cannot map outbound region(%d) in iATU\n", idx); 205*26abae3fSMichal Meloun return (ETIMEDOUT); 206*26abae3fSMichal Meloun } 207*26abae3fSMichal Meloun 208*26abae3fSMichal Meloun static int 209*26abae3fSMichal Meloun pci_dw_setup_hw(struct pci_dw_softc *sc) 210*26abae3fSMichal Meloun { 211*26abae3fSMichal Meloun uint32_t reg; 212*26abae3fSMichal Meloun int rv; 213*26abae3fSMichal Meloun 214*26abae3fSMichal Meloun pci_dw_dbi_protect(sc, false); 215*26abae3fSMichal Meloun 216*26abae3fSMichal Meloun /* Setup config registers */ 217*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_CLASS, PCIC_BRIDGE); 218*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); 219*26abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(0), 4); 220*26abae3fSMichal Meloun DBI_WR4(sc, PCIR_BAR(1), 0); 221*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_INTPIN, 1); 222*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_PRIBUS_1, sc->root_bus); 223*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_SECBUS_1, sc->sub_bus); 224*26abae3fSMichal Meloun DBI_WR1(sc, PCIR_SUBBUS_1, sc->bus_end); 225*26abae3fSMichal Meloun DBI_WR2(sc, PCIR_COMMAND, 226*26abae3fSMichal Meloun PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | 227*26abae3fSMichal Meloun PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN); 228*26abae3fSMichal Meloun pci_dw_dbi_protect(sc, true); 229*26abae3fSMichal Meloun 230*26abae3fSMichal Meloun /* Setup outbound memory window */ 231*26abae3fSMichal Meloun rv = pci_dw_map_out_atu(sc, 0, IATU_CTRL1_TYPE_MEM, 232*26abae3fSMichal Meloun sc->mem_range.host, sc->mem_range.pci, sc->mem_range.size); 233*26abae3fSMichal Meloun if (rv != 0) 234*26abae3fSMichal Meloun return (rv); 235*26abae3fSMichal Meloun 236*26abae3fSMichal Meloun /* If we have enouht viewports ..*/ 237*26abae3fSMichal Meloun if (sc->num_viewport >= 3) { 238*26abae3fSMichal Meloun /* Setup outbound I/O window */ 239*26abae3fSMichal Meloun rv = pci_dw_map_out_atu(sc, 0, IATU_CTRL1_TYPE_MEM, 240*26abae3fSMichal Meloun sc->io_range.host, sc->io_range.pci, sc->io_range.size); 241*26abae3fSMichal Meloun if (rv != 0) 242*26abae3fSMichal Meloun return (rv); 243*26abae3fSMichal Meloun } 244*26abae3fSMichal Meloun /* XXX Should we handle also prefetch memory? */ 245*26abae3fSMichal Meloun 246*26abae3fSMichal Meloun 247*26abae3fSMichal Meloun /* Adjust number of lanes */ 248*26abae3fSMichal Meloun reg = DBI_RD4(sc, DW_PORT_LINK_CTRL); 249*26abae3fSMichal Meloun reg &= ~PORT_LINK_CAPABLE(~0); 250*26abae3fSMichal Meloun switch (sc->num_lanes) { 251*26abae3fSMichal Meloun case 1: 252*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_1); 253*26abae3fSMichal Meloun break; 254*26abae3fSMichal Meloun case 2: 255*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_2); 256*26abae3fSMichal Meloun break; 257*26abae3fSMichal Meloun case 4: 258*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_4); 259*26abae3fSMichal Meloun break; 260*26abae3fSMichal Meloun case 8: 261*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_8); 262*26abae3fSMichal Meloun break; 263*26abae3fSMichal Meloun case 16: 264*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_16); 265*26abae3fSMichal Meloun break; 266*26abae3fSMichal Meloun case 32: 267*26abae3fSMichal Meloun reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_32); 268*26abae3fSMichal Meloun break; 269*26abae3fSMichal Meloun default: 270*26abae3fSMichal Meloun device_printf(sc->dev, 271*26abae3fSMichal Meloun "'num-lanes' property have invalid value: %d\n", 272*26abae3fSMichal Meloun sc->num_lanes); 273*26abae3fSMichal Meloun return (EINVAL); 274*26abae3fSMichal Meloun } 275*26abae3fSMichal Meloun DBI_WR4(sc, DW_PORT_LINK_CTRL, reg); 276*26abae3fSMichal Meloun 277*26abae3fSMichal Meloun 278*26abae3fSMichal Meloun /* And link width */ 279*26abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 280*26abae3fSMichal Meloun reg &= ~GEN2_CTRL_NUM_OF_LANES(~0); 281*26abae3fSMichal Meloun switch (sc->num_lanes) { 282*26abae3fSMichal Meloun case 1: 283*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_1); 284*26abae3fSMichal Meloun break; 285*26abae3fSMichal Meloun case 2: 286*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_2); 287*26abae3fSMichal Meloun break; 288*26abae3fSMichal Meloun case 4: 289*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_4); 290*26abae3fSMichal Meloun break; 291*26abae3fSMichal Meloun case 8: 292*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_8); 293*26abae3fSMichal Meloun break; 294*26abae3fSMichal Meloun case 16: 295*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_16); 296*26abae3fSMichal Meloun break; 297*26abae3fSMichal Meloun case 32: 298*26abae3fSMichal Meloun reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_32); 299*26abae3fSMichal Meloun break; 300*26abae3fSMichal Meloun } 301*26abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 302*26abae3fSMichal Meloun 303*26abae3fSMichal Meloun reg = DBI_RD4(sc, DW_GEN2_CTRL); 304*26abae3fSMichal Meloun reg |= DIRECT_SPEED_CHANGE; 305*26abae3fSMichal Meloun DBI_WR4(sc, DW_GEN2_CTRL, reg); 306*26abae3fSMichal Meloun 307*26abae3fSMichal Meloun 308*26abae3fSMichal Meloun return (0); 309*26abae3fSMichal Meloun } 310*26abae3fSMichal Meloun 311*26abae3fSMichal Meloun static int 312*26abae3fSMichal Meloun pci_dw_decode_ranges(struct pci_dw_softc *sc, struct ofw_pci_range *ranges, 313*26abae3fSMichal Meloun int nranges) 314*26abae3fSMichal Meloun { 315*26abae3fSMichal Meloun int i; 316*26abae3fSMichal Meloun 317*26abae3fSMichal Meloun for (i = 0; i < nranges; i++) { 318*26abae3fSMichal Meloun if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 319*26abae3fSMichal Meloun OFW_PCI_PHYS_HI_SPACE_IO) { 320*26abae3fSMichal Meloun if (sc->io_range.size != 0) { 321*26abae3fSMichal Meloun device_printf(sc->dev, 322*26abae3fSMichal Meloun "Duplicated IO range found in DT\n"); 323*26abae3fSMichal Meloun return (ENXIO); 324*26abae3fSMichal Meloun } 325*26abae3fSMichal Meloun sc->io_range = ranges[i]; 326*26abae3fSMichal Meloun } 327*26abae3fSMichal Meloun if (((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 328*26abae3fSMichal Meloun OFW_PCI_PHYS_HI_SPACE_MEM32)) { 329*26abae3fSMichal Meloun if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { 330*26abae3fSMichal Meloun if (sc->pref_mem_range.size != 0) { 331*26abae3fSMichal Meloun device_printf(sc->dev, 332*26abae3fSMichal Meloun "Duplicated memory range found " 333*26abae3fSMichal Meloun "in DT\n"); 334*26abae3fSMichal Meloun return (ENXIO); 335*26abae3fSMichal Meloun } 336*26abae3fSMichal Meloun sc->pref_mem_range = ranges[i]; 337*26abae3fSMichal Meloun } else { 338*26abae3fSMichal Meloun if (sc->mem_range.size != 0) { 339*26abae3fSMichal Meloun device_printf(sc->dev, 340*26abae3fSMichal Meloun "Duplicated memory range found " 341*26abae3fSMichal Meloun "in DT\n"); 342*26abae3fSMichal Meloun return (ENXIO); 343*26abae3fSMichal Meloun } 344*26abae3fSMichal Meloun sc->mem_range = ranges[i]; 345*26abae3fSMichal Meloun } 346*26abae3fSMichal Meloun } 347*26abae3fSMichal Meloun } 348*26abae3fSMichal Meloun if ((sc->io_range.size == 0) || (sc->mem_range.size == 0)) { 349*26abae3fSMichal Meloun device_printf(sc->dev, 350*26abae3fSMichal Meloun " Not all required ranges are found in DT\n"); 351*26abae3fSMichal Meloun return (ENXIO); 352*26abae3fSMichal Meloun } 353*26abae3fSMichal Meloun return (0); 354*26abae3fSMichal Meloun } 355*26abae3fSMichal Meloun 356*26abae3fSMichal Meloun 357*26abae3fSMichal Meloun 358*26abae3fSMichal Meloun /*----------------------------------------------------------------------------- 359*26abae3fSMichal Meloun * 360*26abae3fSMichal Meloun * P C I B I N T E R F A C E 361*26abae3fSMichal Meloun */ 362*26abae3fSMichal Meloun 363*26abae3fSMichal Meloun static uint32_t 364*26abae3fSMichal Meloun pci_dw_read_config(device_t dev, u_int bus, u_int slot, 365*26abae3fSMichal Meloun u_int func, u_int reg, int bytes) 366*26abae3fSMichal Meloun { 367*26abae3fSMichal Meloun struct pci_dw_softc *sc; 368*26abae3fSMichal Meloun struct resource *res; 369*26abae3fSMichal Meloun uint32_t data; 370*26abae3fSMichal Meloun uint64_t addr; 371*26abae3fSMichal Meloun int type, rv; 372*26abae3fSMichal Meloun 373*26abae3fSMichal Meloun sc = device_get_softc(dev); 374*26abae3fSMichal Meloun 375*26abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 376*26abae3fSMichal Meloun return (0xFFFFFFFFU); 377*26abae3fSMichal Meloun 378*26abae3fSMichal Meloun if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || 379*26abae3fSMichal Meloun (reg > PCI_REGMAX)) 380*26abae3fSMichal Meloun return (0xFFFFFFFFU); 381*26abae3fSMichal Meloun 382*26abae3fSMichal Meloun if (bus == sc->root_bus) { 383*26abae3fSMichal Meloun res = (sc->dbi_res); 384*26abae3fSMichal Meloun } else { 385*26abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 386*26abae3fSMichal Meloun IATU_CFG_FUNC(func); 387*26abae3fSMichal Meloun if (bus == sc->sub_bus) 388*26abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 389*26abae3fSMichal Meloun else 390*26abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 391*26abae3fSMichal Meloun rv = pci_dw_map_out_atu(sc, 1, type, 392*26abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 393*26abae3fSMichal Meloun if (rv != 0) 394*26abae3fSMichal Meloun return (0xFFFFFFFFU); 395*26abae3fSMichal Meloun res = sc->cfg_res; 396*26abae3fSMichal Meloun } 397*26abae3fSMichal Meloun 398*26abae3fSMichal Meloun switch (bytes) { 399*26abae3fSMichal Meloun case 1: 400*26abae3fSMichal Meloun data = bus_read_1(res, reg); 401*26abae3fSMichal Meloun break; 402*26abae3fSMichal Meloun case 2: 403*26abae3fSMichal Meloun data = bus_read_2(res, reg); 404*26abae3fSMichal Meloun break; 405*26abae3fSMichal Meloun case 4: 406*26abae3fSMichal Meloun data = bus_read_4(res, reg); 407*26abae3fSMichal Meloun break; 408*26abae3fSMichal Meloun default: 409*26abae3fSMichal Meloun data = 0xFFFFFFFFU; 410*26abae3fSMichal Meloun } 411*26abae3fSMichal Meloun 412*26abae3fSMichal Meloun return (data); 413*26abae3fSMichal Meloun 414*26abae3fSMichal Meloun } 415*26abae3fSMichal Meloun 416*26abae3fSMichal Meloun static void 417*26abae3fSMichal Meloun pci_dw_write_config(device_t dev, u_int bus, u_int slot, 418*26abae3fSMichal Meloun u_int func, u_int reg, uint32_t val, int bytes) 419*26abae3fSMichal Meloun { 420*26abae3fSMichal Meloun struct pci_dw_softc *sc; 421*26abae3fSMichal Meloun struct resource *res; 422*26abae3fSMichal Meloun uint64_t addr; 423*26abae3fSMichal Meloun int type, rv; 424*26abae3fSMichal Meloun 425*26abae3fSMichal Meloun sc = device_get_softc(dev); 426*26abae3fSMichal Meloun if (!pci_dw_check_dev(sc, bus, slot, func, reg)) 427*26abae3fSMichal Meloun return; 428*26abae3fSMichal Meloun 429*26abae3fSMichal Meloun if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || 430*26abae3fSMichal Meloun (reg > PCI_REGMAX)) 431*26abae3fSMichal Meloun return; 432*26abae3fSMichal Meloun 433*26abae3fSMichal Meloun if (bus == sc->root_bus) { 434*26abae3fSMichal Meloun res = (sc->dbi_res); 435*26abae3fSMichal Meloun } else { 436*26abae3fSMichal Meloun addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | 437*26abae3fSMichal Meloun IATU_CFG_FUNC(func); 438*26abae3fSMichal Meloun if (bus == sc->sub_bus) 439*26abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG0; 440*26abae3fSMichal Meloun else 441*26abae3fSMichal Meloun type = IATU_CTRL1_TYPE_CFG1; 442*26abae3fSMichal Meloun rv = pci_dw_map_out_atu(sc, 1, type, 443*26abae3fSMichal Meloun sc->cfg_pa, addr, sc->cfg_size); 444*26abae3fSMichal Meloun if (rv != 0) 445*26abae3fSMichal Meloun return ; 446*26abae3fSMichal Meloun res = sc->cfg_res; 447*26abae3fSMichal Meloun } 448*26abae3fSMichal Meloun 449*26abae3fSMichal Meloun 450*26abae3fSMichal Meloun switch (bytes) { 451*26abae3fSMichal Meloun case 1: 452*26abae3fSMichal Meloun bus_write_1(res, reg, val); 453*26abae3fSMichal Meloun break; 454*26abae3fSMichal Meloun case 2: 455*26abae3fSMichal Meloun bus_write_2(res, reg, val); 456*26abae3fSMichal Meloun break; 457*26abae3fSMichal Meloun case 4: 458*26abae3fSMichal Meloun bus_write_4(res, reg, val); 459*26abae3fSMichal Meloun break; 460*26abae3fSMichal Meloun default: 461*26abae3fSMichal Meloun break; 462*26abae3fSMichal Meloun } 463*26abae3fSMichal Meloun } 464*26abae3fSMichal Meloun 465*26abae3fSMichal Meloun static int 466*26abae3fSMichal Meloun pci_dw_alloc_msi(device_t pci, device_t child, int count, 467*26abae3fSMichal Meloun int maxcount, int *irqs) 468*26abae3fSMichal Meloun { 469*26abae3fSMichal Meloun phandle_t msi_parent; 470*26abae3fSMichal Meloun int rv; 471*26abae3fSMichal Meloun 472*26abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 473*26abae3fSMichal Meloun &msi_parent, NULL); 474*26abae3fSMichal Meloun if (rv != 0) 475*26abae3fSMichal Meloun return (rv); 476*26abae3fSMichal Meloun 477*26abae3fSMichal Meloun return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 478*26abae3fSMichal Meloun irqs)); 479*26abae3fSMichal Meloun } 480*26abae3fSMichal Meloun 481*26abae3fSMichal Meloun static int 482*26abae3fSMichal Meloun pci_dw_release_msi(device_t pci, device_t child, int count, int *irqs) 483*26abae3fSMichal Meloun { 484*26abae3fSMichal Meloun phandle_t msi_parent; 485*26abae3fSMichal Meloun int rv; 486*26abae3fSMichal Meloun 487*26abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 488*26abae3fSMichal Meloun &msi_parent, NULL); 489*26abae3fSMichal Meloun if (rv != 0) 490*26abae3fSMichal Meloun return (rv); 491*26abae3fSMichal Meloun return (intr_release_msi(pci, child, msi_parent, count, irqs)); 492*26abae3fSMichal Meloun } 493*26abae3fSMichal Meloun 494*26abae3fSMichal Meloun static int 495*26abae3fSMichal Meloun pci_dw_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 496*26abae3fSMichal Meloun uint32_t *data) 497*26abae3fSMichal Meloun { 498*26abae3fSMichal Meloun phandle_t msi_parent; 499*26abae3fSMichal Meloun int rv; 500*26abae3fSMichal Meloun 501*26abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 502*26abae3fSMichal Meloun &msi_parent, NULL); 503*26abae3fSMichal Meloun if (rv != 0) 504*26abae3fSMichal Meloun return (rv); 505*26abae3fSMichal Meloun 506*26abae3fSMichal Meloun return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 507*26abae3fSMichal Meloun } 508*26abae3fSMichal Meloun 509*26abae3fSMichal Meloun static int 510*26abae3fSMichal Meloun pci_dw_alloc_msix(device_t pci, device_t child, int *irq) 511*26abae3fSMichal Meloun { 512*26abae3fSMichal Meloun phandle_t msi_parent; 513*26abae3fSMichal Meloun int rv; 514*26abae3fSMichal Meloun 515*26abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 516*26abae3fSMichal Meloun &msi_parent, NULL); 517*26abae3fSMichal Meloun if (rv != 0) 518*26abae3fSMichal Meloun return (rv); 519*26abae3fSMichal Meloun return (intr_alloc_msix(pci, child, msi_parent, irq)); 520*26abae3fSMichal Meloun } 521*26abae3fSMichal Meloun 522*26abae3fSMichal Meloun static int 523*26abae3fSMichal Meloun pci_dw_release_msix(device_t pci, device_t child, int irq) 524*26abae3fSMichal Meloun { 525*26abae3fSMichal Meloun phandle_t msi_parent; 526*26abae3fSMichal Meloun int rv; 527*26abae3fSMichal Meloun 528*26abae3fSMichal Meloun rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), 529*26abae3fSMichal Meloun &msi_parent, NULL); 530*26abae3fSMichal Meloun if (rv != 0) 531*26abae3fSMichal Meloun return (rv); 532*26abae3fSMichal Meloun return (intr_release_msix(pci, child, msi_parent, irq)); 533*26abae3fSMichal Meloun } 534*26abae3fSMichal Meloun 535*26abae3fSMichal Meloun static int 536*26abae3fSMichal Meloun pci_dw_get_id(device_t pci, device_t child, enum pci_id_type type, 537*26abae3fSMichal Meloun uintptr_t *id) 538*26abae3fSMichal Meloun { 539*26abae3fSMichal Meloun phandle_t node; 540*26abae3fSMichal Meloun int rv; 541*26abae3fSMichal Meloun uint32_t rid; 542*26abae3fSMichal Meloun uint16_t pci_rid; 543*26abae3fSMichal Meloun 544*26abae3fSMichal Meloun if (type != PCI_ID_MSI) 545*26abae3fSMichal Meloun return (pcib_get_id(pci, child, type, id)); 546*26abae3fSMichal Meloun 547*26abae3fSMichal Meloun node = ofw_bus_get_node(pci); 548*26abae3fSMichal Meloun pci_rid = pci_get_rid(child); 549*26abae3fSMichal Meloun 550*26abae3fSMichal Meloun rv = ofw_bus_msimap(node, pci_rid, NULL, &rid); 551*26abae3fSMichal Meloun if (rv != 0) 552*26abae3fSMichal Meloun return (rv); 553*26abae3fSMichal Meloun *id = rid; 554*26abae3fSMichal Meloun 555*26abae3fSMichal Meloun return (0); 556*26abae3fSMichal Meloun } 557*26abae3fSMichal Meloun 558*26abae3fSMichal Meloun /*----------------------------------------------------------------------------- 559*26abae3fSMichal Meloun * 560*26abae3fSMichal Meloun * B U S / D E V I C E I N T E R F A C E 561*26abae3fSMichal Meloun */ 562*26abae3fSMichal Meloun static bus_dma_tag_t 563*26abae3fSMichal Meloun pci_dw_get_dma_tag(device_t dev, device_t child) 564*26abae3fSMichal Meloun { 565*26abae3fSMichal Meloun struct pci_dw_softc *sc; 566*26abae3fSMichal Meloun 567*26abae3fSMichal Meloun sc = device_get_softc(dev); 568*26abae3fSMichal Meloun return (sc->dmat); 569*26abae3fSMichal Meloun } 570*26abae3fSMichal Meloun 571*26abae3fSMichal Meloun int 572*26abae3fSMichal Meloun pci_dw_init(device_t dev) 573*26abae3fSMichal Meloun { 574*26abae3fSMichal Meloun struct pci_dw_softc *sc; 575*26abae3fSMichal Meloun int rv, rid; 576*26abae3fSMichal Meloun 577*26abae3fSMichal Meloun sc = device_get_softc(dev); 578*26abae3fSMichal Meloun sc->dev = dev; 579*26abae3fSMichal Meloun sc->node = ofw_bus_get_node(dev); 580*26abae3fSMichal Meloun 581*26abae3fSMichal Meloun mtx_init(&sc->mtx, "pci_dw_mtx", NULL, MTX_DEF); 582*26abae3fSMichal Meloun 583*26abae3fSMichal Meloun /* XXXn Should not be this configurable ? */ 584*26abae3fSMichal Meloun sc->bus_start = 0; 585*26abae3fSMichal Meloun sc->bus_end = 255; 586*26abae3fSMichal Meloun sc->root_bus = 0; 587*26abae3fSMichal Meloun sc->sub_bus = 1; 588*26abae3fSMichal Meloun 589*26abae3fSMichal Meloun /* Read FDT properties */ 590*26abae3fSMichal Meloun if (!sc->coherent) 591*26abae3fSMichal Meloun sc->coherent = OF_hasprop(sc->node, "dma-coherent"); 592*26abae3fSMichal Meloun 593*26abae3fSMichal Meloun rv = OF_getencprop(sc->node, "num-viewport", &sc->num_viewport, 594*26abae3fSMichal Meloun sizeof(sc->num_viewport)); 595*26abae3fSMichal Meloun if (rv != sizeof(sc->num_viewport)) 596*26abae3fSMichal Meloun sc->num_viewport = 2; 597*26abae3fSMichal Meloun 598*26abae3fSMichal Meloun rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes, 599*26abae3fSMichal Meloun sizeof(sc->num_viewport)); 600*26abae3fSMichal Meloun if (rv != sizeof(sc->num_lanes)) 601*26abae3fSMichal Meloun sc->num_lanes = 1; 602*26abae3fSMichal Meloun if (sc->num_lanes != 1 && sc->num_lanes != 2 && 603*26abae3fSMichal Meloun sc->num_lanes != 4 && sc->num_lanes != 8) { 604*26abae3fSMichal Meloun device_printf(dev, 605*26abae3fSMichal Meloun "invalid number of lanes: %d\n",sc->num_lanes); 606*26abae3fSMichal Meloun sc->num_lanes = 0; 607*26abae3fSMichal Meloun rv = ENXIO; 608*26abae3fSMichal Meloun goto out; 609*26abae3fSMichal Meloun } 610*26abae3fSMichal Meloun 611*26abae3fSMichal Meloun rid = 0; 612*26abae3fSMichal Meloun rv = ofw_bus_find_string_index(sc->node, "reg-names", "config", &rid); 613*26abae3fSMichal Meloun if (rv != 0) { 614*26abae3fSMichal Meloun device_printf(dev, "Cannot get config space memory\n"); 615*26abae3fSMichal Meloun rv = ENXIO; 616*26abae3fSMichal Meloun goto out; 617*26abae3fSMichal Meloun } 618*26abae3fSMichal Meloun sc->cfg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 619*26abae3fSMichal Meloun RF_ACTIVE); 620*26abae3fSMichal Meloun if (sc->cfg_res == NULL) { 621*26abae3fSMichal Meloun device_printf(dev, "Cannot allocate config space(rid: %d)\n", 622*26abae3fSMichal Meloun rid); 623*26abae3fSMichal Meloun rv = ENXIO; 624*26abae3fSMichal Meloun goto out; 625*26abae3fSMichal Meloun } 626*26abae3fSMichal Meloun 627*26abae3fSMichal Meloun /* Fill up config region related variables */ 628*26abae3fSMichal Meloun sc->cfg_size = rman_get_size(sc->cfg_res); 629*26abae3fSMichal Meloun sc->cfg_pa = rman_get_start(sc->cfg_res) ; 630*26abae3fSMichal Meloun 631*26abae3fSMichal Meloun if (bootverbose) 632*26abae3fSMichal Meloun device_printf(dev, "Bus is%s cache-coherent\n", 633*26abae3fSMichal Meloun sc->coherent ? "" : " not"); 634*26abae3fSMichal Meloun rv = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 635*26abae3fSMichal Meloun 1, 0, /* alignment, bounds */ 636*26abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* lowaddr */ 637*26abae3fSMichal Meloun BUS_SPACE_MAXADDR, /* highaddr */ 638*26abae3fSMichal Meloun NULL, NULL, /* filter, filterarg */ 639*26abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsize */ 640*26abae3fSMichal Meloun BUS_SPACE_UNRESTRICTED, /* nsegments */ 641*26abae3fSMichal Meloun BUS_SPACE_MAXSIZE, /* maxsegsize */ 642*26abae3fSMichal Meloun sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ 643*26abae3fSMichal Meloun NULL, NULL, /* lockfunc, lockarg */ 644*26abae3fSMichal Meloun &sc->dmat); 645*26abae3fSMichal Meloun if (rv != 0) 646*26abae3fSMichal Meloun goto out; 647*26abae3fSMichal Meloun 648*26abae3fSMichal Meloun rv = ofw_pci_init(dev); 649*26abae3fSMichal Meloun if (rv != 0) 650*26abae3fSMichal Meloun goto out; 651*26abae3fSMichal Meloun rv = pci_dw_decode_ranges(sc, sc->ofw_pci.sc_range, 652*26abae3fSMichal Meloun sc->ofw_pci.sc_nrange); 653*26abae3fSMichal Meloun if (rv != 0) 654*26abae3fSMichal Meloun goto out; 655*26abae3fSMichal Meloun 656*26abae3fSMichal Meloun rv = pci_dw_setup_hw(sc); 657*26abae3fSMichal Meloun if (rv != 0) 658*26abae3fSMichal Meloun goto out; 659*26abae3fSMichal Meloun 660*26abae3fSMichal Meloun device_add_child(dev, "pci", -1); 661*26abae3fSMichal Meloun 662*26abae3fSMichal Meloun return (bus_generic_attach(dev)); 663*26abae3fSMichal Meloun out: 664*26abae3fSMichal Meloun /* XXX Cleanup */ 665*26abae3fSMichal Meloun return (rv); 666*26abae3fSMichal Meloun } 667*26abae3fSMichal Meloun 668*26abae3fSMichal Meloun static device_method_t pci_dw_methods[] = { 669*26abae3fSMichal Meloun 670*26abae3fSMichal Meloun /* Bus interface */ 671*26abae3fSMichal Meloun DEVMETHOD(bus_get_dma_tag, pci_dw_get_dma_tag), 672*26abae3fSMichal Meloun 673*26abae3fSMichal Meloun /* pcib interface */ 674*26abae3fSMichal Meloun DEVMETHOD(pcib_read_config, pci_dw_read_config), 675*26abae3fSMichal Meloun DEVMETHOD(pcib_write_config, pci_dw_write_config), 676*26abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msi, pci_dw_alloc_msi), 677*26abae3fSMichal Meloun DEVMETHOD(pcib_release_msi, pci_dw_release_msi), 678*26abae3fSMichal Meloun DEVMETHOD(pcib_alloc_msix, pci_dw_alloc_msix), 679*26abae3fSMichal Meloun DEVMETHOD(pcib_release_msix, pci_dw_release_msix), 680*26abae3fSMichal Meloun DEVMETHOD(pcib_map_msi, pci_dw_map_msi), 681*26abae3fSMichal Meloun DEVMETHOD(pcib_get_id, pci_dw_get_id), 682*26abae3fSMichal Meloun 683*26abae3fSMichal Meloun /* OFW bus interface */ 684*26abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 685*26abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 686*26abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 687*26abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 688*26abae3fSMichal Meloun DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 689*26abae3fSMichal Meloun 690*26abae3fSMichal Meloun /* PCI DW interface */ 691*26abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_read, pci_dw_dbi_read), 692*26abae3fSMichal Meloun DEVMETHOD(pci_dw_dbi_write, pci_dw_dbi_write), 693*26abae3fSMichal Meloun DEVMETHOD_END 694*26abae3fSMichal Meloun }; 695*26abae3fSMichal Meloun 696*26abae3fSMichal Meloun DEFINE_CLASS_1(pcib, pci_dw_driver, pci_dw_methods, 697*26abae3fSMichal Meloun sizeof(struct pci_dw_softc), ofw_pci_driver); 698