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