xref: /netbsd-src/sys/arch/arm/nxp/imxpcie.c (revision cecde1b5250be188abd1ea1de5507e00d7ddefbe)
1*cecde1b5Sandvar /*	$NetBSD: imxpcie.c,v 1.5 2024/06/02 13:28:45 andvar Exp $	*/
28644267aSskrll 
38644267aSskrll /*
48644267aSskrll  * Copyright (c) 2019  Genetec Corporation.  All rights reserved.
58644267aSskrll  * Written by Hashimoto Kenichi for Genetec Corporation.
68644267aSskrll  *
78644267aSskrll  * Redistribution and use in source and binary forms, with or without
88644267aSskrll  * modification, are permitted provided that the following conditions
98644267aSskrll  * are met:
108644267aSskrll  * 1. Redistributions of source code must retain the above copyright
118644267aSskrll  *    notice, this list of conditions and the following disclaimer.
128644267aSskrll  * 2. Redistributions in binary form must reproduce the above copyright
138644267aSskrll  *    notice, this list of conditions and the following disclaimer in the
148644267aSskrll  *    documentation and/or other materials provided with the distribution.
158644267aSskrll  *
168644267aSskrll  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
178644267aSskrll  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
188644267aSskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
198644267aSskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
208644267aSskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
218644267aSskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
228644267aSskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
238644267aSskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
248644267aSskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
258644267aSskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
268644267aSskrll  * POSSIBILITY OF SUCH DAMAGE.
278644267aSskrll  */
288644267aSskrll 
298644267aSskrll /*
308644267aSskrll  * i.MX6 On-Chip PCI Express Controller
318644267aSskrll  */
328644267aSskrll 
338644267aSskrll #include <sys/cdefs.h>
34*cecde1b5Sandvar __KERNEL_RCSID(0, "$NetBSD: imxpcie.c,v 1.5 2024/06/02 13:28:45 andvar Exp $");
358644267aSskrll 
368644267aSskrll #include "opt_pci.h"
378644267aSskrll #include "opt_fdt.h"
388644267aSskrll 
398644267aSskrll #include "pci.h"
408644267aSskrll #include "locators.h"
418644267aSskrll 
428644267aSskrll #define	_INTR_PRIVATE
438644267aSskrll 
448644267aSskrll #include <sys/bus.h>
458644267aSskrll #include <sys/device.h>
468644267aSskrll #include <sys/intr.h>
478644267aSskrll #include <sys/systm.h>
488644267aSskrll #include <sys/param.h>
498644267aSskrll #include <sys/kernel.h>
508644267aSskrll #include <sys/extent.h>
518644267aSskrll #include <sys/queue.h>
528644267aSskrll #include <sys/mutex.h>
538644267aSskrll #include <sys/kmem.h>
548644267aSskrll 
558644267aSskrll #include <machine/frame.h>
568644267aSskrll #include <arm/cpufunc.h>
578644267aSskrll 
588644267aSskrll #include <dev/pci/pcireg.h>
598644267aSskrll #include <dev/pci/pcivar.h>
608644267aSskrll #include <dev/pci/pciconf.h>
618644267aSskrll #include <dev/clk/clk_backend.h>
628644267aSskrll 
638644267aSskrll #include <arm/imx/imxpciereg.h>
648644267aSskrll #include <arm/imx/imxpcievar.h>
658644267aSskrll #include <arm/nxp/imx6_iomuxreg.h>
668644267aSskrll 
678644267aSskrll #define PCIE_CONF_LOCK(s)	(s) = disable_interrupts(I32_bit)
688644267aSskrll #define PCIE_CONF_UNLOCK(s)	restore_interrupts((s))
698644267aSskrll 
708644267aSskrll #define PCIE_READ(sc, reg)					\
718644267aSskrll 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, reg)
728644267aSskrll #define PCIE_WRITE(sc, reg, val)				\
738644267aSskrll 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, reg, val)
748644267aSskrll 
758644267aSskrll static void imxpcie_init(pci_chipset_tag_t, void *);
768644267aSskrll static void imxpcie_setup(struct imxpcie_softc * const);
778644267aSskrll 
788644267aSskrll static void imxpcie_attach_hook(device_t, device_t, struct pcibus_attach_args *);
798644267aSskrll static int imxpcie_bus_maxdevs(void *, int);
808644267aSskrll static pcitag_t imxpcie_make_tag(void *, int, int, int);
818644267aSskrll static void imxpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
828644267aSskrll static pcireg_t imxpcie_conf_read(void *, pcitag_t, int);
838644267aSskrll static void imxpcie_conf_write(void *, pcitag_t, int, pcireg_t);
848644267aSskrll #ifdef __HAVE_PCI_CONF_HOOK
858644267aSskrll static int imxpcie_conf_hook(void *, int, int, int, pcireg_t);
868644267aSskrll #endif
878644267aSskrll static void imxpcie_conf_interrupt(void *, int, int, int, int, int *);
888644267aSskrll 
898644267aSskrll static int imxpcie_intr_map(const struct pci_attach_args *, pci_intr_handle_t *);
908644267aSskrll static const char *imxpcie_intr_string(void *, pci_intr_handle_t, char *, size_t);
918644267aSskrll const struct evcnt *imxpcie_intr_evcnt(void *, pci_intr_handle_t);
928644267aSskrll static void * imxpcie_intr_establish(void *, pci_intr_handle_t, int,
938644267aSskrll     int (*)(void *), void *, const char *);
948644267aSskrll static void imxpcie_intr_disestablish(void *, void *);
958644267aSskrll 
968644267aSskrll static int
imxpcie_linkup_status(struct imxpcie_softc * sc)978644267aSskrll imxpcie_linkup_status(struct imxpcie_softc *sc)
988644267aSskrll {
998644267aSskrll 	return PCIE_READ(sc, PCIE_PL_DEBUG1) & PCIE_PL_DEBUG1_XMLH_LINK_UP;
1008644267aSskrll }
1018644267aSskrll 
1028644267aSskrll static int
imxpcie_valid_device(struct imxpcie_softc * sc,int bus,int dev)1038644267aSskrll imxpcie_valid_device(struct imxpcie_softc *sc, int bus, int dev)
1048644267aSskrll {
1058644267aSskrll 	if (bus != 0 && !imxpcie_linkup_status(sc))
1068644267aSskrll 		return 0;
1078644267aSskrll 	if (bus <= 1 && dev > 0)
1088644267aSskrll 		return 0;
1098644267aSskrll 
1108644267aSskrll 	return 1;
1118644267aSskrll }
1128644267aSskrll 
1138644267aSskrll static int
imxpcie_init_phy(struct imxpcie_softc * sc)1148644267aSskrll imxpcie_init_phy(struct imxpcie_softc *sc)
1158644267aSskrll {
1168644267aSskrll 	uint32_t v;
1178644267aSskrll 
1188644267aSskrll 	/* initialize IOMUX */
1198644267aSskrll 	v = sc->sc_gpr_read(sc, IOMUX_GPR12);
1208644267aSskrll 	v &= ~IOMUX_GPR12_APP_LTSSM_ENABLE;
1218644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR12, v);
1228644267aSskrll 
1238644267aSskrll 	v &= ~IOMUX_GPR12_LOS_LEVEL;
1248644267aSskrll 	v |= __SHIFTIN(9, IOMUX_GPR12_LOS_LEVEL);
1258644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR12, v);
1268644267aSskrll 
1278644267aSskrll 	v = 0;
1288644267aSskrll 	v |= __SHIFTIN(0x7f, IOMUX_GPR8_PCS_TX_SWING_LOW);
1298644267aSskrll 	v |= __SHIFTIN(0x7f, IOMUX_GPR8_PCS_TX_SWING_FULL);
1308644267aSskrll 	v |= __SHIFTIN(20, IOMUX_GPR8_PCS_TX_DEEMPH_GEN2_6DB);
1318644267aSskrll 	v |= __SHIFTIN(20, IOMUX_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB);
1328644267aSskrll 	v |= __SHIFTIN(20, IOMUX_GPR8_PCS_TX_DEEMPH_GEN1);
1338644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR8, v);
1348644267aSskrll 
1358644267aSskrll 	v = sc->sc_gpr_read(sc, IOMUX_GPR12);
1368644267aSskrll 	v &= ~IOMUX_GPR12_DEVICE_TYPE;
1378644267aSskrll 	v |= IOMUX_GPR12_DEVICE_TYPE_PCIE_RC;
1388644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR12, v);
1398644267aSskrll 
1408644267aSskrll 	return 0;
1418644267aSskrll }
1428644267aSskrll 
1438644267aSskrll static int
imxpcie_phy_wait_ack(struct imxpcie_softc * sc,int ack)1448644267aSskrll imxpcie_phy_wait_ack(struct imxpcie_softc *sc, int ack)
1458644267aSskrll {
1468644267aSskrll 	uint32_t v;
1478644267aSskrll 	int timeout;
1488644267aSskrll 
1498644267aSskrll 	for (timeout = 10; timeout > 0; --timeout) {
1508644267aSskrll 		v = PCIE_READ(sc, PCIE_PL_PHY_STATUS);
1518644267aSskrll 		if (!!(v & PCIE_PL_PHY_STATUS_ACK) == !!ack)
1528644267aSskrll 			return 0;
1538644267aSskrll 		delay(1);
1548644267aSskrll 	}
1558644267aSskrll 
1568644267aSskrll 	return -1;
1578644267aSskrll }
1588644267aSskrll 
1598644267aSskrll static int
imxpcie_phy_addr(struct imxpcie_softc * sc,uint32_t addr)1608644267aSskrll imxpcie_phy_addr(struct imxpcie_softc *sc, uint32_t addr)
1618644267aSskrll {
1628644267aSskrll 	uint32_t v;
1638644267aSskrll 
1648644267aSskrll 	v = __SHIFTIN(addr, PCIE_PL_PHY_CTRL_DATA);
1658644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
1668644267aSskrll 
1678644267aSskrll 	v |= PCIE_PL_PHY_CTRL_CAP_ADR;
1688644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
1698644267aSskrll 
1708644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 1))
1718644267aSskrll 		return -1;
1728644267aSskrll 
1738644267aSskrll 	v = __SHIFTIN(addr, PCIE_PL_PHY_CTRL_DATA);
1748644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
1758644267aSskrll 
1768644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 0))
1778644267aSskrll 		return -1;
1788644267aSskrll 
1798644267aSskrll 	return 0;
1808644267aSskrll }
1818644267aSskrll 
1828644267aSskrll static int
imxpcie_phy_write(struct imxpcie_softc * sc,uint32_t addr,uint16_t data)1838644267aSskrll imxpcie_phy_write(struct imxpcie_softc *sc, uint32_t addr, uint16_t data)
1848644267aSskrll {
1858644267aSskrll 	/* write address */
1868644267aSskrll 	if (imxpcie_phy_addr(sc, addr) != 0)
1878644267aSskrll 		return -1;
1888644267aSskrll 
1898644267aSskrll 	/* store data */
1908644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
1918644267aSskrll 
1928644267aSskrll 	/* assert CAP_DAT and wait ack */
1938644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA) | PCIE_PL_PHY_CTRL_CAP_DAT);
1948644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 1))
1958644267aSskrll 		return -1;
1968644267aSskrll 
1978644267aSskrll 	/* deassert CAP_DAT and wait ack */
1988644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
1998644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 0))
2008644267aSskrll 		return -1;
2018644267aSskrll 
2028644267aSskrll 	/* assert WR and wait ack */
2038644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, PCIE_PL_PHY_CTRL_WR);
2048644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 1))
2058644267aSskrll 		return -1;
2068644267aSskrll 
2078644267aSskrll 	/* deassert WR and wait ack */
2088644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
2098644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 0))
2108644267aSskrll 		return -1;
2118644267aSskrll 
2128644267aSskrll 	/* done */
2138644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, 0);
2148644267aSskrll 
2158644267aSskrll 	return 0;
2168644267aSskrll }
2178644267aSskrll 
2188644267aSskrll static int
imxpcie_phy_read(struct imxpcie_softc * sc,uint32_t addr)2198644267aSskrll imxpcie_phy_read(struct imxpcie_softc *sc, uint32_t addr)
2208644267aSskrll {
2218644267aSskrll 	uint32_t v;
2228644267aSskrll 
2238644267aSskrll 	/* write address */
2248644267aSskrll 	if (imxpcie_phy_addr(sc, addr) != 0)
2258644267aSskrll 		return -1;
2268644267aSskrll 
2278644267aSskrll 	/* assert RD */
2288644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, PCIE_PL_PHY_CTRL_RD);
2298644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 1))
2308644267aSskrll 		return -1;
2318644267aSskrll 
2328644267aSskrll 	/* read data */
2338644267aSskrll 	v = __SHIFTOUT(PCIE_READ(sc, PCIE_PL_PHY_STATUS),
2348644267aSskrll 	    PCIE_PL_PHY_STATUS_DATA);
2358644267aSskrll 
2368644267aSskrll 	/* deassert RD */
2378644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, 0);
2388644267aSskrll 	if (imxpcie_phy_wait_ack(sc, 0))
2398644267aSskrll 		return -1;
2408644267aSskrll 
2418644267aSskrll 	return v;
2428644267aSskrll }
2438644267aSskrll 
2448644267aSskrll static int
imxpcie_assert_core_reset(struct imxpcie_softc * sc)2458644267aSskrll imxpcie_assert_core_reset(struct imxpcie_softc *sc)
2468644267aSskrll {
2478644267aSskrll 	uint32_t gpr1 = sc->sc_gpr_read(sc, IOMUX_GPR1);
2488644267aSskrll 
2498644267aSskrll 	if (sc->sc_have_sw_reset) {
2508644267aSskrll 		gpr1 |= IOMUX_GPR1_PCIE_SW_RST;
2518644267aSskrll 		sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
2528644267aSskrll 	} else {
2538644267aSskrll 		uint32_t gpr12 = sc->sc_gpr_read(sc, IOMUX_GPR12);
2548644267aSskrll 
2558644267aSskrll 		/* already enabled by bootloader */
2568644267aSskrll 		if ((gpr1 & IOMUX_GPR1_REF_SSP_EN) &&
2578644267aSskrll 		    (gpr12 & IOMUX_GPR12_APP_LTSSM_ENABLE)) {
2588644267aSskrll 			uint32_t v = PCIE_READ(sc, PCIE_PL_PFLR);
2598644267aSskrll 			v &= ~PCIE_PL_PFLR_LINK_STATE;
2608644267aSskrll 			v |= PCIE_PL_PFLR_FORCE_LINK;
2618644267aSskrll 			PCIE_WRITE(sc, PCIE_PL_PFLR, v);
2628644267aSskrll 
2638644267aSskrll 			gpr12 &= ~IOMUX_GPR12_APP_LTSSM_ENABLE;
2648644267aSskrll 			sc->sc_gpr_write(sc, IOMUX_GPR12, gpr12);
2658644267aSskrll 		}
2668644267aSskrll 	}
2678644267aSskrll 
2688644267aSskrll 	gpr1 |= IOMUX_GPR1_TEST_POWERDOWN;
2698644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
2708644267aSskrll 	gpr1 &= ~IOMUX_GPR1_REF_SSP_EN;
2718644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
2728644267aSskrll 
2738644267aSskrll 	return 0;
2748644267aSskrll }
2758644267aSskrll 
2768644267aSskrll static int
imxpcie_deassert_core_reset(struct imxpcie_softc * sc)2778644267aSskrll imxpcie_deassert_core_reset(struct imxpcie_softc *sc)
2788644267aSskrll {
2798644267aSskrll 	int error;
2808644267aSskrll 
2818644267aSskrll 	error = clk_enable(sc->sc_clk_pcie);
2828644267aSskrll 	if (error) {
2838644267aSskrll 		aprint_error_dev(sc->sc_dev, "couldn't enable pcie: %d\n", error);
2848644267aSskrll 		return error;
2858644267aSskrll 	}
2868644267aSskrll 
2878644267aSskrll 	if (sc->sc_ext_osc) {
2888644267aSskrll 		error = clk_enable(sc->sc_clk_pcie_ext);
2898644267aSskrll 		if (error) {
2908644267aSskrll 			aprint_error_dev(sc->sc_dev, "couldn't enable ext: %d\n", error);
2918644267aSskrll 			return error;
2928644267aSskrll 		}
2938644267aSskrll 	} else {
2948644267aSskrll 		error = clk_enable(sc->sc_clk_pcie_bus);
2958644267aSskrll 		if (error) {
2968644267aSskrll 			aprint_error_dev(sc->sc_dev, "couldn't enable pcie_bus: %d\n",
2978644267aSskrll 			    error);
2988644267aSskrll 			return error;
2998644267aSskrll 		}
3008644267aSskrll 	}
3018644267aSskrll 
3028644267aSskrll 	error = clk_enable(sc->sc_clk_pcie_phy);
3038644267aSskrll 	if (error) {
3048644267aSskrll 		aprint_error_dev(sc->sc_dev, "couldn't enable pcie_ref: %d\n", error);
3058644267aSskrll 		return error;
3068644267aSskrll 	}
3078644267aSskrll 
3088644267aSskrll 	uint32_t gpr1 = sc->sc_gpr_read(sc, IOMUX_GPR1);
3098644267aSskrll 
3108644267aSskrll 	delay(50 * 1000);
3118644267aSskrll 
3128644267aSskrll 	gpr1 &= ~IOMUX_GPR1_TEST_POWERDOWN;
3138644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
3148644267aSskrll 	delay(10);
3158644267aSskrll 	gpr1 |= IOMUX_GPR1_REF_SSP_EN;
3168644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
3178644267aSskrll 
3188644267aSskrll 	delay(50 * 1000);
3198644267aSskrll 
3208644267aSskrll 	/* Reset */
3218644267aSskrll 	if (sc->sc_reset != NULL)
3228644267aSskrll 		sc->sc_reset(sc);
3238644267aSskrll 
3248644267aSskrll 	if (sc->sc_have_sw_reset) {
3258644267aSskrll 		gpr1 &= ~IOMUX_GPR1_PCIE_SW_RST;
3268644267aSskrll 		sc->sc_gpr_write(sc, IOMUX_GPR1, gpr1);
3278644267aSskrll 		delay(200);
3288644267aSskrll 	}
3298644267aSskrll 
3308644267aSskrll 	uint64_t rate;
3318644267aSskrll 	if (sc->sc_ext_osc)
3328644267aSskrll 		rate = clk_get_rate(sc->sc_clk_pcie_ext);
3338644267aSskrll 	else
3348644267aSskrll 		rate = clk_get_rate(sc->sc_clk_pcie_phy);
3358644267aSskrll 	aprint_normal_dev(sc->sc_dev, "PCIe ref clk %d MHz\n", (int)(rate / 1000 / 1000));
3368644267aSskrll 
3378644267aSskrll 	int mult;
3388644267aSskrll 	int div;
3398644267aSskrll 	if (rate == 100000000) {
3408644267aSskrll 		mult = 25;
3418644267aSskrll 		div = 0;
3428644267aSskrll 	} else if (rate == 125000000) {
3438644267aSskrll 		mult = 40;
3448644267aSskrll 		div = 1;
3458644267aSskrll 	} else if (rate == 200000000) {
3468644267aSskrll 		mult = 25;
3478644267aSskrll 		div = 1;
3488644267aSskrll 	} else {
3498644267aSskrll 		return -1;
3508644267aSskrll 	}
3518644267aSskrll 
3528644267aSskrll 	uint32_t val;
3538644267aSskrll 	val = imxpcie_phy_read(sc, PCIE_PHY_MPLL_OVRD_IN_LO);
3548644267aSskrll 	val &= ~MPLL_MULTIPLIER;
3558644267aSskrll 	val |= __SHIFTIN(mult, MPLL_MULTIPLIER);
3568644267aSskrll 	val |= MPLL_MULTIPLIER_OVRD;
3578644267aSskrll 	imxpcie_phy_write(sc, PCIE_PHY_MPLL_OVRD_IN_LO, val);
3588644267aSskrll 
3598644267aSskrll 	val = imxpcie_phy_read(sc, PCIE_PHY_ATEOVRD);
3608644267aSskrll 	val &= ~REF_CLKDIV2;
3618644267aSskrll 	val |= __SHIFTIN(div, REF_CLKDIV2);
3628644267aSskrll 	val |= ATEOVRD_EN;
3638644267aSskrll 	imxpcie_phy_write(sc, PCIE_PHY_ATEOVRD, val);
3648644267aSskrll 
3658644267aSskrll 	return 0;
3668644267aSskrll }
3678644267aSskrll 
3688644267aSskrll static int
imxpcie_wait_for_link(struct imxpcie_softc * sc)3698644267aSskrll imxpcie_wait_for_link(struct imxpcie_softc *sc)
3708644267aSskrll {
3718644267aSskrll #define LINKUP_RETRY	20000
3728644267aSskrll 	for (int retry = LINKUP_RETRY; retry > 0; --retry) {
3738644267aSskrll 		if (!imxpcie_linkup_status(sc)) {
3748644267aSskrll 			delay(10);
3758644267aSskrll 			continue;
3768644267aSskrll 		}
3778644267aSskrll 
3788644267aSskrll 		uint32_t valid = imxpcie_phy_read(sc, PCIE_PHY_RX_ASIC_OUT) &
3798644267aSskrll 		    PCIE_PHY_RX_ASIC_OUT_VALID;
3808644267aSskrll 		uint32_t ltssm = __SHIFTOUT(PCIE_READ(sc, PCIE_PL_DEBUG0),
3818644267aSskrll 		    PCIE_PL_DEBUG0_XMLH_LTSSM_STATE);
3828644267aSskrll 
3838644267aSskrll 		if ((ltssm == 0x0d) && !valid) {
3848644267aSskrll 			aprint_normal_dev(sc->sc_dev, "resetting PCIe phy\n");
3858644267aSskrll 
3868644267aSskrll 			uint32_t v = imxpcie_phy_read(sc, PCIE_PHY_RX_OVRD_IN_LO);
3878644267aSskrll 			v |= PCIE_PHY_RX_OVRD_IN_LO_RX_PLL_EN_OVRD;
3888644267aSskrll 			v |= PCIE_PHY_RX_OVRD_IN_LO_RX_DATA_EN_OVRD;
3898644267aSskrll 			imxpcie_phy_write(sc, PCIE_PHY_RX_OVRD_IN_LO, v);
3908644267aSskrll 
3918644267aSskrll 			delay(3000);
3928644267aSskrll 
3938644267aSskrll 			v = imxpcie_phy_read(sc, PCIE_PHY_RX_OVRD_IN_LO);
3948644267aSskrll 			v &= ~PCIE_PHY_RX_OVRD_IN_LO_RX_PLL_EN_OVRD;
3958644267aSskrll 			v &= ~PCIE_PHY_RX_OVRD_IN_LO_RX_DATA_EN_OVRD;
3968644267aSskrll 			imxpcie_phy_write(sc, PCIE_PHY_RX_OVRD_IN_LO, v);
3978644267aSskrll 		}
3988644267aSskrll 
3998644267aSskrll 		return 0;
4008644267aSskrll 	}
4018644267aSskrll 
4028644267aSskrll 	aprint_error_dev(sc->sc_dev, "Link Up failed.\n");
4038644267aSskrll 
4048644267aSskrll 	return -1;
4058644267aSskrll }
4068644267aSskrll 
4078644267aSskrll static int
imxpcie_wait_for_changespeed(struct imxpcie_softc * sc)4088644267aSskrll imxpcie_wait_for_changespeed(struct imxpcie_softc *sc)
4098644267aSskrll {
4108644267aSskrll #define CHANGESPEED_RETRY	200
4118644267aSskrll 	for (int retry = CHANGESPEED_RETRY; retry > 0; --retry) {
4128644267aSskrll 		uint32_t v = PCIE_READ(sc, PCIE_PL_G2CR);
4138644267aSskrll 		if (!(v & PCIE_PL_G2CR_DIRECTED_SPEED_CHANGE))
4148644267aSskrll 			return 0;
4158644267aSskrll 		delay(100);
4168644267aSskrll 	}
4178644267aSskrll 
4188644267aSskrll 	aprint_error_dev(sc->sc_dev, "Speed change timeout.\n");
4198644267aSskrll 
4208644267aSskrll 	return -1;
4218644267aSskrll }
4228644267aSskrll 
4238644267aSskrll static void
imxpcie_linkup(struct imxpcie_softc * sc)4248644267aSskrll imxpcie_linkup(struct imxpcie_softc *sc)
4258644267aSskrll {
4268644267aSskrll 	uint32_t v;
4278644267aSskrll 	int ret;
4288644267aSskrll 
4298644267aSskrll 	imxpcie_assert_core_reset(sc);
4308644267aSskrll 	imxpcie_init_phy(sc);
4318644267aSskrll 	imxpcie_deassert_core_reset(sc);
4328644267aSskrll 
4338644267aSskrll 	imxpcie_setup(sc);
4348644267aSskrll 
4358644267aSskrll 	/* GEN1 Operation */
4368644267aSskrll 	v = PCIE_READ(sc, PCIE_RC_LCR);
4378644267aSskrll 	v &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS;
4388644267aSskrll 	v |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
4398644267aSskrll 	PCIE_WRITE(sc, PCIE_RC_LCR, v);
4408644267aSskrll 
4418644267aSskrll 	/* Link Up */
4428644267aSskrll 	v = sc->sc_gpr_read(sc, IOMUX_GPR12);
4438644267aSskrll 	v |= IOMUX_GPR12_APP_LTSSM_ENABLE;
4448644267aSskrll 	sc->sc_gpr_write(sc, IOMUX_GPR12, v);
4458644267aSskrll 
4468644267aSskrll 	ret = imxpcie_wait_for_link(sc);
4478644267aSskrll 	if (ret)
4488644267aSskrll 		goto error;
4498644267aSskrll 
4508644267aSskrll 	/* Allow Gen2 mode */
4518644267aSskrll 	v = PCIE_READ(sc, PCIE_RC_LCR);
4528644267aSskrll 	v &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS;
4538644267aSskrll 	v |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
4548644267aSskrll 	PCIE_WRITE(sc, PCIE_RC_LCR, v);
4558644267aSskrll 
4568644267aSskrll 	/* Change speed */
4578644267aSskrll 	v = PCIE_READ(sc, PCIE_PL_G2CR);
4588644267aSskrll 	v |= PCIE_PL_G2CR_DIRECTED_SPEED_CHANGE;
4598644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_G2CR, v);
4608644267aSskrll 
4618644267aSskrll 	ret = imxpcie_wait_for_changespeed(sc);
4628644267aSskrll 	if (ret)
4638644267aSskrll 		goto error;
4648644267aSskrll 
4658644267aSskrll 	ret = imxpcie_wait_for_link(sc);
4668644267aSskrll 	if (ret)
4678644267aSskrll 		goto error;
4688644267aSskrll 
4698644267aSskrll 	v = PCIE_READ(sc, PCIE_RC_LCSR);
4708644267aSskrll 	aprint_normal_dev(sc->sc_dev, "LinkUp, Gen %d\n",
4718644267aSskrll 	    (int)__SHIFTOUT(v, PCIE_RC_LCSR_LINK_SPEED));
4728644267aSskrll 
4738644267aSskrll 	return;
4748644267aSskrll 
4758644267aSskrll error:
4768644267aSskrll 	aprint_error_dev(sc->sc_dev, "PCIE_PL_DEBUG0,1 = %08x, %08x\n",
4778644267aSskrll 	    PCIE_READ(sc, PCIE_PL_DEBUG0), PCIE_READ(sc, PCIE_PL_DEBUG1));
4788644267aSskrll 
4798644267aSskrll 	return;
4808644267aSskrll }
4818644267aSskrll 
4828644267aSskrll void
imxpcie_attach_common(struct imxpcie_softc * const sc)4838644267aSskrll imxpcie_attach_common(struct imxpcie_softc * const sc)
4848644267aSskrll {
4858644267aSskrll 	struct pcibus_attach_args pba;
4868644267aSskrll 
4878644267aSskrll 	if (bus_space_map(sc->sc_iot, sc->sc_root_addr, sc->sc_root_size, 0,
4888644267aSskrll 		&sc->sc_root_ioh)) {
4898644267aSskrll 		aprint_error_dev(sc->sc_dev, "Cannot map root config\n");
4908644267aSskrll 		return;
4918644267aSskrll 	}
4928644267aSskrll 
4938644267aSskrll 	imxpcie_linkup(sc);
4948644267aSskrll 
4958644267aSskrll 	TAILQ_INIT(&sc->sc_intrs);
4968644267aSskrll 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
4978644267aSskrll 
4988644267aSskrll 	imxpcie_init(&sc->sc_pc, sc);
4998644267aSskrll 
5008644267aSskrll 	if (sc->sc_pci_netbsd_configure != NULL)
5018644267aSskrll 		sc->sc_pci_netbsd_configure(sc);
5028644267aSskrll 
5038644267aSskrll 	memset(&pba, 0, sizeof(pba));
5048644267aSskrll 	pba.pba_flags = PCI_FLAGS_MEM_OKAY |
5058644267aSskrll 	    PCI_FLAGS_IO_OKAY;
5068644267aSskrll 	pba.pba_iot = sc->sc_iot;
5078644267aSskrll 	pba.pba_memt = sc->sc_iot;
5088644267aSskrll 	pba.pba_dmat = sc->sc_dmat;
5098644267aSskrll 	pba.pba_pc = &sc->sc_pc;
5108644267aSskrll 	pba.pba_bus = 0;
5118644267aSskrll 
512d1083ec1Sthorpej 	config_found(sc->sc_dev, &pba, pcibusprint,
513c7fb772bSthorpej 	    CFARGS(.devhandle = device_handle(sc->sc_dev)));
5148644267aSskrll }
5158644267aSskrll 
5168644267aSskrll int
imxpcie_intr(void * priv)5178644267aSskrll imxpcie_intr(void *priv)
5188644267aSskrll {
5198644267aSskrll 	struct imxpcie_softc *sc = priv;
5208644267aSskrll 	struct imxpcie_ih *pcie_ih;
5218644267aSskrll 
5228644267aSskrll 	for (int i = 0; i < 8; i++) {
5238644267aSskrll 		uint32_t v = PCIE_READ(sc, PCIE_PL_MSICIN_STATUS + i * 0xC);
5248644267aSskrll 		int bit;
5258644267aSskrll 		while ((bit = ffs(v) - 1) >= 0) {
5268644267aSskrll 			PCIE_WRITE(sc, PCIE_PL_MSICIN_STATUS + i * 0xC,
5278644267aSskrll 			    __BIT(bit));
5288644267aSskrll 			v &= ~__BIT(bit);
5298644267aSskrll 		}
5308644267aSskrll 	}
5318644267aSskrll 
5328644267aSskrll 	mutex_enter(&sc->sc_lock);
5338644267aSskrll 	int rv = 0;
5348644267aSskrll 	const u_int lastgen = sc->sc_intrgen;
5358644267aSskrll 	TAILQ_FOREACH(pcie_ih, &sc->sc_intrs, ih_entry) {
5368644267aSskrll 		int (*callback)(void *) = pcie_ih->ih_handler;
5378644267aSskrll 		void *arg = pcie_ih->ih_arg;
5388644267aSskrll 		mutex_exit(&sc->sc_lock);
5398644267aSskrll 		rv += callback(arg);
5408644267aSskrll 		mutex_enter(&sc->sc_lock);
5418644267aSskrll 		if (lastgen != sc->sc_intrgen)
5428644267aSskrll 			break;
5438644267aSskrll 	}
5448644267aSskrll 	mutex_exit(&sc->sc_lock);
5458644267aSskrll 
5468644267aSskrll 	return rv;
5478644267aSskrll }
5488644267aSskrll 
5498644267aSskrll static void
imxpcie_setup(struct imxpcie_softc * const sc)5508644267aSskrll imxpcie_setup(struct imxpcie_softc * const sc)
5518644267aSskrll {
5528644267aSskrll 	uint32_t v;
5538644267aSskrll 
5548644267aSskrll 	/* Setup RC */
5558644267aSskrll 	v = PCIE_READ(sc, PCIE_PL_PLCR);
5568644267aSskrll 	v &= ~PCIE_PL_PLCR_LINK_MODE_ENABLE;
5578644267aSskrll 	v |= __SHIFTIN(1, PCIE_PL_PLCR_LINK_MODE_ENABLE);
5588644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_PLCR, v);
5598644267aSskrll 
5608644267aSskrll 	v = PCIE_READ(sc, PCIE_PL_G2CR);
5618644267aSskrll 	v &= ~PCIE_PL_G2CR_PREDETERMINED_NUMBER_OF_LANES;
5628644267aSskrll 	v |= __SHIFTIN(1, PCIE_PL_G2CR_PREDETERMINED_NUMBER_OF_LANES);
5638644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_G2CR, v);
5648644267aSskrll 
5658644267aSskrll 	/* BARs */
5668644267aSskrll 	PCIE_WRITE(sc, PCI_BAR0, 0x00000004);
5678644267aSskrll 	PCIE_WRITE(sc, PCI_BAR1, 0x00000000);
5688644267aSskrll 
569*cecde1b5Sandvar 	/* Interrupt pins */
5708644267aSskrll 	v = PCIE_READ(sc, PCI_INTERRUPT_REG);
5718644267aSskrll 	v &= ~(PCI_INTERRUPT_PIN_MASK << PCI_INTERRUPT_PIN_SHIFT);
5728644267aSskrll 	v |= PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT;
5738644267aSskrll 	PCIE_WRITE(sc, PCI_INTERRUPT_REG, v);
5748644267aSskrll 
5758644267aSskrll 	/* Bus number */
5768644267aSskrll 	v = PCIE_READ(sc, PCI_BRIDGE_BUS_REG);
5778644267aSskrll 	v &= ~(PCI_BRIDGE_BUS_SUBORDINATE | PCI_BRIDGE_BUS_SECONDARY |
5788644267aSskrll 	    PCI_BRIDGE_BUS_PRIMARY);
5798644267aSskrll 	v |= PCI_BRIDGE_BUS_NUM_SUBORDINATE(1);
5808644267aSskrll 	v |= PCI_BRIDGE_BUS_NUM_SECONDARY(1);
5818644267aSskrll 	v |= PCI_BRIDGE_BUS_NUM_PRIMARY(0);
5828644267aSskrll 	PCIE_WRITE(sc, PCI_BRIDGE_BUS_REG, v);
5838644267aSskrll 
5848644267aSskrll 	/* Command register */
5858644267aSskrll 	v = PCIE_READ(sc, PCI_COMMAND_STATUS_REG);
5868644267aSskrll 	v |= PCI_COMMAND_IO_ENABLE |
5878644267aSskrll 	    PCI_COMMAND_MEM_ENABLE |
5888644267aSskrll 	    PCI_COMMAND_MASTER_ENABLE |
5898644267aSskrll 	    PCI_COMMAND_SERR_ENABLE;
5908644267aSskrll 	PCIE_WRITE(sc, PCI_COMMAND_STATUS_REG, v);
5918644267aSskrll 
5928644267aSskrll 	PCIE_WRITE(sc, PCI_CLASS_REG,
5938644267aSskrll 	    PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
5948644267aSskrll 		PCI_SUBCLASS_BRIDGE_PCI,
5958644267aSskrll 		PCI_INTERFACE_BRIDGE_PCI_PCI));
5968644267aSskrll 
5978644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
5988644267aSskrll 
5998644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURLBA, sc->sc_root_addr);
6008644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURUBA, 0);
6018644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURLA, sc->sc_root_addr + sc->sc_root_size);
6028644267aSskrll 
6038644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURLTA, 0);
6048644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURUTA, 0);
6058644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
6068644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATURC2, PCIE_PL_IATURC2_REGION_ENABLE);
6078644267aSskrll }
6088644267aSskrll 
6098644267aSskrll void
imxpcie_init(pci_chipset_tag_t pc,void * priv)6108644267aSskrll imxpcie_init(pci_chipset_tag_t pc, void *priv)
6118644267aSskrll {
6128644267aSskrll 	pc->pc_conf_v = priv;
6138644267aSskrll 	pc->pc_attach_hook = imxpcie_attach_hook;
6148644267aSskrll 	pc->pc_bus_maxdevs = imxpcie_bus_maxdevs;
6158644267aSskrll 	pc->pc_make_tag = imxpcie_make_tag;
6168644267aSskrll 	pc->pc_decompose_tag = imxpcie_decompose_tag;
6178644267aSskrll 	pc->pc_conf_read = imxpcie_conf_read;
6188644267aSskrll 	pc->pc_conf_write = imxpcie_conf_write;
6198644267aSskrll #ifdef __HAVE_PCI_CONF_HOOK
6208644267aSskrll 	pc->pc_conf_hook = imxpcie_conf_hook;
6218644267aSskrll #endif
6228644267aSskrll 	pc->pc_conf_interrupt = imxpcie_conf_interrupt;
6238644267aSskrll 
6248644267aSskrll 	pc->pc_intr_v = priv;
6258644267aSskrll 	pc->pc_intr_map = imxpcie_intr_map;
6268644267aSskrll 	pc->pc_intr_string = imxpcie_intr_string;
6278644267aSskrll 	pc->pc_intr_evcnt = imxpcie_intr_evcnt;
6288644267aSskrll 	pc->pc_intr_establish = imxpcie_intr_establish;
6298644267aSskrll 	pc->pc_intr_disestablish = imxpcie_intr_disestablish;
6308644267aSskrll }
6318644267aSskrll 
6328644267aSskrll static void
imxpcie_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)6338644267aSskrll imxpcie_attach_hook(device_t parent, device_t self,
6348644267aSskrll     struct pcibus_attach_args *pba)
6358644267aSskrll {
6368644267aSskrll 	/* nothing to do */
6378644267aSskrll }
6388644267aSskrll 
6398644267aSskrll static int
imxpcie_bus_maxdevs(void * v,int busno)6408644267aSskrll imxpcie_bus_maxdevs(void *v, int busno)
6418644267aSskrll {
6428644267aSskrll 	return 32;
6438644267aSskrll }
6448644267aSskrll 
6458644267aSskrll static pcitag_t
imxpcie_make_tag(void * v,int b,int d,int f)6468644267aSskrll imxpcie_make_tag(void *v, int b, int d, int f)
6478644267aSskrll {
6488644267aSskrll 	return (b << 16) | (d << 11) | (f << 8);
6498644267aSskrll }
6508644267aSskrll 
6518644267aSskrll static void
imxpcie_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)6528644267aSskrll imxpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
6538644267aSskrll {
6548644267aSskrll 	if (bp)
6558644267aSskrll 		*bp = (tag >> 16) & 0xff;
6568644267aSskrll 	if (dp)
6578644267aSskrll 		*dp = (tag >> 11) & 0x1f;
6588644267aSskrll 	if (fp)
6598644267aSskrll 		*fp = (tag >> 8) & 0x7;
6608644267aSskrll }
6618644267aSskrll 
6628644267aSskrll /*
6638644267aSskrll  * work around.
6648644267aSskrll  * If there is no PCIe devices, DABT will be generated by read/write access to
6658644267aSskrll  * config area, so replace original DABT handler with simple jump-back one.
6668644267aSskrll  */
6678644267aSskrll extern u_int data_abort_handler_address;
6688644267aSskrll static bool data_abort_flag;
6698644267aSskrll static void
imxpcie_data_abort_handler(trapframe_t * tf)6708644267aSskrll imxpcie_data_abort_handler(trapframe_t *tf)
6718644267aSskrll {
6728644267aSskrll 	data_abort_flag = true;
6738644267aSskrll 	tf->tf_pc += 0x4;
6748644267aSskrll 	return;
6758644267aSskrll }
6768644267aSskrll 
6778644267aSskrll static pcireg_t
imxpcie_conf_read(void * v,pcitag_t tag,int offset)6788644267aSskrll imxpcie_conf_read(void *v, pcitag_t tag, int offset)
6798644267aSskrll {
6808644267aSskrll 	struct imxpcie_softc *sc = v;
6818644267aSskrll 	bus_space_handle_t bsh;
6828644267aSskrll 	int b, d, f;
6838644267aSskrll 	pcireg_t ret = -1;
6848644267aSskrll 	int s;
6858644267aSskrll 
6868644267aSskrll 	imxpcie_decompose_tag(v, tag, &b, &d, &f);
6878644267aSskrll 
6888644267aSskrll 	if ((unsigned int)offset >= PCI_EXTCONF_SIZE)
6898644267aSskrll 		return ret;
6908644267aSskrll 	if (!imxpcie_valid_device(sc, b, d))
6918644267aSskrll 		return ret;
6928644267aSskrll 
6938644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
6948644267aSskrll 	if (b < 2)
6958644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
6968644267aSskrll 	else
6978644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG1);
6988644267aSskrll 
6998644267aSskrll 	if (b == 0) {
7008644267aSskrll 		bsh = sc->sc_ioh;
7018644267aSskrll 	} else {
7028644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURLTA, tag << 8);
7038644267aSskrll 		bsh = sc->sc_root_ioh;
7048644267aSskrll 	}
7058644267aSskrll 	PCIE_READ(sc, PCIE_PL_IATURC2);
7068644267aSskrll 
7078644267aSskrll 	PCIE_CONF_LOCK(s);
7088644267aSskrll 
7098644267aSskrll 	u_int saved = data_abort_handler_address;
7108644267aSskrll 	data_abort_handler_address = (u_int)imxpcie_data_abort_handler;
7118644267aSskrll 	data_abort_flag = false;
7128644267aSskrll 
7138644267aSskrll 	ret = bus_space_read_4(sc->sc_iot, bsh, offset & ~0x3);
7148644267aSskrll 
7158644267aSskrll 	data_abort_handler_address = saved;
7168644267aSskrll 
7178644267aSskrll 	PCIE_CONF_UNLOCK(s);
7188644267aSskrll 
7198644267aSskrll 	if (data_abort_flag)
7208644267aSskrll 		ret = -1;
7218644267aSskrll 
7228644267aSskrll 	return ret;
7238644267aSskrll }
7248644267aSskrll 
7258644267aSskrll static void
imxpcie_conf_write(void * v,pcitag_t tag,int offset,pcireg_t val)7268644267aSskrll imxpcie_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
7278644267aSskrll {
7288644267aSskrll 	struct imxpcie_softc *sc = v;
7298644267aSskrll 	bus_space_handle_t bsh;
7308644267aSskrll 	int b, d, f;
7318644267aSskrll 	int s;
7328644267aSskrll 
7338644267aSskrll 	imxpcie_decompose_tag(v, tag, &b, &d, &f);
7348644267aSskrll 
7358644267aSskrll 	if ((unsigned int)offset >= PCI_EXTCONF_SIZE)
7368644267aSskrll 		return;
7378644267aSskrll 	if (!imxpcie_valid_device(sc, b, d))
7388644267aSskrll 		return;
7398644267aSskrll 
7408644267aSskrll 	PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
7418644267aSskrll 	if (b < 2)
7428644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
7438644267aSskrll 	else
7448644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG1);
7458644267aSskrll 
7468644267aSskrll 	if (b == 0) {
7478644267aSskrll 		bsh = sc->sc_ioh;
7488644267aSskrll 	} else {
7498644267aSskrll 		PCIE_WRITE(sc, PCIE_PL_IATURLTA, tag << 8);
7508644267aSskrll 		bsh = sc->sc_root_ioh;
7518644267aSskrll 	}
7528644267aSskrll 	PCIE_READ(sc, PCIE_PL_IATURC2);
7538644267aSskrll 
7548644267aSskrll 	PCIE_CONF_LOCK(s);
7558644267aSskrll 
7568644267aSskrll 	u_int saved = data_abort_handler_address;
7578644267aSskrll 	data_abort_handler_address = (u_int)imxpcie_data_abort_handler;
7588644267aSskrll 
7598644267aSskrll 	bus_space_write_4(sc->sc_iot, bsh, offset & ~0x3, val);
7608644267aSskrll 
7618644267aSskrll 	data_abort_handler_address = saved;
7628644267aSskrll 
7638644267aSskrll 	PCIE_CONF_UNLOCK(s);
7648644267aSskrll 
7658644267aSskrll 	return;
7668644267aSskrll }
7678644267aSskrll 
7688644267aSskrll #ifdef __HAVE_PCI_CONF_HOOK
7698644267aSskrll static int
imxpcie_conf_hook(void * v,int b,int d,int f,pcireg_t id)7708644267aSskrll imxpcie_conf_hook(void *v, int b, int d, int f, pcireg_t id)
7718644267aSskrll {
7728644267aSskrll 	return PCI_CONF_DEFAULT;
7738644267aSskrll }
7748644267aSskrll #endif
7758644267aSskrll 
7768644267aSskrll static void
imxpcie_conf_interrupt(void * v,int bus,int dev,int ipin,int swiz,int * ilinep)7778644267aSskrll imxpcie_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz,
7788644267aSskrll     int *ilinep)
7798644267aSskrll {
7808644267aSskrll 	/* nothing to do */
7818644267aSskrll }
7828644267aSskrll 
7838644267aSskrll static int
imxpcie_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ih)7848644267aSskrll imxpcie_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih)
7858644267aSskrll {
7868644267aSskrll 	if (pa->pa_intrpin == 0)
7878644267aSskrll 		return EINVAL;
7888644267aSskrll 	*ih = pa->pa_intrpin;
7898644267aSskrll 	return 0;
7908644267aSskrll }
7918644267aSskrll 
7928644267aSskrll static const char *
imxpcie_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)7938644267aSskrll imxpcie_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
7948644267aSskrll {
7958644267aSskrll 	if (ih == PCI_INTERRUPT_PIN_NONE)
7968644267aSskrll 		return NULL;
7978644267aSskrll 
7988644267aSskrll 	snprintf(buf, len, "pci");
7998644267aSskrll 
8008644267aSskrll 	return buf;
8018644267aSskrll }
8028644267aSskrll 
8038644267aSskrll const struct evcnt *
imxpcie_intr_evcnt(void * v,pci_intr_handle_t ih)8048644267aSskrll imxpcie_intr_evcnt(void *v, pci_intr_handle_t ih)
8058644267aSskrll {
8068644267aSskrll 	return NULL;
8078644267aSskrll }
8088644267aSskrll 
8098644267aSskrll static void *
imxpcie_intr_establish(void * v,pci_intr_handle_t ih,int ipl,int (* callback)(void *),void * arg,const char * xname)8108644267aSskrll imxpcie_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
8118644267aSskrll     int (*callback)(void *), void *arg, const char *xname)
8128644267aSskrll {
8138644267aSskrll 	struct imxpcie_softc *sc = v;
8148644267aSskrll 	struct imxpcie_ih *pcie_ih;
8158644267aSskrll 
8168644267aSskrll 	if (ih == 0)
8178644267aSskrll 		return NULL;
8188644267aSskrll 
8198644267aSskrll 	pcie_ih = kmem_alloc(sizeof(*pcie_ih), KM_SLEEP);
8208644267aSskrll 	pcie_ih->ih_handler = callback;
8218644267aSskrll 	pcie_ih->ih_arg = arg;
8228644267aSskrll 	pcie_ih->ih_ipl = ipl;
8238644267aSskrll 
8248644267aSskrll 	mutex_enter(&sc->sc_lock);
8258644267aSskrll 	TAILQ_INSERT_TAIL(&sc->sc_intrs, pcie_ih, ih_entry);
8268644267aSskrll 	sc->sc_intrgen++;
8278644267aSskrll 	mutex_exit(&sc->sc_lock);
8288644267aSskrll 
8298644267aSskrll 	return pcie_ih;
8308644267aSskrll }
8318644267aSskrll 
8328644267aSskrll static void
imxpcie_intr_disestablish(void * v,void * vih)8338644267aSskrll imxpcie_intr_disestablish(void *v, void *vih)
8348644267aSskrll {
8358644267aSskrll 	struct imxpcie_softc *sc = v;
8368644267aSskrll 	struct imxpcie_ih *pcie_ih = vih;
8378644267aSskrll 
8388644267aSskrll 	mutex_enter(&sc->sc_lock);
8398644267aSskrll 	TAILQ_REMOVE(&sc->sc_intrs, pcie_ih, ih_entry);
8408644267aSskrll 	sc->sc_intrgen++;
8418644267aSskrll 	mutex_exit(&sc->sc_lock);
8428644267aSskrll 
8438644267aSskrll 	kmem_free(pcie_ih, sizeof(*pcie_ih));
8448644267aSskrll }
845