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 */
63516e591dSGordon 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
qorif_dw_pci_dbi_protect(struct qorif_dw_pci_softc * sc,bool protect)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
qorif_dw_pci_intr(void * arg)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
qorif_dw_pci_get_link(device_t dev,bool * status)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
qorif_dw_pci_init(struct qorif_dw_pci_softc * sc)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
qorif_dw_pci_probe(device_t dev)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
qorif_dw_pci_attach(device_t dev)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