1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 /* Layerscape DesignWare PCIe driver */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 #include <sys/devmap.h> 35 #include <sys/proc.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/rman.h> 41 #include <sys/sysctl.h> 42 43 #include <machine/bus.h> 44 #include <machine/intr.h> 45 #include <machine/resource.h> 46 47 #include <dev/ofw/ofw_bus.h> 48 #include <dev/ofw/ofw_bus_subr.h> 49 #include <dev/ofw/ofw_pci.h> 50 #include <dev/ofw/ofwpci.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pcireg.h> 53 #include <dev/pci/pcib_private.h> 54 #include <dev/pci/pci_dw.h> 55 56 #include "pcib_if.h" 57 #include "pci_dw_if.h" 58 59 #define PCIE_ABSERR 0x8D0 60 61 struct qoriq_dw_pci_cfg { 62 uint32_t pex_pf0_dgb; /* offset of PEX_PF0_DBG register */ 63 uint32_t ltssm_bit; /* LSB bit of of LTSSM state field */ 64 }; 65 66 struct qorif_dw_pci_softc { 67 struct pci_dw_softc dw_sc; 68 device_t dev; 69 phandle_t node; 70 struct resource *irq_res; 71 void *intr_cookie; 72 struct qoriq_dw_pci_cfg *soc_cfg; 73 74 }; 75 76 static struct qoriq_dw_pci_cfg ls1043_cfg = { 77 .pex_pf0_dgb = 0x10000 + 0x7FC, 78 .ltssm_bit = 24, 79 }; 80 81 static struct qoriq_dw_pci_cfg ls1012_cfg = { 82 .pex_pf0_dgb = 0x80000 + 0x407FC, 83 .ltssm_bit = 24, 84 }; 85 86 static struct qoriq_dw_pci_cfg ls2080_cfg = { 87 .pex_pf0_dgb = 0x80000 + 0x7FC, 88 .ltssm_bit = 0, 89 }; 90 91 static struct qoriq_dw_pci_cfg ls2028_cfg = { 92 .pex_pf0_dgb = 0x80000 + 0x407FC, 93 .ltssm_bit = 0, 94 }; 95 96 97 /* Compatible devices. */ 98 static struct ofw_compat_data compat_data[] = { 99 {"fsl,ls1012a-pcie", (uintptr_t)&ls1012_cfg}, 100 {"fsl,ls1028a-pcie", (uintptr_t)&ls2028_cfg}, 101 {"fsl,ls1043a-pcie", (uintptr_t)&ls1043_cfg}, 102 {"fsl,ls1046a-pcie", (uintptr_t)&ls1012_cfg}, 103 {"fsl,ls2080a-pcie", (uintptr_t)&ls2080_cfg}, 104 {"fsl,ls2085a-pcie", (uintptr_t)&ls2080_cfg}, 105 {"fsl,ls2088a-pcie", (uintptr_t)&ls2028_cfg}, 106 {"fsl,ls1088a-pcie", (uintptr_t)&ls2028_cfg}, 107 {NULL, 0}, 108 }; 109 110 static void 111 qorif_dw_pci_dbi_protect(struct qorif_dw_pci_softc *sc, bool protect) 112 { 113 uint32_t reg; 114 115 reg = pci_dw_dbi_rd4(sc->dev, DW_MISC_CONTROL_1); 116 if (protect) 117 reg &= ~DBI_RO_WR_EN; 118 else 119 reg |= DBI_RO_WR_EN; 120 pci_dw_dbi_wr4(sc->dev, DW_MISC_CONTROL_1, reg); 121 } 122 123 static int qorif_dw_pci_intr(void *arg) 124 { 125 #if 0 126 struct qorif_dw_pci_softc *sc = arg; 127 uint32_t cause1, cause2; 128 129 /* Ack all interrups */ 130 cause1 = pci_dw_dbi_rd4(sc->dev, MV_INT_CAUSE1); 131 cause2 = pci_dw_dbi_rd4(sc->dev, MV_INT_CAUSE2); 132 133 pci_dw_dbi_wr4(sc->dev, MV_INT_CAUSE1, cause1); 134 pci_dw_dbi_wr4(sc->dev, MV_INT_CAUSE2, cause2); 135 #endif 136 return (FILTER_HANDLED); 137 } 138 139 static int 140 qorif_dw_pci_get_link(device_t dev, bool *status) 141 { 142 struct qorif_dw_pci_softc *sc; 143 uint32_t reg; 144 145 sc = device_get_softc(dev); 146 reg = pci_dw_dbi_rd4(sc->dev, sc->soc_cfg->pex_pf0_dgb); 147 reg >>= sc->soc_cfg->ltssm_bit; 148 reg &= 0x3F; 149 *status = (reg == 0x11) ? true : false; 150 return (0); 151 } 152 153 static void 154 qorif_dw_pci_init(struct qorif_dw_pci_softc *sc) 155 { 156 157 // ls_pcie_disable_outbound_atus(pcie); 158 159 /* Forward error response */ 160 pci_dw_dbi_wr4(sc->dev, PCIE_ABSERR, 0x9401); 161 162 qorif_dw_pci_dbi_protect(sc, true); 163 pci_dw_dbi_wr1(sc->dev, PCIR_HDRTYPE, 1); 164 qorif_dw_pci_dbi_protect(sc, false); 165 166 // ls_pcie_drop_msg_tlp(pcie); 167 168 } 169 170 static int 171 qorif_dw_pci_probe(device_t dev) 172 { 173 174 if (!ofw_bus_status_okay(dev)) 175 return (ENXIO); 176 177 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 178 return (ENXIO); 179 180 device_set_desc(dev, "NPX Layaerscape PCI-E Controller"); 181 return (BUS_PROBE_DEFAULT); 182 } 183 184 static int 185 qorif_dw_pci_attach(device_t dev) 186 { 187 struct resource_map_request req; 188 struct resource_map map; 189 struct qorif_dw_pci_softc *sc; 190 phandle_t node; 191 int rv; 192 int rid; 193 194 sc = device_get_softc(dev); 195 node = ofw_bus_get_node(dev); 196 sc->dev = dev; 197 sc->node = node; 198 sc->soc_cfg = (struct qoriq_dw_pci_cfg *) 199 ofw_bus_search_compatible(dev, compat_data)->ocd_data; 200 201 rid = 0; 202 sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 203 RF_ACTIVE | RF_UNMAPPED); 204 if (sc->dw_sc.dbi_res == NULL) { 205 device_printf(dev, "Cannot allocate DBI memory\n"); 206 rv = ENXIO; 207 goto out; 208 } 209 210 resource_init_map_request(&req); 211 req.memattr = VM_MEMATTR_DEVICE_NP; 212 rv = bus_map_resource(dev, SYS_RES_MEMORY, sc->dw_sc.dbi_res, &req, 213 &map); 214 if (rv != 0) { 215 device_printf(dev, "could not map memory.\n"); 216 return (rv); 217 } 218 rman_set_mapping(sc->dw_sc.dbi_res, &map); 219 220 /* PCI interrupt */ 221 rid = 0; 222 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 223 RF_ACTIVE | RF_SHAREABLE); 224 if (sc->irq_res == NULL) { 225 device_printf(dev, "Cannot allocate IRQ resources\n"); 226 rv = ENXIO; 227 goto out; 228 } 229 230 rv = pci_dw_init(dev); 231 if (rv != 0) 232 goto out; 233 234 qorif_dw_pci_init(sc); 235 236 /* Setup interrupt */ 237 if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 238 qorif_dw_pci_intr, NULL, sc, &sc->intr_cookie)) { 239 device_printf(dev, "cannot setup interrupt handler\n"); 240 rv = ENXIO; 241 goto out; 242 } 243 244 return (bus_generic_attach(dev)); 245 out: 246 /* XXX Cleanup */ 247 return (rv); 248 } 249 250 static device_method_t qorif_dw_pci_methods[] = { 251 /* Device interface */ 252 DEVMETHOD(device_probe, qorif_dw_pci_probe), 253 DEVMETHOD(device_attach, qorif_dw_pci_attach), 254 255 DEVMETHOD(pci_dw_get_link, qorif_dw_pci_get_link), 256 257 DEVMETHOD_END 258 }; 259 260 DEFINE_CLASS_1(pcib, qorif_dw_pci_driver, qorif_dw_pci_methods, 261 sizeof(struct qorif_dw_pci_softc), pci_dw_driver); 262 DRIVER_MODULE( qorif_dw_pci, simplebus, qorif_dw_pci_driver, NULL, NULL); 263