16844eecfSMichal Meloun /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 36844eecfSMichal Meloun * 46844eecfSMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 56844eecfSMichal Meloun * 66844eecfSMichal Meloun * Redistribution and use in source and binary forms, with or without 76844eecfSMichal Meloun * modification, are permitted provided that the following conditions 86844eecfSMichal Meloun * are met: 96844eecfSMichal Meloun * 1. Redistributions of source code must retain the above copyright 106844eecfSMichal Meloun * notice, this list of conditions and the following disclaimer. 116844eecfSMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 126844eecfSMichal Meloun * notice, this list of conditions and the following disclaimer in the 136844eecfSMichal Meloun * documentation and/or other materials provided with the distribution. 146844eecfSMichal Meloun * 156844eecfSMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 166844eecfSMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 176844eecfSMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 186844eecfSMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 196844eecfSMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 206844eecfSMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 216844eecfSMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 226844eecfSMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 236844eecfSMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 246844eecfSMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 256844eecfSMichal Meloun * SUCH DAMAGE. 266844eecfSMichal Meloun * 276844eecfSMichal Meloun */ 286844eecfSMichal Meloun 296844eecfSMichal Meloun /* Layerscape DesignWare PCIe driver */ 306844eecfSMichal Meloun 316844eecfSMichal Meloun #include <sys/param.h> 326844eecfSMichal Meloun #include <sys/systm.h> 336844eecfSMichal Meloun #include <sys/bus.h> 346844eecfSMichal Meloun #include <sys/devmap.h> 356844eecfSMichal Meloun #include <sys/proc.h> 366844eecfSMichal Meloun #include <sys/kernel.h> 376844eecfSMichal Meloun #include <sys/malloc.h> 386844eecfSMichal Meloun #include <sys/module.h> 396844eecfSMichal Meloun #include <sys/mutex.h> 406844eecfSMichal Meloun #include <sys/rman.h> 416844eecfSMichal Meloun #include <sys/sysctl.h> 426844eecfSMichal Meloun 436844eecfSMichal Meloun #include <machine/bus.h> 446844eecfSMichal Meloun #include <machine/intr.h> 456844eecfSMichal Meloun #include <machine/resource.h> 466844eecfSMichal Meloun 476844eecfSMichal Meloun #include <dev/ofw/ofw_bus.h> 486844eecfSMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 496844eecfSMichal Meloun #include <dev/ofw/ofw_pci.h> 506844eecfSMichal Meloun #include <dev/ofw/ofwpci.h> 516844eecfSMichal Meloun #include <dev/pci/pcivar.h> 526844eecfSMichal Meloun #include <dev/pci/pcireg.h> 536844eecfSMichal Meloun #include <dev/pci/pcib_private.h> 546844eecfSMichal Meloun #include <dev/pci/pci_dw.h> 556844eecfSMichal Meloun 566844eecfSMichal Meloun #include "pcib_if.h" 576844eecfSMichal Meloun #include "pci_dw_if.h" 586844eecfSMichal Meloun 596844eecfSMichal Meloun #define PCIE_ABSERR 0x8D0 606844eecfSMichal Meloun 616844eecfSMichal Meloun struct qoriq_dw_pci_cfg { 626844eecfSMichal Meloun uint32_t pex_pf0_dgb; /* offset of PEX_PF0_DBG register */ 63*516e591dSGordon Bergling uint32_t ltssm_bit; /* LSB bit of LTSSM state field */ 646844eecfSMichal Meloun }; 656844eecfSMichal Meloun 666844eecfSMichal Meloun struct qorif_dw_pci_softc { 676844eecfSMichal Meloun struct pci_dw_softc dw_sc; 686844eecfSMichal Meloun device_t dev; 696844eecfSMichal Meloun phandle_t node; 706844eecfSMichal Meloun struct resource *irq_res; 716844eecfSMichal Meloun void *intr_cookie; 726844eecfSMichal Meloun struct qoriq_dw_pci_cfg *soc_cfg; 736844eecfSMichal Meloun 746844eecfSMichal Meloun }; 756844eecfSMichal Meloun 766844eecfSMichal Meloun static struct qoriq_dw_pci_cfg ls1043_cfg = { 776844eecfSMichal Meloun .pex_pf0_dgb = 0x10000 + 0x7FC, 786844eecfSMichal Meloun .ltssm_bit = 24, 796844eecfSMichal Meloun }; 806844eecfSMichal Meloun 816844eecfSMichal Meloun static struct qoriq_dw_pci_cfg ls1012_cfg = { 826844eecfSMichal Meloun .pex_pf0_dgb = 0x80000 + 0x407FC, 836844eecfSMichal Meloun .ltssm_bit = 24, 846844eecfSMichal Meloun }; 856844eecfSMichal Meloun 866844eecfSMichal Meloun static struct qoriq_dw_pci_cfg ls2080_cfg = { 876844eecfSMichal Meloun .pex_pf0_dgb = 0x80000 + 0x7FC, 886844eecfSMichal Meloun .ltssm_bit = 0, 896844eecfSMichal Meloun }; 906844eecfSMichal Meloun 916844eecfSMichal Meloun static struct qoriq_dw_pci_cfg ls2028_cfg = { 926844eecfSMichal Meloun .pex_pf0_dgb = 0x80000 + 0x407FC, 936844eecfSMichal Meloun .ltssm_bit = 0, 946844eecfSMichal Meloun }; 956844eecfSMichal Meloun 966844eecfSMichal Meloun 976844eecfSMichal Meloun /* Compatible devices. */ 986844eecfSMichal Meloun static struct ofw_compat_data compat_data[] = { 996844eecfSMichal Meloun {"fsl,ls1012a-pcie", (uintptr_t)&ls1012_cfg}, 1006844eecfSMichal Meloun {"fsl,ls1028a-pcie", (uintptr_t)&ls2028_cfg}, 1016844eecfSMichal Meloun {"fsl,ls1043a-pcie", (uintptr_t)&ls1043_cfg}, 1026844eecfSMichal Meloun {"fsl,ls1046a-pcie", (uintptr_t)&ls1012_cfg}, 1036844eecfSMichal Meloun {"fsl,ls2080a-pcie", (uintptr_t)&ls2080_cfg}, 1046844eecfSMichal Meloun {"fsl,ls2085a-pcie", (uintptr_t)&ls2080_cfg}, 1056844eecfSMichal Meloun {"fsl,ls2088a-pcie", (uintptr_t)&ls2028_cfg}, 1066844eecfSMichal Meloun {"fsl,ls1088a-pcie", (uintptr_t)&ls2028_cfg}, 1076844eecfSMichal Meloun {NULL, 0}, 1086844eecfSMichal Meloun }; 1096844eecfSMichal Meloun 1106844eecfSMichal Meloun static void 1116844eecfSMichal Meloun qorif_dw_pci_dbi_protect(struct qorif_dw_pci_softc *sc, bool protect) 1126844eecfSMichal Meloun { 1136844eecfSMichal Meloun uint32_t reg; 1146844eecfSMichal Meloun 1156844eecfSMichal Meloun reg = pci_dw_dbi_rd4(sc->dev, DW_MISC_CONTROL_1); 1166844eecfSMichal Meloun if (protect) 1176844eecfSMichal Meloun reg &= ~DBI_RO_WR_EN; 1186844eecfSMichal Meloun else 1196844eecfSMichal Meloun reg |= DBI_RO_WR_EN; 1206844eecfSMichal Meloun pci_dw_dbi_wr4(sc->dev, DW_MISC_CONTROL_1, reg); 1216844eecfSMichal Meloun } 1226844eecfSMichal Meloun 1236844eecfSMichal Meloun static int qorif_dw_pci_intr(void *arg) 1246844eecfSMichal Meloun { 1256844eecfSMichal Meloun #if 0 1266844eecfSMichal Meloun struct qorif_dw_pci_softc *sc = arg; 1276844eecfSMichal Meloun uint32_t cause1, cause2; 1286844eecfSMichal Meloun 1296844eecfSMichal Meloun /* Ack all interrups */ 1306844eecfSMichal Meloun cause1 = pci_dw_dbi_rd4(sc->dev, MV_INT_CAUSE1); 1316844eecfSMichal Meloun cause2 = pci_dw_dbi_rd4(sc->dev, MV_INT_CAUSE2); 1326844eecfSMichal Meloun 1336844eecfSMichal Meloun pci_dw_dbi_wr4(sc->dev, MV_INT_CAUSE1, cause1); 1346844eecfSMichal Meloun pci_dw_dbi_wr4(sc->dev, MV_INT_CAUSE2, cause2); 1356844eecfSMichal Meloun #endif 1366844eecfSMichal Meloun return (FILTER_HANDLED); 1376844eecfSMichal Meloun } 1386844eecfSMichal Meloun 1396844eecfSMichal Meloun static int 1406844eecfSMichal Meloun qorif_dw_pci_get_link(device_t dev, bool *status) 1416844eecfSMichal Meloun { 1426844eecfSMichal Meloun struct qorif_dw_pci_softc *sc; 1436844eecfSMichal Meloun uint32_t reg; 1446844eecfSMichal Meloun 1456844eecfSMichal Meloun sc = device_get_softc(dev); 1466844eecfSMichal Meloun reg = pci_dw_dbi_rd4(sc->dev, sc->soc_cfg->pex_pf0_dgb); 1476844eecfSMichal Meloun reg >>= sc->soc_cfg->ltssm_bit; 1486844eecfSMichal Meloun reg &= 0x3F; 149df9c0e88SBartlomiej Grzesik *status = (reg == 0x11) ? true : false; 1506844eecfSMichal Meloun return (0); 1516844eecfSMichal Meloun } 1526844eecfSMichal Meloun 1536844eecfSMichal Meloun static void 1546844eecfSMichal Meloun qorif_dw_pci_init(struct qorif_dw_pci_softc *sc) 1556844eecfSMichal Meloun { 1566844eecfSMichal Meloun 1576844eecfSMichal Meloun // ls_pcie_disable_outbound_atus(pcie); 1586844eecfSMichal Meloun 1596844eecfSMichal Meloun /* Forward error response */ 1606844eecfSMichal Meloun pci_dw_dbi_wr4(sc->dev, PCIE_ABSERR, 0x9401); 1616844eecfSMichal Meloun 1626844eecfSMichal Meloun qorif_dw_pci_dbi_protect(sc, true); 1636844eecfSMichal Meloun pci_dw_dbi_wr1(sc->dev, PCIR_HDRTYPE, 1); 1646844eecfSMichal Meloun qorif_dw_pci_dbi_protect(sc, false); 1656844eecfSMichal Meloun 1666844eecfSMichal Meloun // ls_pcie_drop_msg_tlp(pcie); 1676844eecfSMichal Meloun 1686844eecfSMichal Meloun } 1696844eecfSMichal Meloun 1706844eecfSMichal Meloun static int 1716844eecfSMichal Meloun qorif_dw_pci_probe(device_t dev) 1726844eecfSMichal Meloun { 1736844eecfSMichal Meloun 1746844eecfSMichal Meloun if (!ofw_bus_status_okay(dev)) 1756844eecfSMichal Meloun return (ENXIO); 1766844eecfSMichal Meloun 1776844eecfSMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 1786844eecfSMichal Meloun return (ENXIO); 1796844eecfSMichal Meloun 1806844eecfSMichal Meloun device_set_desc(dev, "NPX Layaerscape PCI-E Controller"); 1816844eecfSMichal Meloun return (BUS_PROBE_DEFAULT); 1826844eecfSMichal Meloun } 1836844eecfSMichal Meloun 1846844eecfSMichal Meloun static int 1856844eecfSMichal Meloun qorif_dw_pci_attach(device_t dev) 1866844eecfSMichal Meloun { 187cb894f74SAndrew Turner struct resource_map_request req; 188cb894f74SAndrew Turner struct resource_map map; 1896844eecfSMichal Meloun struct qorif_dw_pci_softc *sc; 1906844eecfSMichal Meloun phandle_t node; 1916844eecfSMichal Meloun int rv; 1926844eecfSMichal Meloun int rid; 1936844eecfSMichal Meloun 1946844eecfSMichal Meloun sc = device_get_softc(dev); 1956844eecfSMichal Meloun node = ofw_bus_get_node(dev); 1966844eecfSMichal Meloun sc->dev = dev; 1976844eecfSMichal Meloun sc->node = node; 1986844eecfSMichal Meloun sc->soc_cfg = (struct qoriq_dw_pci_cfg *) 1996844eecfSMichal Meloun ofw_bus_search_compatible(dev, compat_data)->ocd_data; 2006844eecfSMichal Meloun 2016844eecfSMichal Meloun rid = 0; 2026844eecfSMichal Meloun sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 203cb894f74SAndrew Turner RF_ACTIVE | RF_UNMAPPED); 2046844eecfSMichal Meloun if (sc->dw_sc.dbi_res == NULL) { 2056844eecfSMichal Meloun device_printf(dev, "Cannot allocate DBI memory\n"); 2066844eecfSMichal Meloun rv = ENXIO; 2076844eecfSMichal Meloun goto out; 2086844eecfSMichal Meloun } 2096844eecfSMichal Meloun 210cb894f74SAndrew Turner resource_init_map_request(&req); 211cb894f74SAndrew Turner req.memattr = VM_MEMATTR_DEVICE_NP; 212cb894f74SAndrew Turner rv = bus_map_resource(dev, SYS_RES_MEMORY, sc->dw_sc.dbi_res, &req, 213cb894f74SAndrew Turner &map); 214cb894f74SAndrew Turner if (rv != 0) { 215cb894f74SAndrew Turner device_printf(dev, "could not map memory.\n"); 216cb894f74SAndrew Turner return (rv); 217cb894f74SAndrew Turner } 218cb894f74SAndrew Turner rman_set_mapping(sc->dw_sc.dbi_res, &map); 219cb894f74SAndrew Turner 2206844eecfSMichal Meloun /* PCI interrupt */ 2216844eecfSMichal Meloun rid = 0; 2226844eecfSMichal Meloun sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2236844eecfSMichal Meloun RF_ACTIVE | RF_SHAREABLE); 2246844eecfSMichal Meloun if (sc->irq_res == NULL) { 2256844eecfSMichal Meloun device_printf(dev, "Cannot allocate IRQ resources\n"); 2266844eecfSMichal Meloun rv = ENXIO; 2276844eecfSMichal Meloun goto out; 2286844eecfSMichal Meloun } 2296844eecfSMichal Meloun 2306844eecfSMichal Meloun rv = pci_dw_init(dev); 2316844eecfSMichal Meloun if (rv != 0) 2326844eecfSMichal Meloun goto out; 2336844eecfSMichal Meloun 2346844eecfSMichal Meloun qorif_dw_pci_init(sc); 2356844eecfSMichal Meloun 2366844eecfSMichal Meloun /* Setup interrupt */ 2376844eecfSMichal Meloun if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 2386844eecfSMichal Meloun qorif_dw_pci_intr, NULL, sc, &sc->intr_cookie)) { 2396844eecfSMichal Meloun device_printf(dev, "cannot setup interrupt handler\n"); 2406844eecfSMichal Meloun rv = ENXIO; 2416844eecfSMichal Meloun goto out; 2426844eecfSMichal Meloun } 2436844eecfSMichal Meloun 2446844eecfSMichal Meloun return (bus_generic_attach(dev)); 2456844eecfSMichal Meloun out: 2466844eecfSMichal Meloun /* XXX Cleanup */ 2476844eecfSMichal Meloun return (rv); 2486844eecfSMichal Meloun } 2496844eecfSMichal Meloun 2506844eecfSMichal Meloun static device_method_t qorif_dw_pci_methods[] = { 2516844eecfSMichal Meloun /* Device interface */ 2526844eecfSMichal Meloun DEVMETHOD(device_probe, qorif_dw_pci_probe), 2536844eecfSMichal Meloun DEVMETHOD(device_attach, qorif_dw_pci_attach), 2546844eecfSMichal Meloun 2556844eecfSMichal Meloun DEVMETHOD(pci_dw_get_link, qorif_dw_pci_get_link), 2566844eecfSMichal Meloun 2576844eecfSMichal Meloun DEVMETHOD_END 2586844eecfSMichal Meloun }; 2596844eecfSMichal Meloun 2606844eecfSMichal Meloun DEFINE_CLASS_1(pcib, qorif_dw_pci_driver, qorif_dw_pci_methods, 2616844eecfSMichal Meloun sizeof(struct qorif_dw_pci_softc), pci_dw_driver); 262d7827042SJohn Baldwin DRIVER_MODULE( qorif_dw_pci, simplebus, qorif_dw_pci_driver, NULL, NULL); 263