xref: /freebsd/sys/arm64/qoriq/qoriq_dw_pci.c (revision 516e591d)
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