1*54fbbda3Sjsg /* $OpenBSD: dwpcie.c,v 1.57 2024/09/01 03:08:56 jsg Exp $ */ 27659d2d7Skettenis /* 37659d2d7Skettenis * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 47659d2d7Skettenis * 57659d2d7Skettenis * Permission to use, copy, modify, and distribute this software for any 67659d2d7Skettenis * purpose with or without fee is hereby granted, provided that the above 77659d2d7Skettenis * copyright notice and this permission notice appear in all copies. 87659d2d7Skettenis * 97659d2d7Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 107659d2d7Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 117659d2d7Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 127659d2d7Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 137659d2d7Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 147659d2d7Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 157659d2d7Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 167659d2d7Skettenis */ 177659d2d7Skettenis 187659d2d7Skettenis #include <sys/param.h> 197659d2d7Skettenis #include <sys/systm.h> 207659d2d7Skettenis #include <sys/device.h> 21d5dfbc11Skettenis #include <sys/evcount.h> 227659d2d7Skettenis #include <sys/extent.h> 237659d2d7Skettenis #include <sys/malloc.h> 247659d2d7Skettenis 257659d2d7Skettenis #include <machine/intr.h> 267659d2d7Skettenis #include <machine/bus.h> 277659d2d7Skettenis #include <machine/fdt.h> 287659d2d7Skettenis 297659d2d7Skettenis #include <dev/pci/pcidevs.h> 307659d2d7Skettenis #include <dev/pci/pcireg.h> 317659d2d7Skettenis #include <dev/pci/pcivar.h> 32d43be508Skettenis #include <dev/pci/ppbreg.h> 337659d2d7Skettenis 347659d2d7Skettenis #include <dev/ofw/openfirm.h> 357659d2d7Skettenis #include <dev/ofw/ofw_clock.h> 366a2b914cSpatrick #include <dev/ofw/ofw_gpio.h> 376a2b914cSpatrick #include <dev/ofw/ofw_misc.h> 384605d28eSkettenis #include <dev/ofw/ofw_pinctrl.h> 396a2b914cSpatrick #include <dev/ofw/ofw_power.h> 401140f82aSkettenis #include <dev/ofw/ofw_regulator.h> 417659d2d7Skettenis #include <dev/ofw/fdt.h> 427659d2d7Skettenis 434605d28eSkettenis /* Registers */ 446a2b914cSpatrick #define PCIE_PORT_LINK_CTRL 0x710 456a2b914cSpatrick #define PCIE_PORT_LINK_CTRL_LANES_MASK (0x3f << 16) 466a2b914cSpatrick #define PCIE_PORT_LINK_CTRL_LANES_1 (0x1 << 16) 476a2b914cSpatrick #define PCIE_PORT_LINK_CTRL_LANES_2 (0x3 << 16) 486a2b914cSpatrick #define PCIE_PORT_LINK_CTRL_LANES_4 (0x7 << 16) 496a2b914cSpatrick #define PCIE_PORT_LINK_CTRL_LANES_8 (0xf << 16) 506a2b914cSpatrick #define PCIE_PHY_DEBUG_R1 0x72c 516a2b914cSpatrick #define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29) 526a2b914cSpatrick #define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4) 536a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL 0x80c 546a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK (0x1f << 8) 556a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1 (0x1 << 8) 566a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2 (0x2 << 8) 576a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4 (0x4 << 8) 586a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8 (0x8 << 8) 596a2b914cSpatrick #define PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE (1 << 17) 606a2b914cSpatrick 61d5dfbc11Skettenis #define PCIE_MSI_ADDR_LO 0x820 62d5dfbc11Skettenis #define PCIE_MSI_ADDR_HI 0x824 639a76443bSkettenis #define PCIE_MSI_INTR_ENABLE(x) (0x828 + (x) * 12) 649a76443bSkettenis #define PCIE_MSI_INTR_MASK(x) (0x82c + (x) * 12) 659a76443bSkettenis #define PCIE_MSI_INTR_STATUS(x) (0x830 + (x) * 12) 66d5dfbc11Skettenis 674605d28eSkettenis #define MISC_CONTROL_1 0x8bc 684605d28eSkettenis #define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0) 694605d28eSkettenis #define IATU_VIEWPORT 0x900 706a2b914cSpatrick #define IATU_VIEWPORT_INDEX0 0 716a2b914cSpatrick #define IATU_VIEWPORT_INDEX1 1 726a2b914cSpatrick #define IATU_VIEWPORT_INDEX2 2 73d2397242Skettenis #define IATU_VIEWPORT_INDEX3 3 746a2b914cSpatrick #define IATU_OFFSET_VIEWPORT 0x904 756a2b914cSpatrick #define IATU_OFFSET_UNROLL(x) (0x200 * (x)) 766a2b914cSpatrick #define IATU_REGION_CTRL_1 0x000 776a2b914cSpatrick #define IATU_REGION_CTRL_1_TYPE_MEM 0 7871fe361bSkettenis #define IATU_REGION_CTRL_1_TYPE_IO 2 794605d28eSkettenis #define IATU_REGION_CTRL_1_TYPE_CFG0 4 804605d28eSkettenis #define IATU_REGION_CTRL_1_TYPE_CFG1 5 816a2b914cSpatrick #define IATU_REGION_CTRL_2 0x004 824605d28eSkettenis #define IATU_REGION_CTRL_2_REGION_EN (1U << 31) 836a2b914cSpatrick #define IATU_LWR_BASE_ADDR 0x08 846a2b914cSpatrick #define IATU_UPPER_BASE_ADDR 0x0c 856a2b914cSpatrick #define IATU_LIMIT_ADDR 0x10 866a2b914cSpatrick #define IATU_LWR_TARGET_ADDR 0x14 876a2b914cSpatrick #define IATU_UPPER_TARGET_ADDR 0x18 884605d28eSkettenis 895f800b9bSkettenis /* Marvell ARMADA 8k registers */ 904605d28eSkettenis #define PCIE_GLOBAL_CTRL 0x8000 914605d28eSkettenis #define PCIE_GLOBAL_CTRL_APP_LTSSM_EN (1 << 2) 924605d28eSkettenis #define PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK (0xf << 4) 934605d28eSkettenis #define PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC (0x4 << 4) 944605d28eSkettenis #define PCIE_GLOBAL_STATUS 0x8008 954605d28eSkettenis #define PCIE_GLOBAL_STATUS_RDLH_LINK_UP (1 << 1) 964605d28eSkettenis #define PCIE_GLOBAL_STATUS_PHY_LINK_UP (1 << 9) 974605d28eSkettenis #define PCIE_PM_STATUS 0x8014 98f2c2f061Skettenis #define PCIE_GLOBAL_INT_CAUSE 0x801c 99f2c2f061Skettenis #define PCIE_GLOBAL_INT_MASK 0x8020 100f2c2f061Skettenis #define PCIE_GLOBAL_INT_MASK_INT_A (1 << 9) 101f2c2f061Skettenis #define PCIE_GLOBAL_INT_MASK_INT_B (1 << 10) 102f2c2f061Skettenis #define PCIE_GLOBAL_INT_MASK_INT_C (1 << 11) 103f2c2f061Skettenis #define PCIE_GLOBAL_INT_MASK_INT_D (1 << 12) 1044605d28eSkettenis #define PCIE_ARCACHE_TRC 0x8050 1054605d28eSkettenis #define PCIE_ARCACHE_TRC_DEFAULT 0x3511 1064605d28eSkettenis #define PCIE_AWCACHE_TRC 0x8054 1074605d28eSkettenis #define PCIE_AWCACHE_TRC_DEFAULT 0x5311 1084605d28eSkettenis #define PCIE_ARUSER 0x805c 1094605d28eSkettenis #define PCIE_AWUSER 0x8060 1104605d28eSkettenis #define PCIE_AXUSER_DOMAIN_MASK (0x3 << 4) 1114605d28eSkettenis #define PCIE_AXUSER_DOMAIN_INNER_SHARABLE (0x1 << 4) 1124605d28eSkettenis #define PCIE_AXUSER_DOMAIN_OUTER_SHARABLE (0x2 << 4) 113eae9bc5eSpatrick #define PCIE_STREAMID 0x8064 114eae9bc5eSpatrick #define PCIE_STREAMID_FUNC_BITS(x) ((x) << 0) 115eae9bc5eSpatrick #define PCIE_STREAMID_DEV_BITS(x) ((x) << 4) 116eae9bc5eSpatrick #define PCIE_STREAMID_BUS_BITS(x) ((x) << 8) 117eae9bc5eSpatrick #define PCIE_STREAMID_ROOTPORT(x) ((x) << 12) 118eae9bc5eSpatrick #define PCIE_STREAMID_8040 \ 119eae9bc5eSpatrick (PCIE_STREAMID_ROOTPORT(0x80) | PCIE_STREAMID_BUS_BITS(2) | \ 120eae9bc5eSpatrick PCIE_STREAMID_DEV_BITS(2) | PCIE_STREAMID_FUNC_BITS(3)) 1217659d2d7Skettenis 122c244e331Skettenis /* Amlogic G12A registers */ 123c244e331Skettenis #define PCIE_CFG0 0x0000 124c244e331Skettenis #define PCIE_CFG0_APP_LTSSM_EN (1 << 7) 125c244e331Skettenis #define PCIE_STATUS12 0x0030 126c244e331Skettenis #define PCIE_STATUS12_RDLH_LINK_UP (1 << 16) 127c244e331Skettenis #define PCIE_STATUS12_LTSSM_MASK (0x1f << 10) 128c244e331Skettenis #define PCIE_STATUS12_LTSSM_UP (0x11 << 10) 129c244e331Skettenis #define PCIE_STATUS12_SMLH_LINK_UP (1 << 6) 130c244e331Skettenis 131c244e331Skettenis /* NXP i.MX8MQ registers */ 1326a2b914cSpatrick #define PCIE_RC_LCR 0x7c 1336a2b914cSpatrick #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 1346a2b914cSpatrick #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 1356a2b914cSpatrick #define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf 1366a2b914cSpatrick #define PCIE_RC_LCR_L1EL_MASK (0x7 << 15) 1376a2b914cSpatrick #define PCIE_RC_LCR_L1EL_64US (0x6 << 15) 1386a2b914cSpatrick 1396a2b914cSpatrick #define IOMUXC_GPR12 0x30 1406a2b914cSpatrick #define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK (0xf << 8) 1416a2b914cSpatrick #define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC (0x4 << 8) 1426a2b914cSpatrick #define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK (0xf << 12) 1436a2b914cSpatrick #define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC (0x4 << 12) 1446a2b914cSpatrick #define IOMUXC_GPR14 0x38 1456a2b914cSpatrick #define IOMUXC_GPR16 0x40 1466a2b914cSpatrick #define IMX8MQ_GPR_PCIE_REF_USE_PAD (1 << 9) 1476a2b914cSpatrick #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN (1 << 10) 1486a2b914cSpatrick #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE (1 << 11) 1491ad6abbaSpatrick #define IMX8MM_GPR_PCIE_SSC_EN (1 << 16) 1501ad6abbaSpatrick #define IMX8MM_GPR_PCIE_POWER_OFF (1 << 17) 1511ad6abbaSpatrick #define IMX8MM_GPR_PCIE_CMN_RST (1 << 18) 1521ad6abbaSpatrick #define IMX8MM_GPR_PCIE_AUX_EN (1 << 19) 1531ad6abbaSpatrick #define IMX8MM_GPR_PCIE_REF_CLK_MASK (0x3 << 24) 1541ad6abbaSpatrick #define IMX8MM_GPR_PCIE_REF_CLK_PLL (0x3 << 24) 1551ad6abbaSpatrick #define IMX8MM_GPR_PCIE_REF_CLK_EXT (0x2 << 24) 1561ad6abbaSpatrick 1571ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG62 0x188 1581ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG62_PLL_CLK_OUT 0x08 1591ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG64 0x190 1601ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM 0x8c 1611ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG75 0x1d4 1621ad6abbaSpatrick #define IMX8MM_PCIE_PHY_CMN_REG75_PLL_DONE 0x3 1631ad6abbaSpatrick #define IMX8MM_PCIE_PHY_TRSV_REG5 0x414 1641ad6abbaSpatrick #define IMX8MM_PCIE_PHY_TRSV_REG5_GEN1_DEEMP 0x2d 1651ad6abbaSpatrick #define IMX8MM_PCIE_PHY_TRSV_REG6 0x418 1661ad6abbaSpatrick #define IMX8MM_PCIE_PHY_TRSV_REG6_GEN2_DEEMP 0xf 1676a2b914cSpatrick 1686a2b914cSpatrick #define ANATOP_PLLOUT_CTL 0x74 1696a2b914cSpatrick #define ANATOP_PLLOUT_CTL_CKE (1 << 4) 1706a2b914cSpatrick #define ANATOP_PLLOUT_CTL_SEL_SYSPLL1 0xb 1716a2b914cSpatrick #define ANATOP_PLLOUT_CTL_SEL_MASK 0xf 1726a2b914cSpatrick #define ANATOP_PLLOUT_DIV 0x7c 1736a2b914cSpatrick #define ANATOP_PLLOUT_DIV_SYSPLL1 0x7 1746a2b914cSpatrick 1755f800b9bSkettenis /* Rockchip RK3568/RK3588 registers */ 176f98fd054Skettenis #define PCIE_CLIENT_GENERAL_CON 0x0000 177f98fd054Skettenis #define PCIE_CLIENT_DEV_TYPE_RC ((0xf << 4) << 16 | (0x4 << 4)) 178f98fd054Skettenis #define PCIE_CLIENT_LINK_REQ_RST_GRT ((1 << 3) << 16 | (1 << 3)) 179f98fd054Skettenis #define PCIE_CLIENT_APP_LTSSM_ENABLE ((1 << 2) << 16 | (1 << 2)) 1805f800b9bSkettenis #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x0008 1815f800b9bSkettenis #define PCIE_CLIENT_INTR_MASK_LEGACY 0x001c 182f98fd054Skettenis #define PCIE_CLIENT_HOT_RESET_CTRL 0x0180 183f98fd054Skettenis #define PCIE_CLIENT_APP_LTSSM_ENABLE_ENHANCE ((1 << 4) << 16 | (1 << 4)) 184f98fd054Skettenis #define PCIE_CLIENT_LTSSM_STATUS 0x0300 185f98fd054Skettenis #define PCIE_CLIENT_RDLH_LINK_UP (1 << 17) 186f98fd054Skettenis #define PCIE_CLIENT_SMLH_LINK_UP (1 << 16) 187f98fd054Skettenis #define PCIE_CLIENT_LTSSM_MASK (0x1f << 0) 188f98fd054Skettenis #define PCIE_CLIENT_LTSSM_UP (0x11 << 0) 189f98fd054Skettenis 1907659d2d7Skettenis #define HREAD4(sc, reg) \ 1917659d2d7Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 1927659d2d7Skettenis #define HWRITE4(sc, reg, val) \ 1937659d2d7Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 1947659d2d7Skettenis #define HSET4(sc, reg, bits) \ 1957659d2d7Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 1967659d2d7Skettenis #define HCLR4(sc, reg, bits) \ 1977659d2d7Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 1987659d2d7Skettenis 1994605d28eSkettenis struct dwpcie_range { 2004605d28eSkettenis uint32_t flags; 2014605d28eSkettenis uint64_t pci_base; 2024605d28eSkettenis uint64_t phys_base; 2034605d28eSkettenis uint64_t size; 2044605d28eSkettenis }; 2054605d28eSkettenis 2065f800b9bSkettenis struct dwpcie_intx { 2075f800b9bSkettenis int (*di_func)(void *); 2085f800b9bSkettenis void *di_arg; 2095f800b9bSkettenis int di_ipl; 2105f800b9bSkettenis int di_flags; 2115f800b9bSkettenis int di_pin; 2125f800b9bSkettenis struct evcount di_count; 2135f800b9bSkettenis char *di_name; 2145f800b9bSkettenis struct dwpcie_softc *di_sc; 2155f800b9bSkettenis TAILQ_ENTRY(dwpcie_intx) di_next; 2165f800b9bSkettenis }; 2175f800b9bSkettenis 2189a76443bSkettenis #define DWPCIE_MAX_MSI 64 219d5dfbc11Skettenis 220d5dfbc11Skettenis struct dwpcie_msi { 221d5dfbc11Skettenis int (*dm_func)(void *); 222d5dfbc11Skettenis void *dm_arg; 223d5dfbc11Skettenis int dm_ipl; 224d5dfbc11Skettenis int dm_flags; 225d5dfbc11Skettenis int dm_vec; 2269a76443bSkettenis int dm_nvec; 227d5dfbc11Skettenis struct evcount dm_count; 228d5dfbc11Skettenis char *dm_name; 229d5dfbc11Skettenis }; 230d5dfbc11Skettenis 2317659d2d7Skettenis struct dwpcie_softc { 2327659d2d7Skettenis struct device sc_dev; 2337659d2d7Skettenis bus_space_tag_t sc_iot; 2347659d2d7Skettenis bus_space_handle_t sc_ioh; 23531876e8bSkettenis bus_dma_tag_t sc_dmat; 2366a2b914cSpatrick 23731876e8bSkettenis bus_addr_t sc_ctrl_base; 23831876e8bSkettenis bus_size_t sc_ctrl_size; 23901dd2b7cSkettenis 24001dd2b7cSkettenis bus_addr_t sc_conf_base; 24101dd2b7cSkettenis bus_size_t sc_conf_size; 24201dd2b7cSkettenis bus_space_handle_t sc_conf_ioh; 243c244e331Skettenis 244c244e331Skettenis bus_addr_t sc_glue_base; 245c244e331Skettenis bus_size_t sc_glue_size; 246c244e331Skettenis bus_space_handle_t sc_glue_ioh; 247c244e331Skettenis 248a848a3cbSpatrick bus_addr_t sc_atu_base; 249a848a3cbSpatrick bus_size_t sc_atu_size; 250a848a3cbSpatrick bus_space_handle_t sc_atu_ioh; 251a848a3cbSpatrick 2526a2b914cSpatrick bus_addr_t sc_io_base; 2536a2b914cSpatrick bus_addr_t sc_io_bus_addr; 2546a2b914cSpatrick bus_size_t sc_io_size; 2556a2b914cSpatrick bus_addr_t sc_mem_base; 2566a2b914cSpatrick bus_addr_t sc_mem_bus_addr; 2576a2b914cSpatrick bus_size_t sc_mem_size; 258d2397242Skettenis bus_addr_t sc_pmem_base; 259d2397242Skettenis bus_addr_t sc_pmem_bus_addr; 260d2397242Skettenis bus_size_t sc_pmem_size; 2617659d2d7Skettenis 2624605d28eSkettenis int sc_node; 2637659d2d7Skettenis int sc_acells; 2647659d2d7Skettenis int sc_scells; 2657659d2d7Skettenis int sc_pacells; 2667659d2d7Skettenis int sc_pscells; 2674605d28eSkettenis struct dwpcie_range *sc_ranges; 268d43be508Skettenis int sc_nranges; 2697659d2d7Skettenis 27071fe361bSkettenis struct bus_space sc_bus_iot; 27171fe361bSkettenis struct bus_space sc_bus_memt; 27271fe361bSkettenis 2732b0be198Skettenis struct machine_pci_chipset sc_pc; 2747659d2d7Skettenis int sc_bus; 275f2c2f061Skettenis 2766a2b914cSpatrick int sc_num_viewport; 2776a2b914cSpatrick int sc_atu_unroll; 278a848a3cbSpatrick int sc_atu_viewport; 2796a2b914cSpatrick 280f2c2f061Skettenis void *sc_ih; 2815f800b9bSkettenis struct interrupt_controller sc_ic; 2825f800b9bSkettenis TAILQ_HEAD(,dwpcie_intx) sc_intx[4]; 283d5dfbc11Skettenis 2849a76443bSkettenis void *sc_msi_ih[2]; 285d5dfbc11Skettenis uint64_t sc_msi_addr; 2869a76443bSkettenis uint64_t sc_msi_mask; 2879a76443bSkettenis struct dwpcie_msi sc_msi[DWPCIE_MAX_MSI]; 2889a76443bSkettenis int sc_num_msi; 2897659d2d7Skettenis }; 2907659d2d7Skettenis 291cc0ede06Spatrick struct dwpcie_intr_handle { 2922b0be198Skettenis struct machine_intr_handle pih_ih; 293d5dfbc11Skettenis struct dwpcie_softc *pih_sc; 294d5dfbc11Skettenis struct dwpcie_msi *pih_dm; 295cc0ede06Spatrick bus_dma_tag_t pih_dmat; 296cc0ede06Spatrick bus_dmamap_t pih_map; 297cc0ede06Spatrick }; 298cc0ede06Spatrick 2997659d2d7Skettenis int dwpcie_match(struct device *, void *, void *); 3007659d2d7Skettenis void dwpcie_attach(struct device *, struct device *, void *); 3017659d2d7Skettenis 3029fdf0c62Smpi const struct cfattach dwpcie_ca = { 3037659d2d7Skettenis sizeof (struct dwpcie_softc), dwpcie_match, dwpcie_attach 3047659d2d7Skettenis }; 3057659d2d7Skettenis 3067659d2d7Skettenis struct cfdriver dwpcie_cd = { 3077659d2d7Skettenis NULL, "dwpcie", DV_DULL 3087659d2d7Skettenis }; 3097659d2d7Skettenis 3107659d2d7Skettenis int 3117659d2d7Skettenis dwpcie_match(struct device *parent, void *match, void *aux) 3127659d2d7Skettenis { 3137659d2d7Skettenis struct fdt_attach_args *faa = aux; 3147659d2d7Skettenis 31508f55413Skn return (OF_is_compatible(faa->fa_node, "amlogic,g12a-pcie") || 31608f55413Skn OF_is_compatible(faa->fa_node, "baikal,bm1000-pcie") || 3171ad6abbaSpatrick OF_is_compatible(faa->fa_node, "fsl,imx8mm-pcie") || 318919f025aSkettenis OF_is_compatible(faa->fa_node, "fsl,imx8mq-pcie") || 3195f3e3118Skettenis OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie") || 320a848a3cbSpatrick OF_is_compatible(faa->fa_node, "qcom,pcie-sc8280xp") || 321c53ff863Spatrick OF_is_compatible(faa->fa_node, "qcom,pcie-x1e80100") || 3225f3e3118Skettenis OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie") || 3235f800b9bSkettenis OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie") || 324919f025aSkettenis OF_is_compatible(faa->fa_node, "sifive,fu740-pcie")); 3257659d2d7Skettenis } 3267659d2d7Skettenis 32731876e8bSkettenis void dwpcie_attach_deferred(struct device *); 32831876e8bSkettenis 3295f3e3118Skettenis void dwpcie_atu_disable(struct dwpcie_softc *, int); 3306a2b914cSpatrick void dwpcie_atu_config(struct dwpcie_softc *, int, int, 3316a2b914cSpatrick uint64_t, uint64_t, uint64_t); 3326a2b914cSpatrick void dwpcie_link_config(struct dwpcie_softc *); 3336a2b914cSpatrick int dwpcie_link_up(struct dwpcie_softc *); 3346a2b914cSpatrick 335c3f9cac9Spatrick int dwpcie_armada8k_init(struct dwpcie_softc *); 3364605d28eSkettenis int dwpcie_armada8k_link_up(struct dwpcie_softc *); 337f2c2f061Skettenis int dwpcie_armada8k_intr(void *); 3387659d2d7Skettenis 339c244e331Skettenis int dwpcie_g12a_init(struct dwpcie_softc *); 340c244e331Skettenis int dwpcie_g12a_link_up(struct dwpcie_softc *); 341c244e331Skettenis 342c3f9cac9Spatrick int dwpcie_imx8mq_init(struct dwpcie_softc *); 3436a2b914cSpatrick int dwpcie_imx8mq_intr(void *); 3446a2b914cSpatrick 345d2397242Skettenis int dwpcie_fu740_init(struct dwpcie_softc *); 3465f800b9bSkettenis 3475f3e3118Skettenis int dwpcie_rk3568_init(struct dwpcie_softc *); 3485f800b9bSkettenis int dwpcie_rk3568_intr(void *); 3495f800b9bSkettenis void *dwpcie_rk3568_intr_establish(void *, int *, int, 3505f800b9bSkettenis struct cpu_info *, int (*)(void *), void *, char *); 3515f800b9bSkettenis void dwpcie_rk3568_intr_disestablish(void *); 3525f800b9bSkettenis void dwpcie_rk3568_intr_barrier(void *); 3535f800b9bSkettenis 354a848a3cbSpatrick int dwpcie_sc8280xp_init(struct dwpcie_softc *); 355d2397242Skettenis 3567659d2d7Skettenis void dwpcie_attach_hook(struct device *, struct device *, 3577659d2d7Skettenis struct pcibus_attach_args *); 3587659d2d7Skettenis int dwpcie_bus_maxdevs(void *, int); 3597659d2d7Skettenis pcitag_t dwpcie_make_tag(void *, int, int, int); 3607659d2d7Skettenis void dwpcie_decompose_tag(void *, pcitag_t, int *, int *, int *); 3617659d2d7Skettenis int dwpcie_conf_size(void *, pcitag_t); 3627659d2d7Skettenis pcireg_t dwpcie_conf_read(void *, pcitag_t, int); 3637659d2d7Skettenis void dwpcie_conf_write(void *, pcitag_t, int, pcireg_t); 364619b146dSpatrick int dwpcie_probe_device_hook(void *, struct pci_attach_args *); 3657659d2d7Skettenis 3667659d2d7Skettenis int dwpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 3677659d2d7Skettenis const char *dwpcie_intr_string(void *, pci_intr_handle_t); 3687659d2d7Skettenis void *dwpcie_intr_establish(void *, pci_intr_handle_t, int, 369d67371fdSpatrick struct cpu_info *, int (*)(void *), void *, char *); 3707659d2d7Skettenis void dwpcie_intr_disestablish(void *, void *); 3717659d2d7Skettenis 37271fe361bSkettenis int dwpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 37371fe361bSkettenis bus_space_handle_t *); 37471fe361bSkettenis int dwpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 37571fe361bSkettenis bus_space_handle_t *); 37671fe361bSkettenis 377cc0ede06Spatrick struct interrupt_controller dwpcie_ic = { 378cc0ede06Spatrick .ic_barrier = intr_barrier 379cc0ede06Spatrick }; 380cc0ede06Spatrick 3817659d2d7Skettenis void 3827659d2d7Skettenis dwpcie_attach(struct device *parent, struct device *self, void *aux) 3837659d2d7Skettenis { 3847659d2d7Skettenis struct dwpcie_softc *sc = (struct dwpcie_softc *)self; 3857659d2d7Skettenis struct fdt_attach_args *faa = aux; 3864605d28eSkettenis uint32_t *ranges; 3874605d28eSkettenis int i, j, nranges, rangeslen; 388a848a3cbSpatrick int atu, config, ctrl, glue; 3897659d2d7Skettenis 3907659d2d7Skettenis if (faa->fa_nreg < 2) { 3917659d2d7Skettenis printf(": no registers\n"); 3927659d2d7Skettenis return; 3937659d2d7Skettenis } 3947659d2d7Skettenis 395c244e331Skettenis sc->sc_ctrl_base = faa->fa_reg[0].addr; 396c244e331Skettenis sc->sc_ctrl_size = faa->fa_reg[0].size; 397c244e331Skettenis 398a848a3cbSpatrick ctrl = OF_getindex(faa->fa_node, "dbi", "reg-names"); 399a848a3cbSpatrick if (ctrl >= 0 && ctrl < faa->fa_nreg) { 400a848a3cbSpatrick sc->sc_ctrl_base = faa->fa_reg[ctrl].addr; 401a848a3cbSpatrick sc->sc_ctrl_size = faa->fa_reg[ctrl].size; 402a848a3cbSpatrick } 403a848a3cbSpatrick 404c244e331Skettenis config = OF_getindex(faa->fa_node, "config", "reg-names"); 405c244e331Skettenis if (config < 0 || config >= faa->fa_nreg) { 406c244e331Skettenis printf(": no config registers\n"); 407c244e331Skettenis return; 408c244e331Skettenis } 409c244e331Skettenis 41001dd2b7cSkettenis sc->sc_conf_base = faa->fa_reg[config].addr; 41101dd2b7cSkettenis sc->sc_conf_size = faa->fa_reg[config].size; 412c244e331Skettenis 413a848a3cbSpatrick sc->sc_atu_base = sc->sc_ctrl_base + 0x300000; 414a848a3cbSpatrick sc->sc_atu_size = sc->sc_ctrl_size - 0x300000; 415a848a3cbSpatrick 416a848a3cbSpatrick atu = OF_getindex(faa->fa_node, "atu", "reg-names"); 417a848a3cbSpatrick if (atu >= 0 && atu < faa->fa_nreg) { 418a848a3cbSpatrick sc->sc_atu_base = faa->fa_reg[atu].addr; 419a848a3cbSpatrick sc->sc_atu_size = faa->fa_reg[atu].size; 420a848a3cbSpatrick } 421a848a3cbSpatrick 422c244e331Skettenis if (OF_is_compatible(faa->fa_node, "amlogic,g12a-pcie")) { 423c244e331Skettenis glue = OF_getindex(faa->fa_node, "cfg", "reg-names"); 424c244e331Skettenis if (glue < 0 || glue >= faa->fa_nreg) { 425c244e331Skettenis printf(": no glue registers\n"); 426c244e331Skettenis return; 427c244e331Skettenis } 428c244e331Skettenis 429c244e331Skettenis sc->sc_glue_base = faa->fa_reg[glue].addr; 430c244e331Skettenis sc->sc_glue_size = faa->fa_reg[glue].size; 431c244e331Skettenis } 432c244e331Skettenis 4335f800b9bSkettenis if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie") || 4345f800b9bSkettenis OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie")) { 435f98fd054Skettenis glue = OF_getindex(faa->fa_node, "apb", "reg-names"); 436f98fd054Skettenis if (glue < 0 || glue >= faa->fa_nreg) { 437f98fd054Skettenis printf(": no glue registers\n"); 438f98fd054Skettenis return; 439f98fd054Skettenis } 440f98fd054Skettenis 441f98fd054Skettenis sc->sc_glue_base = faa->fa_reg[glue].addr; 442f98fd054Skettenis sc->sc_glue_size = faa->fa_reg[glue].size; 443f98fd054Skettenis } 444f98fd054Skettenis 4457659d2d7Skettenis sc->sc_iot = faa->fa_iot; 44631876e8bSkettenis sc->sc_dmat = faa->fa_dmat; 4474605d28eSkettenis sc->sc_node = faa->fa_node; 4487659d2d7Skettenis 4497659d2d7Skettenis sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", 4507659d2d7Skettenis faa->fa_acells); 4517659d2d7Skettenis sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", 4527659d2d7Skettenis faa->fa_scells); 4537659d2d7Skettenis sc->sc_pacells = faa->fa_acells; 4547659d2d7Skettenis sc->sc_pscells = faa->fa_scells; 4557659d2d7Skettenis 4564605d28eSkettenis rangeslen = OF_getproplen(sc->sc_node, "ranges"); 4574605d28eSkettenis if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) || 4584605d28eSkettenis (rangeslen / sizeof(uint32_t)) % (sc->sc_acells + 4594605d28eSkettenis sc->sc_pacells + sc->sc_scells)) { 4604605d28eSkettenis printf(": invalid ranges property\n"); 4614605d28eSkettenis return; 4624605d28eSkettenis } 4634605d28eSkettenis 4644605d28eSkettenis ranges = malloc(rangeslen, M_TEMP, M_WAITOK); 4654605d28eSkettenis OF_getpropintarray(sc->sc_node, "ranges", ranges, 4664605d28eSkettenis rangeslen); 4674605d28eSkettenis 4684605d28eSkettenis nranges = (rangeslen / sizeof(uint32_t)) / 4694605d28eSkettenis (sc->sc_acells + sc->sc_pacells + sc->sc_scells); 4704605d28eSkettenis sc->sc_ranges = mallocarray(nranges, 4714605d28eSkettenis sizeof(struct dwpcie_range), M_TEMP, M_WAITOK); 472d43be508Skettenis sc->sc_nranges = nranges; 4734605d28eSkettenis 474d43be508Skettenis for (i = 0, j = 0; i < sc->sc_nranges; i++) { 4754605d28eSkettenis sc->sc_ranges[i].flags = ranges[j++]; 4764605d28eSkettenis sc->sc_ranges[i].pci_base = ranges[j++]; 4774605d28eSkettenis if (sc->sc_acells - 1 == 2) { 4784605d28eSkettenis sc->sc_ranges[i].pci_base <<= 32; 4794605d28eSkettenis sc->sc_ranges[i].pci_base |= ranges[j++]; 4804605d28eSkettenis } 4814605d28eSkettenis sc->sc_ranges[i].phys_base = ranges[j++]; 4824605d28eSkettenis if (sc->sc_pacells == 2) { 4834605d28eSkettenis sc->sc_ranges[i].phys_base <<= 32; 4844605d28eSkettenis sc->sc_ranges[i].phys_base |= ranges[j++]; 4854605d28eSkettenis } 4864605d28eSkettenis sc->sc_ranges[i].size = ranges[j++]; 4874605d28eSkettenis if (sc->sc_scells == 2) { 4884605d28eSkettenis sc->sc_ranges[i].size <<= 32; 4894605d28eSkettenis sc->sc_ranges[i].size |= ranges[j++]; 4904605d28eSkettenis } 4914605d28eSkettenis } 4924605d28eSkettenis 4934605d28eSkettenis free(ranges, M_TEMP, rangeslen); 4944605d28eSkettenis 49531876e8bSkettenis if (bus_space_map(sc->sc_iot, sc->sc_ctrl_base, 49631876e8bSkettenis sc->sc_ctrl_size, 0, &sc->sc_ioh)) { 497f9087cb3Spatrick free(sc->sc_ranges, M_TEMP, sc->sc_nranges * 498f9087cb3Spatrick sizeof(struct dwpcie_range)); 4997659d2d7Skettenis printf(": can't map ctrl registers\n"); 5007659d2d7Skettenis return; 5017659d2d7Skettenis } 5027659d2d7Skettenis 50301dd2b7cSkettenis if (bus_space_map(sc->sc_iot, sc->sc_conf_base, 50401dd2b7cSkettenis sc->sc_conf_size, 0, &sc->sc_conf_ioh)) { 50531876e8bSkettenis bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ctrl_size); 506f9087cb3Spatrick free(sc->sc_ranges, M_TEMP, sc->sc_nranges * 507f9087cb3Spatrick sizeof(struct dwpcie_range)); 5086a2b914cSpatrick printf(": can't map config registers\n"); 5096a2b914cSpatrick return; 5106a2b914cSpatrick } 5116a2b914cSpatrick 5126a2b914cSpatrick sc->sc_num_viewport = OF_getpropint(sc->sc_node, "num-viewport", 2); 5137659d2d7Skettenis 5147659d2d7Skettenis printf("\n"); 5157659d2d7Skettenis 5164605d28eSkettenis pinctrl_byname(sc->sc_node, "default"); 5176a2b914cSpatrick clock_set_assigned(sc->sc_node); 5187659d2d7Skettenis 51931876e8bSkettenis config_defer(self, dwpcie_attach_deferred); 52031876e8bSkettenis } 52131876e8bSkettenis 52231876e8bSkettenis void 52331876e8bSkettenis dwpcie_attach_deferred(struct device *self) 52431876e8bSkettenis { 52531876e8bSkettenis struct dwpcie_softc *sc = (struct dwpcie_softc *)self; 52631876e8bSkettenis struct pcibus_attach_args pba; 52731876e8bSkettenis bus_addr_t iobase, iolimit; 52831876e8bSkettenis bus_addr_t membase, memlimit; 529d2397242Skettenis bus_addr_t pmembase, pmemlimit; 53031876e8bSkettenis uint32_t bus_range[2]; 53131876e8bSkettenis pcireg_t bir, blr, csr; 53231876e8bSkettenis int i, error = 0; 53331876e8bSkettenis 5344605d28eSkettenis if (OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie")) 535c3f9cac9Spatrick error = dwpcie_armada8k_init(sc); 536c244e331Skettenis if (OF_is_compatible(sc->sc_node, "amlogic,g12a-pcie")) 537c244e331Skettenis error = dwpcie_g12a_init(sc); 5381ad6abbaSpatrick if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie") || 5391ad6abbaSpatrick OF_is_compatible(sc->sc_node, "fsl,imx8mq-pcie")) 540c3f9cac9Spatrick error = dwpcie_imx8mq_init(sc); 541c53ff863Spatrick if (OF_is_compatible(sc->sc_node, "qcom,pcie-sc8280xp") || 542c53ff863Spatrick OF_is_compatible(sc->sc_node, "qcom,pcie-x1e80100")) 543a848a3cbSpatrick error = dwpcie_sc8280xp_init(sc); 5445f800b9bSkettenis if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-pcie") || 5455f800b9bSkettenis OF_is_compatible(sc->sc_node, "rockchip,rk3588-pcie")) 5465f3e3118Skettenis error = dwpcie_rk3568_init(sc); 547d2397242Skettenis if (OF_is_compatible(sc->sc_node, "sifive,fu740-pcie")) 548d2397242Skettenis error = dwpcie_fu740_init(sc); 549c3f9cac9Spatrick if (error != 0) { 55001dd2b7cSkettenis bus_space_unmap(sc->sc_iot, sc->sc_conf_ioh, sc->sc_conf_size); 55131876e8bSkettenis bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ctrl_size); 552c3f9cac9Spatrick free(sc->sc_ranges, M_TEMP, sc->sc_nranges * 553c3f9cac9Spatrick sizeof(struct dwpcie_range)); 554c3f9cac9Spatrick printf("%s: can't initialize hardware\n", 555c3f9cac9Spatrick sc->sc_dev.dv_xname); 556c3f9cac9Spatrick return; 557c3f9cac9Spatrick } 5586a2b914cSpatrick 559a848a3cbSpatrick sc->sc_atu_viewport = -1; 5606a2b914cSpatrick if (HREAD4(sc, IATU_VIEWPORT) == 0xffffffff) { 5616a2b914cSpatrick sc->sc_atu_unroll = 1; 562a848a3cbSpatrick if (bus_space_map(sc->sc_iot, sc->sc_atu_base, 563a848a3cbSpatrick sc->sc_atu_size, 0, &sc->sc_atu_ioh)) { 564a848a3cbSpatrick bus_space_unmap(sc->sc_iot, sc->sc_conf_ioh, 565a848a3cbSpatrick sc->sc_conf_size); 566a848a3cbSpatrick bus_space_unmap(sc->sc_iot, sc->sc_ioh, 567a848a3cbSpatrick sc->sc_ctrl_size); 568a848a3cbSpatrick free(sc->sc_ranges, M_TEMP, sc->sc_nranges * 569a848a3cbSpatrick sizeof(struct dwpcie_range)); 570a848a3cbSpatrick printf("%s: can't map atu registers\n", 571a848a3cbSpatrick sc->sc_dev.dv_xname); 572a848a3cbSpatrick return; 573a848a3cbSpatrick } 5746a2b914cSpatrick } 5756a2b914cSpatrick 5766a2b914cSpatrick /* Set up address translation for I/O space. */ 5776a2b914cSpatrick for (i = 0; i < sc->sc_nranges; i++) { 5786a2b914cSpatrick if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 5796a2b914cSpatrick sc->sc_ranges[i].size > 0) { 5806a2b914cSpatrick sc->sc_io_base = sc->sc_ranges[i].phys_base; 5816a2b914cSpatrick sc->sc_io_bus_addr = sc->sc_ranges[i].pci_base; 5826a2b914cSpatrick sc->sc_io_size = sc->sc_ranges[i].size; 5836a2b914cSpatrick } 5846a2b914cSpatrick if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 && 5856a2b914cSpatrick sc->sc_ranges[i].size > 0) { 5866a2b914cSpatrick sc->sc_mem_base = sc->sc_ranges[i].phys_base; 5876a2b914cSpatrick sc->sc_mem_bus_addr = sc->sc_ranges[i].pci_base; 5886a2b914cSpatrick sc->sc_mem_size = sc->sc_ranges[i].size; 5896a2b914cSpatrick } 590d2397242Skettenis if ((sc->sc_ranges[i].flags & 0x03000000) == 0x03000000 && 591d2397242Skettenis sc->sc_ranges[i].size > 0) { 592d2397242Skettenis sc->sc_pmem_base = sc->sc_ranges[i].phys_base; 593d2397242Skettenis sc->sc_pmem_bus_addr = sc->sc_ranges[i].pci_base; 594d2397242Skettenis sc->sc_pmem_size = sc->sc_ranges[i].size; 5956a2b914cSpatrick } 596d2397242Skettenis } 597d2397242Skettenis if (sc->sc_mem_size == 0) { 598d2397242Skettenis printf("%s: no memory mapped I/O window\n", 599d2397242Skettenis sc->sc_dev.dv_xname); 600d2397242Skettenis return; 601d2397242Skettenis } 602d2397242Skettenis 603d2397242Skettenis /* 604d2397242Skettenis * Disable prefetchable memory mapped I/O window if we don't 605d2397242Skettenis * have enough viewports to enable it. 606d2397242Skettenis */ 607d2397242Skettenis if (sc->sc_num_viewport < 4) 608d2397242Skettenis sc->sc_pmem_size = 0; 6096a2b914cSpatrick 6105f3e3118Skettenis for (i = 0; i < sc->sc_num_viewport; i++) 6115f3e3118Skettenis dwpcie_atu_disable(sc, i); 6125f3e3118Skettenis 6136a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX0, 6146a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_mem_base, 6156a2b914cSpatrick sc->sc_mem_bus_addr, sc->sc_mem_size); 616d2397242Skettenis if (sc->sc_num_viewport > 2 && sc->sc_io_size > 0) 6176a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX2, 6186a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 6196a2b914cSpatrick sc->sc_io_bus_addr, sc->sc_io_size); 620d2397242Skettenis if (sc->sc_num_viewport > 3 && sc->sc_pmem_size > 0) 621d2397242Skettenis dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX3, 622d2397242Skettenis IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_pmem_base, 623d2397242Skettenis sc->sc_pmem_bus_addr, sc->sc_pmem_size); 6244605d28eSkettenis 6254605d28eSkettenis /* Enable modification of read-only bits. */ 6264605d28eSkettenis HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN); 6274605d28eSkettenis 6284605d28eSkettenis /* A Root Port is a PCI-PCI Bridge. */ 6294605d28eSkettenis HWRITE4(sc, PCI_CLASS_REG, 6304605d28eSkettenis PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT | 6314605d28eSkettenis PCI_SUBCLASS_BRIDGE_PCI << PCI_SUBCLASS_SHIFT); 6324605d28eSkettenis 6334605d28eSkettenis /* Clear BAR as U-Boot seems to leave garbage in it. */ 6347659d2d7Skettenis HWRITE4(sc, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT); 6357659d2d7Skettenis HWRITE4(sc, PCI_MAPREG_START + 4, 0); 6364605d28eSkettenis 6377385e486Skettenis /* Enable 32-bit I/O addressing. */ 6387385e486Skettenis HSET4(sc, PPB_REG_IOSTATUS, 6397385e486Skettenis PPB_IO_32BIT | (PPB_IO_32BIT << PPB_IOLIMIT_SHIFT)); 6407385e486Skettenis 6414605d28eSkettenis /* Make sure read-only bits are write-protected. */ 6424605d28eSkettenis HCLR4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN); 6437659d2d7Skettenis 6447659d2d7Skettenis /* Set up bus range. */ 6457659d2d7Skettenis if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range, 6465f800b9bSkettenis sizeof(bus_range)) != sizeof(bus_range)) { 6477659d2d7Skettenis bus_range[0] = 0; 6487659d2d7Skettenis bus_range[1] = 31; 6497659d2d7Skettenis } 6507659d2d7Skettenis sc->sc_bus = bus_range[0]; 651d43be508Skettenis 652d43be508Skettenis /* Initialize bus range. */ 653d43be508Skettenis bir = bus_range[0]; 654d43be508Skettenis bir |= ((bus_range[0] + 1) << 8); 655d43be508Skettenis bir |= (bus_range[1] << 16); 656d43be508Skettenis HWRITE4(sc, PPB_REG_BUSINFO, bir); 6577659d2d7Skettenis 658d2397242Skettenis /* Initialize memory mapped I/O window. */ 659d2397242Skettenis membase = sc->sc_mem_bus_addr; 660d2397242Skettenis memlimit = membase + sc->sc_mem_size - 1; 661d2397242Skettenis blr = memlimit & PPB_MEM_MASK; 662d2397242Skettenis blr |= (membase >> PPB_MEM_SHIFT); 663d2397242Skettenis HWRITE4(sc, PPB_REG_MEM, blr); 664d2397242Skettenis 665d43be508Skettenis /* Initialize I/O window. */ 666d2397242Skettenis if (sc->sc_io_size > 0) { 6676a2b914cSpatrick iobase = sc->sc_io_bus_addr; 6686a2b914cSpatrick iolimit = iobase + sc->sc_io_size - 1; 669d43be508Skettenis blr = iolimit & PPB_IO_MASK; 670d43be508Skettenis blr |= (iobase >> PPB_IO_SHIFT); 671d43be508Skettenis HWRITE4(sc, PPB_REG_IOSTATUS, blr); 672d43be508Skettenis blr = (iobase & 0xffff0000) >> 16; 673d43be508Skettenis blr |= iolimit & 0xffff0000; 674d43be508Skettenis HWRITE4(sc, PPB_REG_IO_HI, blr); 675d2397242Skettenis } else { 676d2397242Skettenis HWRITE4(sc, PPB_REG_IOSTATUS, 0x000000ff); 677d2397242Skettenis HWRITE4(sc, PPB_REG_IO_HI, 0x0000ffff); 678d2397242Skettenis } 679d43be508Skettenis 680d2397242Skettenis /* Initialize prefetchable memory mapped I/O window. */ 681d2397242Skettenis if (sc->sc_pmem_size > 0) { 682d2397242Skettenis pmembase = sc->sc_pmem_bus_addr; 683d2397242Skettenis pmemlimit = pmembase + sc->sc_pmem_size - 1; 684d2397242Skettenis blr = pmemlimit & PPB_MEM_MASK; 6854bc9c22fSkettenis blr |= ((pmembase & PPB_MEM_MASK) >> PPB_MEM_SHIFT); 686d2397242Skettenis HWRITE4(sc, PPB_REG_PREFMEM, blr); 687d2397242Skettenis HWRITE4(sc, PPB_REG_PREFBASE_HI32, pmembase >> 32); 688d2397242Skettenis HWRITE4(sc, PPB_REG_PREFLIM_HI32, pmemlimit >> 32); 689d2397242Skettenis } else { 690d43be508Skettenis HWRITE4(sc, PPB_REG_PREFMEM, 0x0000ffff); 691d43be508Skettenis HWRITE4(sc, PPB_REG_PREFBASE_HI32, 0); 692d43be508Skettenis HWRITE4(sc, PPB_REG_PREFLIM_HI32, 0); 693d2397242Skettenis } 694d43be508Skettenis 695d2397242Skettenis csr = PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 696d2397242Skettenis if (sc->sc_io_size > 0) 697d43be508Skettenis csr |= PCI_COMMAND_IO_ENABLE; 698d43be508Skettenis HWRITE4(sc, PCI_COMMAND_STATUS_REG, csr); 6994605d28eSkettenis 70071fe361bSkettenis memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); 70171fe361bSkettenis sc->sc_bus_iot.bus_private = sc; 70271fe361bSkettenis sc->sc_bus_iot._space_map = dwpcie_bs_iomap; 70371fe361bSkettenis memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); 70471fe361bSkettenis sc->sc_bus_memt.bus_private = sc; 70571fe361bSkettenis sc->sc_bus_memt._space_map = dwpcie_bs_memmap; 70671fe361bSkettenis 7077659d2d7Skettenis sc->sc_pc.pc_conf_v = sc; 7087659d2d7Skettenis sc->sc_pc.pc_attach_hook = dwpcie_attach_hook; 7097659d2d7Skettenis sc->sc_pc.pc_bus_maxdevs = dwpcie_bus_maxdevs; 7107659d2d7Skettenis sc->sc_pc.pc_make_tag = dwpcie_make_tag; 7117659d2d7Skettenis sc->sc_pc.pc_decompose_tag = dwpcie_decompose_tag; 7127659d2d7Skettenis sc->sc_pc.pc_conf_size = dwpcie_conf_size; 7137659d2d7Skettenis sc->sc_pc.pc_conf_read = dwpcie_conf_read; 7147659d2d7Skettenis sc->sc_pc.pc_conf_write = dwpcie_conf_write; 715619b146dSpatrick sc->sc_pc.pc_probe_device_hook = dwpcie_probe_device_hook; 7167659d2d7Skettenis 7177659d2d7Skettenis sc->sc_pc.pc_intr_v = sc; 7187659d2d7Skettenis sc->sc_pc.pc_intr_map = dwpcie_intr_map; 719e410b95bSkettenis sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi; 72056d02c00Skettenis sc->sc_pc.pc_intr_map_msivec = _pci_intr_map_msivec; 721e410b95bSkettenis sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix; 7227659d2d7Skettenis sc->sc_pc.pc_intr_string = dwpcie_intr_string; 7237659d2d7Skettenis sc->sc_pc.pc_intr_establish = dwpcie_intr_establish; 7247659d2d7Skettenis sc->sc_pc.pc_intr_disestablish = dwpcie_intr_disestablish; 7257659d2d7Skettenis 7267659d2d7Skettenis memset(&pba, 0, sizeof(pba)); 7277659d2d7Skettenis pba.pba_busname = "pci"; 72871fe361bSkettenis pba.pba_iot = &sc->sc_bus_iot; 72971fe361bSkettenis pba.pba_memt = &sc->sc_bus_memt; 73031876e8bSkettenis pba.pba_dmat = sc->sc_dmat; 7317659d2d7Skettenis pba.pba_pc = &sc->sc_pc; 7327659d2d7Skettenis pba.pba_domain = pci_ndomains++; 7337659d2d7Skettenis pba.pba_bus = sc->sc_bus; 7349a76443bSkettenis 735094225feSkn if (OF_is_compatible(sc->sc_node, "baikal,bm1000-pcie") || 736094225feSkn OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie") || 737d0adc912Spatrick OF_getproplen(sc->sc_node, "msi-map") > 0 || 738d5dfbc11Skettenis sc->sc_msi_addr) 7390045467fSkettenis pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; 7409a76443bSkettenis 7419a76443bSkettenis /* 742*54fbbda3Sjsg * Only support multiple MSI vectors if we have enough MSI 7439a76443bSkettenis * interrupts (or are using an external interrupt controller 744*54fbbda3Sjsg * that hopefully supports plenty of MSI interrupts). 7459a76443bSkettenis */ 7469a76443bSkettenis if (OF_getproplen(sc->sc_node, "msi-map") > 0 || 7479a76443bSkettenis sc->sc_num_msi > 32) 74856d02c00Skettenis pba.pba_flags |= PCI_FLAGS_MSIVEC_ENABLED; 7497659d2d7Skettenis 750f02e807fSpatrick pci_dopm = 1; 751f02e807fSpatrick 7527659d2d7Skettenis config_found(self, &pba, NULL); 7537659d2d7Skettenis } 7547659d2d7Skettenis 7557659d2d7Skettenis void 7566a2b914cSpatrick dwpcie_link_config(struct dwpcie_softc *sc) 7576a2b914cSpatrick { 7586a2b914cSpatrick uint32_t mode, width, reg; 7596a2b914cSpatrick int lanes; 7606a2b914cSpatrick 7616a2b914cSpatrick lanes = OF_getpropint(sc->sc_node, "num-lanes", 0); 7626a2b914cSpatrick 7636a2b914cSpatrick switch (lanes) { 7646a2b914cSpatrick case 1: 7656a2b914cSpatrick mode = PCIE_PORT_LINK_CTRL_LANES_1; 7666a2b914cSpatrick width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1; 7676a2b914cSpatrick break; 7686a2b914cSpatrick case 2: 7696a2b914cSpatrick mode = PCIE_PORT_LINK_CTRL_LANES_2; 7706a2b914cSpatrick width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2; 7716a2b914cSpatrick break; 7726a2b914cSpatrick case 4: 7736a2b914cSpatrick mode = PCIE_PORT_LINK_CTRL_LANES_4; 7746a2b914cSpatrick width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4; 7756a2b914cSpatrick break; 7766a2b914cSpatrick case 8: 7776a2b914cSpatrick mode = PCIE_PORT_LINK_CTRL_LANES_8; 7786a2b914cSpatrick width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8; 7796a2b914cSpatrick break; 7806a2b914cSpatrick default: 7816a2b914cSpatrick printf("%s: %d lanes not supported\n", __func__, lanes); 7826a2b914cSpatrick return; 7836a2b914cSpatrick } 7846a2b914cSpatrick 7856a2b914cSpatrick reg = HREAD4(sc, PCIE_PORT_LINK_CTRL); 7866a2b914cSpatrick reg &= ~PCIE_PORT_LINK_CTRL_LANES_MASK; 7876a2b914cSpatrick reg |= mode; 7886a2b914cSpatrick HWRITE4(sc, PCIE_PORT_LINK_CTRL, reg); 7896a2b914cSpatrick 7906a2b914cSpatrick reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 7916a2b914cSpatrick reg &= ~PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK; 7926a2b914cSpatrick reg |= width; 7936a2b914cSpatrick HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 7946a2b914cSpatrick 7956a2b914cSpatrick reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 7966a2b914cSpatrick reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE; 7976a2b914cSpatrick HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 7986a2b914cSpatrick } 7996a2b914cSpatrick 800c3f9cac9Spatrick int 8019a76443bSkettenis dwpcie_msi_intr(struct dwpcie_softc *sc, int idx) 802d5dfbc11Skettenis { 803d5dfbc11Skettenis struct dwpcie_msi *dm; 804d5dfbc11Skettenis uint32_t status; 805d5dfbc11Skettenis int vec, s; 806d5dfbc11Skettenis 8079a76443bSkettenis status = HREAD4(sc, PCIE_MSI_INTR_STATUS(idx)); 808d5dfbc11Skettenis if (status == 0) 809d5dfbc11Skettenis return 0; 810d5dfbc11Skettenis 8119a76443bSkettenis HWRITE4(sc, PCIE_MSI_INTR_STATUS(idx), status); 812d5dfbc11Skettenis while (status) { 813d5dfbc11Skettenis vec = ffs(status) - 1; 814d5dfbc11Skettenis status &= ~(1U << vec); 815d5dfbc11Skettenis 8169a76443bSkettenis dm = &sc->sc_msi[idx * 32 + vec]; 817d5dfbc11Skettenis if (dm->dm_func == NULL) 818d5dfbc11Skettenis continue; 819d5dfbc11Skettenis 820d5dfbc11Skettenis if ((dm->dm_flags & IPL_MPSAFE) == 0) 821d5dfbc11Skettenis KERNEL_LOCK(); 822d5dfbc11Skettenis s = splraise(dm->dm_ipl); 823d5dfbc11Skettenis if (dm->dm_func(dm->dm_arg)) 824d5dfbc11Skettenis dm->dm_count.ec_count++; 825d5dfbc11Skettenis splx(s); 826d5dfbc11Skettenis if ((dm->dm_flags & IPL_MPSAFE) == 0) 827d5dfbc11Skettenis KERNEL_UNLOCK(); 828d5dfbc11Skettenis } 829d5dfbc11Skettenis 830d5dfbc11Skettenis return 1; 831d5dfbc11Skettenis } 832d5dfbc11Skettenis 833d5dfbc11Skettenis int 8349a76443bSkettenis dwpcie_msi0_intr(void *arg) 8359a76443bSkettenis { 8369a76443bSkettenis return dwpcie_msi_intr(arg, 0); 8379a76443bSkettenis } 8389a76443bSkettenis 8399a76443bSkettenis int 8409a76443bSkettenis dwpcie_msi1_intr(void *arg) 8419a76443bSkettenis { 8429a76443bSkettenis return dwpcie_msi_intr(arg, 1); 8439a76443bSkettenis } 8449a76443bSkettenis 8459a76443bSkettenis int 846d5dfbc11Skettenis dwpcie_msi_init(struct dwpcie_softc *sc) 847d5dfbc11Skettenis { 848d5dfbc11Skettenis bus_dma_segment_t seg; 849d5dfbc11Skettenis bus_dmamap_t map; 850d5dfbc11Skettenis uint64_t addr; 851d5dfbc11Skettenis int error, rseg; 8529a76443bSkettenis int idx; 853d5dfbc11Skettenis 854d5dfbc11Skettenis /* 855d5dfbc11Skettenis * Allocate some DMA memory such that we have a "safe" target 856d5dfbc11Skettenis * address for MSIs. 857d5dfbc11Skettenis */ 858d5dfbc11Skettenis error = bus_dmamem_alloc(sc->sc_dmat, sizeof(uint32_t), 859d5dfbc11Skettenis sizeof(uint32_t), 0, &seg, 1, &rseg, BUS_DMA_WAITOK); 860d5dfbc11Skettenis if (error) 861d5dfbc11Skettenis return error; 862d5dfbc11Skettenis 863d5dfbc11Skettenis /* 864d5dfbc11Skettenis * Translate the CPU address into a bus address that we can 865d5dfbc11Skettenis * program into the hardware. 866d5dfbc11Skettenis */ 867d5dfbc11Skettenis error = bus_dmamap_create(sc->sc_dmat, sizeof(uint32_t), 1, 868d5dfbc11Skettenis sizeof(uint32_t), 0, BUS_DMA_WAITOK, &map); 869d5dfbc11Skettenis if (error) { 870d5dfbc11Skettenis bus_dmamem_free(sc->sc_dmat, &seg, 1); 871d5dfbc11Skettenis return error; 872d5dfbc11Skettenis } 873d5dfbc11Skettenis error = bus_dmamap_load_raw(sc->sc_dmat, map, &seg, 1, 874d5dfbc11Skettenis sizeof(uint32_t), BUS_DMA_WAITOK); 875d5dfbc11Skettenis if (error) { 876d5dfbc11Skettenis bus_dmamap_destroy(sc->sc_dmat, map); 877d5dfbc11Skettenis bus_dmamem_free(sc->sc_dmat, &seg, 1); 878d5dfbc11Skettenis return error; 879d5dfbc11Skettenis } 880d5dfbc11Skettenis 881d5dfbc11Skettenis addr = map->dm_segs[0].ds_addr; 882d5dfbc11Skettenis HWRITE4(sc, PCIE_MSI_ADDR_LO, addr); 883d5dfbc11Skettenis HWRITE4(sc, PCIE_MSI_ADDR_HI, addr >> 32); 884d5dfbc11Skettenis 885d5dfbc11Skettenis bus_dmamap_unload(sc->sc_dmat, map); 886d5dfbc11Skettenis bus_dmamap_destroy(sc->sc_dmat, map); 887d5dfbc11Skettenis 8889a76443bSkettenis /* 8899a76443bSkettenis * See if the device tree indicates that the hardware supports 8909a76443bSkettenis * more than 32 vectors. Some hardware supports more than 64, 8919a76443bSkettenis * but 64 is good enough for now. 8929a76443bSkettenis */ 8939a76443bSkettenis idx = OF_getindex(sc->sc_node, "msi1", "interrupt-names"); 8949a76443bSkettenis if (idx == -1) 8959a76443bSkettenis sc->sc_num_msi = 32; 8969a76443bSkettenis else 8979a76443bSkettenis sc->sc_num_msi = 64; 8989a76443bSkettenis KASSERT(sc->sc_num_msi <= DWPCIE_MAX_MSI); 899d5dfbc11Skettenis 9009a76443bSkettenis /* Enable, mask and clear all MSIs. */ 9019a76443bSkettenis for (idx = 0; idx < sc->sc_num_msi / 32; idx++) { 9029a76443bSkettenis HWRITE4(sc, PCIE_MSI_INTR_ENABLE(idx), 0xffffffff); 9039a76443bSkettenis HWRITE4(sc, PCIE_MSI_INTR_MASK(idx), 0xffffffff); 9049a76443bSkettenis HWRITE4(sc, PCIE_MSI_INTR_STATUS(idx), 0xffffffff); 9059a76443bSkettenis } 9069a76443bSkettenis 9079a76443bSkettenis idx = OF_getindex(sc->sc_node, "msi0", "interrupt-names"); 9089a76443bSkettenis if (idx == -1) 9099a76443bSkettenis idx = 0; 9109a76443bSkettenis 9119a76443bSkettenis sc->sc_msi_ih[0] = fdt_intr_establish_idx(sc->sc_node, idx, 9129a76443bSkettenis IPL_BIO | IPL_MPSAFE, dwpcie_msi0_intr, sc, sc->sc_dev.dv_xname); 9139a76443bSkettenis if (sc->sc_msi_ih[0] == NULL) { 914d5dfbc11Skettenis bus_dmamem_free(sc->sc_dmat, &seg, 1); 915d5dfbc11Skettenis return EINVAL; 916d5dfbc11Skettenis } 917d5dfbc11Skettenis 9189a76443bSkettenis idx = OF_getindex(sc->sc_node, "msi1", "interrupt-names"); 9199a76443bSkettenis if (idx == -1) 9209a76443bSkettenis goto finish; 9219a76443bSkettenis 9229a76443bSkettenis sc->sc_msi_ih[1] = fdt_intr_establish_idx(sc->sc_node, idx, 9239a76443bSkettenis IPL_BIO | IPL_MPSAFE, dwpcie_msi1_intr, sc, sc->sc_dev.dv_xname); 9249a76443bSkettenis if (sc->sc_msi_ih[1] == NULL) 9259a76443bSkettenis sc->sc_num_msi = 32; 9269a76443bSkettenis 9279a76443bSkettenis finish: 928d5dfbc11Skettenis /* 929d5dfbc11Skettenis * Hold on to the DMA memory such that nobody can use it to 930d5dfbc11Skettenis * actually do DMA transfers. 931d5dfbc11Skettenis */ 932d5dfbc11Skettenis 933d5dfbc11Skettenis sc->sc_msi_addr = addr; 934d5dfbc11Skettenis return 0; 935d5dfbc11Skettenis } 936d5dfbc11Skettenis 937d5dfbc11Skettenis int 9384605d28eSkettenis dwpcie_armada8k_init(struct dwpcie_softc *sc) 9394605d28eSkettenis { 9404605d28eSkettenis uint32_t reg; 9416a2b914cSpatrick int timo; 9426a2b914cSpatrick 9436a2b914cSpatrick clock_enable_all(sc->sc_node); 9446a2b914cSpatrick 9456a2b914cSpatrick dwpcie_link_config(sc); 9464605d28eSkettenis 9474605d28eSkettenis if (!dwpcie_armada8k_link_up(sc)) { 9484605d28eSkettenis reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 9494605d28eSkettenis reg &= ~PCIE_GLOBAL_CTRL_APP_LTSSM_EN; 9504605d28eSkettenis HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 9514605d28eSkettenis } 9524605d28eSkettenis 953eae9bc5eSpatrick /* 954eae9bc5eSpatrick * Setup Requester-ID to Stream-ID mapping 955eae9bc5eSpatrick * XXX: TF-A is supposed to set this up, but doesn't! 956eae9bc5eSpatrick */ 957eae9bc5eSpatrick HWRITE4(sc, PCIE_STREAMID, PCIE_STREAMID_8040); 958eae9bc5eSpatrick 9594605d28eSkettenis /* Enable Root Complex mode. */ 9604605d28eSkettenis reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 9614605d28eSkettenis reg &= ~PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK; 9624605d28eSkettenis reg |= PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC; 9634605d28eSkettenis HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 9644605d28eSkettenis 9654605d28eSkettenis HWRITE4(sc, PCIE_ARCACHE_TRC, PCIE_ARCACHE_TRC_DEFAULT); 9664605d28eSkettenis HWRITE4(sc, PCIE_AWCACHE_TRC, PCIE_AWCACHE_TRC_DEFAULT); 9674605d28eSkettenis reg = HREAD4(sc, PCIE_ARUSER); 9684605d28eSkettenis reg &= ~PCIE_AXUSER_DOMAIN_MASK; 9694605d28eSkettenis reg |= PCIE_AXUSER_DOMAIN_OUTER_SHARABLE; 9704605d28eSkettenis HWRITE4(sc, PCIE_ARUSER, reg); 9714605d28eSkettenis reg = HREAD4(sc, PCIE_AWUSER); 9724605d28eSkettenis reg &= ~PCIE_AXUSER_DOMAIN_MASK; 9734605d28eSkettenis reg |= PCIE_AXUSER_DOMAIN_OUTER_SHARABLE; 9744605d28eSkettenis HWRITE4(sc, PCIE_AWUSER, reg); 9754605d28eSkettenis 9764605d28eSkettenis if (!dwpcie_armada8k_link_up(sc)) { 9774605d28eSkettenis reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 9784605d28eSkettenis reg |= PCIE_GLOBAL_CTRL_APP_LTSSM_EN; 9794605d28eSkettenis HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 9804605d28eSkettenis } 9814605d28eSkettenis 9824605d28eSkettenis for (timo = 40; timo > 0; timo--) { 9834605d28eSkettenis if (dwpcie_armada8k_link_up(sc)) 9844605d28eSkettenis break; 9854605d28eSkettenis delay(1000); 9864605d28eSkettenis } 987c3f9cac9Spatrick if (timo == 0) 988c3f9cac9Spatrick return ETIMEDOUT; 989f2c2f061Skettenis 99070e69ae2Spatrick sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_AUDIO | IPL_MPSAFE, 991f2c2f061Skettenis dwpcie_armada8k_intr, sc, sc->sc_dev.dv_xname); 992f2c2f061Skettenis 993f2c2f061Skettenis /* Unmask INTx interrupts. */ 994f2c2f061Skettenis HWRITE4(sc, PCIE_GLOBAL_INT_MASK, 995f2c2f061Skettenis PCIE_GLOBAL_INT_MASK_INT_A | PCIE_GLOBAL_INT_MASK_INT_B | 996f2c2f061Skettenis PCIE_GLOBAL_INT_MASK_INT_C | PCIE_GLOBAL_INT_MASK_INT_D); 997c3f9cac9Spatrick 998c3f9cac9Spatrick return 0; 9994605d28eSkettenis } 10004605d28eSkettenis 10014605d28eSkettenis int 10024605d28eSkettenis dwpcie_armada8k_link_up(struct dwpcie_softc *sc) 10034605d28eSkettenis { 10044605d28eSkettenis uint32_t reg, mask; 10054605d28eSkettenis 10064605d28eSkettenis mask = PCIE_GLOBAL_STATUS_RDLH_LINK_UP; 10074605d28eSkettenis mask |= PCIE_GLOBAL_STATUS_PHY_LINK_UP; 10084605d28eSkettenis reg = HREAD4(sc, PCIE_GLOBAL_STATUS); 10094605d28eSkettenis return ((reg & mask) == mask); 10104605d28eSkettenis } 10114605d28eSkettenis 1012f2c2f061Skettenis int 1013f2c2f061Skettenis dwpcie_armada8k_intr(void *arg) 1014f2c2f061Skettenis { 1015f2c2f061Skettenis struct dwpcie_softc *sc = arg; 1016f2c2f061Skettenis uint32_t cause; 1017f2c2f061Skettenis 1018f2c2f061Skettenis /* Acknowledge interrupts. */ 1019f2c2f061Skettenis cause = HREAD4(sc, PCIE_GLOBAL_INT_CAUSE); 1020f2c2f061Skettenis HWRITE4(sc, PCIE_GLOBAL_INT_CAUSE, cause); 1021f2c2f061Skettenis 1022f2c2f061Skettenis /* INTx interrupt, so not really ours. */ 1023f2c2f061Skettenis return 0; 1024f2c2f061Skettenis } 1025f2c2f061Skettenis 1026c3f9cac9Spatrick int 1027c244e331Skettenis dwpcie_g12a_init(struct dwpcie_softc *sc) 1028c244e331Skettenis { 1029c244e331Skettenis uint32_t *reset_gpio; 1030c244e331Skettenis ssize_t reset_gpiolen; 1031c244e331Skettenis uint32_t reg; 1032d5dfbc11Skettenis int error, timo; 1033c244e331Skettenis 1034c244e331Skettenis reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpios"); 1035c244e331Skettenis if (reset_gpiolen <= 0) 1036c244e331Skettenis return ENXIO; 1037c244e331Skettenis 1038c244e331Skettenis if (bus_space_map(sc->sc_iot, sc->sc_glue_base, 1039c244e331Skettenis sc->sc_glue_size, 0, &sc->sc_glue_ioh)) 1040c244e331Skettenis return ENOMEM; 1041c244e331Skettenis 1042c244e331Skettenis power_domain_enable(sc->sc_node); 1043c244e331Skettenis 1044c244e331Skettenis phy_enable(sc->sc_node, "pcie"); 1045c244e331Skettenis 1046c244e331Skettenis reset_assert_all(sc->sc_node); 1047c244e331Skettenis delay(500); 1048c244e331Skettenis reset_deassert_all(sc->sc_node); 1049c244e331Skettenis delay(500); 1050c244e331Skettenis 1051c244e331Skettenis clock_set_frequency(sc->sc_node, "port", 100000000UL); 1052c244e331Skettenis clock_enable_all(sc->sc_node); 1053c244e331Skettenis 1054c244e331Skettenis reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); 1055c244e331Skettenis OF_getpropintarray(sc->sc_node, "reset-gpios", reset_gpio, 1056c244e331Skettenis reset_gpiolen); 1057c244e331Skettenis gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); 1058c244e331Skettenis gpio_controller_set_pin(reset_gpio, 1); 1059c244e331Skettenis 1060c244e331Skettenis dwpcie_link_config(sc); 1061c244e331Skettenis 1062c244e331Skettenis reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CFG0); 1063c244e331Skettenis reg |= PCIE_CFG0_APP_LTSSM_EN; 1064c244e331Skettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CFG0, reg); 1065c244e331Skettenis 1066c244e331Skettenis gpio_controller_set_pin(reset_gpio, 1); 1067c244e331Skettenis delay(500); 1068c244e331Skettenis gpio_controller_set_pin(reset_gpio, 0); 1069c244e331Skettenis 1070c244e331Skettenis free(reset_gpio, M_TEMP, reset_gpiolen); 1071c244e331Skettenis 1072c244e331Skettenis for (timo = 40; timo > 0; timo--) { 1073c244e331Skettenis if (dwpcie_g12a_link_up(sc)) 1074c244e331Skettenis break; 1075c244e331Skettenis delay(1000); 1076c244e331Skettenis } 1077c244e331Skettenis if (timo == 0) 1078c244e331Skettenis return ETIMEDOUT; 1079c244e331Skettenis 1080d5dfbc11Skettenis error = dwpcie_msi_init(sc); 1081d5dfbc11Skettenis if (error) 1082d5dfbc11Skettenis return error; 1083d5dfbc11Skettenis 1084c244e331Skettenis return 0; 1085c244e331Skettenis } 1086c244e331Skettenis 1087c244e331Skettenis int 1088c244e331Skettenis dwpcie_g12a_link_up(struct dwpcie_softc *sc) 1089c244e331Skettenis { 1090c244e331Skettenis uint32_t reg; 1091c244e331Skettenis 1092c244e331Skettenis reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_STATUS12); 1093c244e331Skettenis if ((reg & PCIE_STATUS12_SMLH_LINK_UP) && 1094c244e331Skettenis (reg & PCIE_STATUS12_RDLH_LINK_UP) && 1095c244e331Skettenis (reg & PCIE_STATUS12_LTSSM_MASK) == PCIE_STATUS12_LTSSM_UP) 1096c244e331Skettenis return 1; 1097c244e331Skettenis return 0; 1098c244e331Skettenis } 1099c244e331Skettenis 1100c244e331Skettenis int 11016a2b914cSpatrick dwpcie_imx8mq_init(struct dwpcie_softc *sc) 11027659d2d7Skettenis { 11036a2b914cSpatrick uint32_t *clkreq_gpio, *disable_gpio, *reset_gpio; 11046a2b914cSpatrick ssize_t clkreq_gpiolen, disable_gpiolen, reset_gpiolen; 11051ad6abbaSpatrick struct regmap *anatop, *gpr, *phy; 11066a2b914cSpatrick uint32_t off, reg; 1107c3f9cac9Spatrick int error, timo; 11086a2b914cSpatrick 11091ad6abbaSpatrick if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie")) { 11101ad6abbaSpatrick anatop = regmap_bycompatible("fsl,imx8mm-anatop"); 11111ad6abbaSpatrick gpr = regmap_bycompatible("fsl,imx8mm-iomuxc-gpr"); 11121ad6abbaSpatrick phy = regmap_bycompatible("fsl,imx7d-pcie-phy"); 11131ad6abbaSpatrick KASSERT(phy != NULL); 11141ad6abbaSpatrick } else { 11156a2b914cSpatrick anatop = regmap_bycompatible("fsl,imx8mq-anatop"); 11166a2b914cSpatrick gpr = regmap_bycompatible("fsl,imx8mq-iomuxc-gpr"); 11171ad6abbaSpatrick } 11186a2b914cSpatrick KASSERT(anatop != NULL); 11196a2b914cSpatrick KASSERT(gpr != NULL); 11206a2b914cSpatrick 11216a2b914cSpatrick clkreq_gpiolen = OF_getproplen(sc->sc_node, "clkreq-gpio"); 11226a2b914cSpatrick disable_gpiolen = OF_getproplen(sc->sc_node, "disable-gpio"); 11236a2b914cSpatrick reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpio"); 11246a2b914cSpatrick 11256a2b914cSpatrick if (clkreq_gpiolen > 0) { 11266a2b914cSpatrick clkreq_gpio = malloc(clkreq_gpiolen, M_TEMP, M_WAITOK); 11276a2b914cSpatrick OF_getpropintarray(sc->sc_node, "clkreq-gpio", clkreq_gpio, 11286a2b914cSpatrick clkreq_gpiolen); 11296a2b914cSpatrick gpio_controller_config_pin(clkreq_gpio, GPIO_CONFIG_OUTPUT); 11306a2b914cSpatrick gpio_controller_set_pin(clkreq_gpio, 1); 11316a2b914cSpatrick } 11326a2b914cSpatrick 11336a2b914cSpatrick if (disable_gpiolen > 0) { 11346a2b914cSpatrick disable_gpio = malloc(disable_gpiolen, M_TEMP, M_WAITOK); 11356a2b914cSpatrick OF_getpropintarray(sc->sc_node, "disable-gpio", disable_gpio, 11366a2b914cSpatrick disable_gpiolen); 11376a2b914cSpatrick gpio_controller_config_pin(disable_gpio, GPIO_CONFIG_OUTPUT); 11386a2b914cSpatrick gpio_controller_set_pin(disable_gpio, 0); 11396a2b914cSpatrick } 11406a2b914cSpatrick 11416a2b914cSpatrick if (reset_gpiolen > 0) { 11426a2b914cSpatrick reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); 11436a2b914cSpatrick OF_getpropintarray(sc->sc_node, "reset-gpio", reset_gpio, 11446a2b914cSpatrick reset_gpiolen); 11456a2b914cSpatrick gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); 11466a2b914cSpatrick gpio_controller_set_pin(reset_gpio, 1); 11476a2b914cSpatrick } 11486a2b914cSpatrick 11496a2b914cSpatrick power_domain_enable(sc->sc_node); 11506a2b914cSpatrick reset_assert(sc->sc_node, "pciephy"); 11516a2b914cSpatrick reset_assert(sc->sc_node, "apps"); 11526a2b914cSpatrick 11536a2b914cSpatrick reg = regmap_read_4(gpr, IOMUXC_GPR12); 11546a2b914cSpatrick if (OF_getpropint(sc->sc_node, "ctrl-id", 0) == 0) { 11556a2b914cSpatrick off = IOMUXC_GPR14; 11566a2b914cSpatrick reg &= ~IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK; 11576a2b914cSpatrick reg |= IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC; 11586a2b914cSpatrick } else { 11596a2b914cSpatrick off = IOMUXC_GPR16; 11606a2b914cSpatrick reg &= ~IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK; 11616a2b914cSpatrick reg |= IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC; 11626a2b914cSpatrick } 11636a2b914cSpatrick regmap_write_4(gpr, IOMUXC_GPR12, reg); 11646a2b914cSpatrick 11651ad6abbaSpatrick if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie")) { 11661ad6abbaSpatrick if (OF_getproplen(sc->sc_node, "ext_osc") == 0 || 11671ad6abbaSpatrick OF_getpropint(sc->sc_node, "ext_osc", 0)) { 11681ad6abbaSpatrick reg = regmap_read_4(gpr, off); 11691ad6abbaSpatrick reg &= ~(IMX8MQ_GPR_PCIE_REF_USE_PAD | 11701ad6abbaSpatrick IMX8MM_GPR_PCIE_SSC_EN | 11711ad6abbaSpatrick IMX8MM_GPR_PCIE_POWER_OFF | 11721ad6abbaSpatrick IMX8MM_GPR_PCIE_REF_CLK_MASK); 11731ad6abbaSpatrick reg |= (IMX8MM_GPR_PCIE_AUX_EN | 11741ad6abbaSpatrick IMX8MM_GPR_PCIE_REF_CLK_EXT); 11751ad6abbaSpatrick regmap_write_4(gpr, off, reg); 11761ad6abbaSpatrick delay(100); 11771ad6abbaSpatrick reg = regmap_read_4(gpr, off); 11781ad6abbaSpatrick reg |= IMX8MM_GPR_PCIE_CMN_RST; 11791ad6abbaSpatrick regmap_write_4(gpr, off, reg); 11801ad6abbaSpatrick delay(200); 11811ad6abbaSpatrick } else { 11821ad6abbaSpatrick reg = regmap_read_4(gpr, off); 11831ad6abbaSpatrick reg &= ~(IMX8MQ_GPR_PCIE_REF_USE_PAD | 11841ad6abbaSpatrick IMX8MM_GPR_PCIE_SSC_EN | 11851ad6abbaSpatrick IMX8MM_GPR_PCIE_POWER_OFF | 11861ad6abbaSpatrick IMX8MM_GPR_PCIE_REF_CLK_MASK); 11871ad6abbaSpatrick reg |= (IMX8MM_GPR_PCIE_AUX_EN | 11881ad6abbaSpatrick IMX8MM_GPR_PCIE_REF_CLK_PLL); 11891ad6abbaSpatrick regmap_write_4(gpr, off, reg); 11901ad6abbaSpatrick delay(100); 11911ad6abbaSpatrick regmap_write_4(phy, IMX8MM_PCIE_PHY_CMN_REG62, 11921ad6abbaSpatrick IMX8MM_PCIE_PHY_CMN_REG62_PLL_CLK_OUT); 11931ad6abbaSpatrick regmap_write_4(phy, IMX8MM_PCIE_PHY_CMN_REG64, 11941ad6abbaSpatrick IMX8MM_PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM); 11951ad6abbaSpatrick reg = regmap_read_4(gpr, off); 11961ad6abbaSpatrick reg |= IMX8MM_GPR_PCIE_CMN_RST; 11971ad6abbaSpatrick regmap_write_4(gpr, off, reg); 11981ad6abbaSpatrick delay(200); 11991ad6abbaSpatrick regmap_write_4(phy, IMX8MM_PCIE_PHY_TRSV_REG5, 12001ad6abbaSpatrick IMX8MM_PCIE_PHY_TRSV_REG5_GEN1_DEEMP); 12011ad6abbaSpatrick regmap_write_4(phy, IMX8MM_PCIE_PHY_TRSV_REG6, 12021ad6abbaSpatrick IMX8MM_PCIE_PHY_TRSV_REG6_GEN2_DEEMP); 12031ad6abbaSpatrick } 12041ad6abbaSpatrick } else { 1205ddff7592Spatrick if (OF_getproplen(sc->sc_node, "ext_osc") == 0 || 1206ddff7592Spatrick OF_getpropint(sc->sc_node, "ext_osc", 0)) { 12076a2b914cSpatrick reg = regmap_read_4(gpr, off); 12086a2b914cSpatrick reg |= IMX8MQ_GPR_PCIE_REF_USE_PAD; 12096a2b914cSpatrick regmap_write_4(gpr, off, reg); 12106a2b914cSpatrick } else { 12116a2b914cSpatrick reg = regmap_read_4(gpr, off); 12126a2b914cSpatrick reg &= ~IMX8MQ_GPR_PCIE_REF_USE_PAD; 12136a2b914cSpatrick regmap_write_4(gpr, off, reg); 12146a2b914cSpatrick 12156a2b914cSpatrick regmap_write_4(anatop, ANATOP_PLLOUT_CTL, 12161ad6abbaSpatrick ANATOP_PLLOUT_CTL_CKE | 12171ad6abbaSpatrick ANATOP_PLLOUT_CTL_SEL_SYSPLL1); 12186a2b914cSpatrick regmap_write_4(anatop, ANATOP_PLLOUT_DIV, 12196a2b914cSpatrick ANATOP_PLLOUT_DIV_SYSPLL1); 12206a2b914cSpatrick } 12211ad6abbaSpatrick } 12226a2b914cSpatrick 12236a2b914cSpatrick clock_enable(sc->sc_node, "pcie_phy"); 12246a2b914cSpatrick clock_enable(sc->sc_node, "pcie_bus"); 12256a2b914cSpatrick clock_enable(sc->sc_node, "pcie"); 1226e9c4ad80Spatrick clock_enable(sc->sc_node, "pcie_aux"); 12276a2b914cSpatrick 12286a2b914cSpatrick /* Allow clocks to stabilize. */ 12296a2b914cSpatrick delay(200); 12306a2b914cSpatrick 12316a2b914cSpatrick if (reset_gpiolen > 0) { 12326a2b914cSpatrick gpio_controller_set_pin(reset_gpio, 1); 1233915a5ad8Spatrick delay(100000); 12346a2b914cSpatrick gpio_controller_set_pin(reset_gpio, 0); 12356a2b914cSpatrick } 12366a2b914cSpatrick 12376a2b914cSpatrick reset_deassert(sc->sc_node, "pciephy"); 12386a2b914cSpatrick 12391ad6abbaSpatrick if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie")) { 12401ad6abbaSpatrick for (timo = 2000; timo > 0; timo--) { 12411ad6abbaSpatrick if (regmap_read_4(phy, IMX8MM_PCIE_PHY_CMN_REG75) == 12421ad6abbaSpatrick IMX8MM_PCIE_PHY_CMN_REG75_PLL_DONE) 12431ad6abbaSpatrick break; 12441ad6abbaSpatrick delay(10); 12451ad6abbaSpatrick } 1246c3f9cac9Spatrick if (timo == 0) { 1247c3f9cac9Spatrick error = ETIMEDOUT; 1248c3f9cac9Spatrick goto err; 1249c3f9cac9Spatrick } 12501ad6abbaSpatrick } 12511ad6abbaSpatrick 12526a2b914cSpatrick reg = HREAD4(sc, 0x100000 + PCIE_RC_LCR); 12536a2b914cSpatrick reg &= ~PCIE_RC_LCR_L1EL_MASK; 12546a2b914cSpatrick reg |= PCIE_RC_LCR_L1EL_64US; 12556a2b914cSpatrick HWRITE4(sc, 0x100000 + PCIE_RC_LCR, reg); 12566a2b914cSpatrick 12576a2b914cSpatrick dwpcie_link_config(sc); 12586a2b914cSpatrick 12596a2b914cSpatrick reg = HREAD4(sc, PCIE_RC_LCR); 12606a2b914cSpatrick reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; 12616a2b914cSpatrick reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; 12626a2b914cSpatrick HWRITE4(sc, PCIE_RC_LCR, reg); 12636a2b914cSpatrick 12646a2b914cSpatrick reset_deassert(sc->sc_node, "apps"); 12656a2b914cSpatrick 12666a2b914cSpatrick for (timo = 20000; timo > 0; timo--) { 12676a2b914cSpatrick if (dwpcie_link_up(sc)) 12686a2b914cSpatrick break; 12696a2b914cSpatrick delay(10); 12706a2b914cSpatrick } 1271c3f9cac9Spatrick if (timo == 0) { 1272c3f9cac9Spatrick error = ETIMEDOUT; 1273c3f9cac9Spatrick goto err; 1274c3f9cac9Spatrick } 12756a2b914cSpatrick 12766a2b914cSpatrick if (OF_getpropint(sc->sc_node, "fsl,max-link-speed", 1) >= 2) { 12776a2b914cSpatrick reg = HREAD4(sc, PCIE_RC_LCR); 12786a2b914cSpatrick reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; 12796a2b914cSpatrick reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; 12806a2b914cSpatrick HWRITE4(sc, PCIE_RC_LCR, reg); 12816a2b914cSpatrick 12826a2b914cSpatrick reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 12836a2b914cSpatrick reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE; 12846a2b914cSpatrick HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 12856a2b914cSpatrick 12866a2b914cSpatrick for (timo = 20000; timo > 0; timo--) { 12876a2b914cSpatrick if (dwpcie_link_up(sc)) 12886a2b914cSpatrick break; 12896a2b914cSpatrick delay(10); 12906a2b914cSpatrick } 1291c3f9cac9Spatrick if (timo == 0) { 1292c3f9cac9Spatrick error = ETIMEDOUT; 1293c3f9cac9Spatrick goto err; 1294c3f9cac9Spatrick } 12956a2b914cSpatrick } 12966a2b914cSpatrick 12976a2b914cSpatrick sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_AUDIO | IPL_MPSAFE, 12986a2b914cSpatrick dwpcie_imx8mq_intr, sc, sc->sc_dev.dv_xname); 12996a2b914cSpatrick 13006a2b914cSpatrick /* Unmask INTx interrupts. */ 13016a2b914cSpatrick HWRITE4(sc, PCIE_GLOBAL_INT_MASK, 13026a2b914cSpatrick PCIE_GLOBAL_INT_MASK_INT_A | PCIE_GLOBAL_INT_MASK_INT_B | 13036a2b914cSpatrick PCIE_GLOBAL_INT_MASK_INT_C | PCIE_GLOBAL_INT_MASK_INT_D); 13046a2b914cSpatrick 1305c3f9cac9Spatrick error = 0; 1306c3f9cac9Spatrick err: 13076a2b914cSpatrick if (clkreq_gpiolen > 0) 13086a2b914cSpatrick free(clkreq_gpio, M_TEMP, clkreq_gpiolen); 13096a2b914cSpatrick if (disable_gpiolen > 0) 13106a2b914cSpatrick free(disable_gpio, M_TEMP, disable_gpiolen); 13116a2b914cSpatrick if (reset_gpiolen > 0) 13126a2b914cSpatrick free(reset_gpio, M_TEMP, reset_gpiolen); 1313c3f9cac9Spatrick return error; 13146a2b914cSpatrick } 13156a2b914cSpatrick 13166a2b914cSpatrick int 13176a2b914cSpatrick dwpcie_imx8mq_intr(void *arg) 13186a2b914cSpatrick { 13196a2b914cSpatrick struct dwpcie_softc *sc = arg; 13206a2b914cSpatrick uint32_t cause; 13216a2b914cSpatrick 13226a2b914cSpatrick /* Acknowledge interrupts. */ 13236a2b914cSpatrick cause = HREAD4(sc, PCIE_GLOBAL_INT_CAUSE); 13246a2b914cSpatrick HWRITE4(sc, PCIE_GLOBAL_INT_CAUSE, cause); 13256a2b914cSpatrick 13266a2b914cSpatrick /* INTx interrupt, so not really ours. */ 13276a2b914cSpatrick return 0; 13286a2b914cSpatrick } 13296a2b914cSpatrick 1330d2397242Skettenis int 1331d2397242Skettenis dwpcie_fu740_init(struct dwpcie_softc *sc) 1332d2397242Skettenis { 1333d2397242Skettenis sc->sc_num_viewport = 8; 1334d2397242Skettenis 1335d2397242Skettenis return 0; 1336d2397242Skettenis } 1337d2397242Skettenis 13385f3e3118Skettenis int 1339f98fd054Skettenis dwpcie_rk3568_link_up(struct dwpcie_softc *sc) 1340f98fd054Skettenis { 1341f98fd054Skettenis uint32_t reg; 1342f98fd054Skettenis 1343f98fd054Skettenis reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, 1344f98fd054Skettenis PCIE_CLIENT_LTSSM_STATUS); 1345f98fd054Skettenis if ((reg & PCIE_CLIENT_SMLH_LINK_UP) && 1346f98fd054Skettenis (reg & PCIE_CLIENT_RDLH_LINK_UP) && 1347f98fd054Skettenis (reg & PCIE_CLIENT_LTSSM_MASK) == PCIE_CLIENT_LTSSM_UP) 1348f98fd054Skettenis return 1; 1349f98fd054Skettenis return 0; 1350f98fd054Skettenis } 1351f98fd054Skettenis 1352f98fd054Skettenis int 13535f3e3118Skettenis dwpcie_rk3568_init(struct dwpcie_softc *sc) 13545f3e3118Skettenis { 13551140f82aSkettenis uint32_t *reset_gpio; 13561140f82aSkettenis ssize_t reset_gpiolen; 13575f800b9bSkettenis int error, idx, node; 13585f800b9bSkettenis int pin, timo; 1359f98fd054Skettenis 1360f98fd054Skettenis sc->sc_num_viewport = 8; 1361f98fd054Skettenis 1362f98fd054Skettenis if (bus_space_map(sc->sc_iot, sc->sc_glue_base, 1363f98fd054Skettenis sc->sc_glue_size, 0, &sc->sc_glue_ioh)) 1364f98fd054Skettenis return ENOMEM; 13651140f82aSkettenis 13661140f82aSkettenis reset_assert_all(sc->sc_node); 1367f98fd054Skettenis /* Power must be enabled before initializing the PHY. */ 13681140f82aSkettenis regulator_enable(OF_getpropint(sc->sc_node, "vpcie3v3-supply", 0)); 13691140f82aSkettenis phy_enable(sc->sc_node, "pcie-phy"); 13701140f82aSkettenis reset_deassert_all(sc->sc_node); 13711140f82aSkettenis 13721140f82aSkettenis clock_enable_all(sc->sc_node); 13731140f82aSkettenis 1374f98fd054Skettenis if (dwpcie_rk3568_link_up(sc)) 1375f98fd054Skettenis return 0; 1376f98fd054Skettenis 13771140f82aSkettenis reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpios"); 13781140f82aSkettenis if (reset_gpiolen > 0) { 13791140f82aSkettenis reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); 13801140f82aSkettenis OF_getpropintarray(sc->sc_node, "reset-gpios", reset_gpio, 13811140f82aSkettenis reset_gpiolen); 13821140f82aSkettenis gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); 13831140f82aSkettenis gpio_controller_set_pin(reset_gpio, 1); 13841140f82aSkettenis } 13851140f82aSkettenis 1386f98fd054Skettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 1387f98fd054Skettenis PCIE_CLIENT_HOT_RESET_CTRL, PCIE_CLIENT_APP_LTSSM_ENABLE_ENHANCE); 1388f98fd054Skettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 1389f98fd054Skettenis PCIE_CLIENT_GENERAL_CON, PCIE_CLIENT_DEV_TYPE_RC); 13905f3e3118Skettenis 1391f98fd054Skettenis /* Assert PERST#. */ 1392f98fd054Skettenis if (reset_gpiolen > 0) 1393f98fd054Skettenis gpio_controller_set_pin(reset_gpio, 0); 1394f98fd054Skettenis 1395a14a93a7Skettenis dwpcie_link_config(sc); 1396a14a93a7Skettenis 1397f98fd054Skettenis /* Enable LTSSM. */ 1398f98fd054Skettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CLIENT_GENERAL_CON, 1399f98fd054Skettenis PCIE_CLIENT_LINK_REQ_RST_GRT | PCIE_CLIENT_APP_LTSSM_ENABLE); 1400f98fd054Skettenis 1401f98fd054Skettenis /* 1402f98fd054Skettenis * PERST# must remain asserted for at least 100us after the 1403f98fd054Skettenis * reference clock becomes stable. But also has to remain 1404f98fd054Skettenis * active at least 100ms after power up. Since we may have 1405f98fd054Skettenis * just powered on the device, play it safe and use 100ms. 1406f98fd054Skettenis */ 1407f98fd054Skettenis delay(100000); 1408f98fd054Skettenis 1409f98fd054Skettenis /* Deassert PERST#. */ 1410f98fd054Skettenis if (reset_gpiolen > 0) 1411f98fd054Skettenis gpio_controller_set_pin(reset_gpio, 1); 1412f98fd054Skettenis 1413f98fd054Skettenis /* Wait for the link to come up. */ 1414f98fd054Skettenis for (timo = 100; timo > 0; timo--) { 1415f98fd054Skettenis if (dwpcie_rk3568_link_up(sc)) 1416f98fd054Skettenis break; 1417f98fd054Skettenis delay(10000); 1418f98fd054Skettenis } 1419f98fd054Skettenis if (timo == 0) { 1420f98fd054Skettenis error = ETIMEDOUT; 1421f98fd054Skettenis goto err; 1422f98fd054Skettenis } 1423f98fd054Skettenis 14245f800b9bSkettenis node = OF_getnodebyname(sc->sc_node, "legacy-interrupt-controller"); 14255f800b9bSkettenis idx = OF_getindex(sc->sc_node, "legacy", "interrupt-names"); 14265f800b9bSkettenis if (node && idx != -1) { 14275f800b9bSkettenis sc->sc_ih = fdt_intr_establish_idx(sc->sc_node, idx, 14285f800b9bSkettenis IPL_BIO | IPL_MPSAFE, dwpcie_rk3568_intr, sc, 14295f800b9bSkettenis sc->sc_dev.dv_xname); 14305f800b9bSkettenis } 14315f800b9bSkettenis 14325f800b9bSkettenis if (sc->sc_ih) { 14335f800b9bSkettenis for (pin = 0; pin < nitems(sc->sc_intx); pin++) 14345f800b9bSkettenis TAILQ_INIT(&sc->sc_intx[pin]); 14355f800b9bSkettenis sc->sc_ic.ic_node = node; 14365f800b9bSkettenis sc->sc_ic.ic_cookie = sc; 14375f800b9bSkettenis sc->sc_ic.ic_establish = dwpcie_rk3568_intr_establish; 14385f800b9bSkettenis sc->sc_ic.ic_disestablish = dwpcie_rk3568_intr_disestablish; 14395f800b9bSkettenis sc->sc_ic.ic_barrier = dwpcie_rk3568_intr_barrier; 14405f800b9bSkettenis fdt_intr_register(&sc->sc_ic); 14415f800b9bSkettenis } 14425f800b9bSkettenis 1443f98fd054Skettenis error = 0; 1444f98fd054Skettenis err: 1445f98fd054Skettenis if (reset_gpiolen > 0) 1446f98fd054Skettenis free(reset_gpio, M_TEMP, reset_gpiolen); 1447f98fd054Skettenis 1448f98fd054Skettenis return error; 14495f3e3118Skettenis } 14505f3e3118Skettenis 1451a848a3cbSpatrick int 14525f800b9bSkettenis dwpcie_rk3568_intr(void *arg) 14535f800b9bSkettenis { 14545f800b9bSkettenis struct dwpcie_softc *sc = arg; 14555f800b9bSkettenis struct dwpcie_intx *di; 14565f800b9bSkettenis uint32_t status; 14575f800b9bSkettenis int pin, s; 14585f800b9bSkettenis 14595f800b9bSkettenis status = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, 14605f800b9bSkettenis PCIE_CLIENT_INTR_STATUS_LEGACY); 14615f800b9bSkettenis for (pin = 0; pin < nitems(sc->sc_intx); pin++) { 14625f800b9bSkettenis if ((status & (1 << pin)) == 0) 14635f800b9bSkettenis continue; 14645f800b9bSkettenis 14655f800b9bSkettenis TAILQ_FOREACH(di, &sc->sc_intx[pin], di_next) { 14665f800b9bSkettenis if ((di->di_flags & IPL_MPSAFE) == 0) 14675f800b9bSkettenis KERNEL_LOCK(); 14685f800b9bSkettenis s = splraise(di->di_ipl); 14695f800b9bSkettenis if (di->di_func(di->di_arg)) 14705f800b9bSkettenis di->di_count.ec_count++; 14715f800b9bSkettenis splx(s); 14725f800b9bSkettenis if ((di->di_flags & IPL_MPSAFE) == 0) 14735f800b9bSkettenis KERNEL_UNLOCK(); 14745f800b9bSkettenis } 14755f800b9bSkettenis } 14765f800b9bSkettenis 14775f800b9bSkettenis return 1; 14785f800b9bSkettenis } 14795f800b9bSkettenis 14805f800b9bSkettenis void * 14815f800b9bSkettenis dwpcie_rk3568_intr_establish(void *cookie, int *cell, int level, 14825f800b9bSkettenis struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 14835f800b9bSkettenis { 14845f800b9bSkettenis struct dwpcie_softc *sc = (struct dwpcie_softc *)cookie; 14855f800b9bSkettenis struct dwpcie_intx *di; 14865f800b9bSkettenis int pin = cell[0]; 14875f800b9bSkettenis uint32_t mask = (1U << pin); 14885f800b9bSkettenis 14895f800b9bSkettenis if (ci != NULL && !CPU_IS_PRIMARY(ci)) 14905f800b9bSkettenis return NULL; 14915f800b9bSkettenis 14925f800b9bSkettenis if (pin < 0 || pin >= nitems(sc->sc_intx)) 14935f800b9bSkettenis return NULL; 14945f800b9bSkettenis 14955f800b9bSkettenis /* Mask the interrupt. */ 14965f800b9bSkettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 14975f800b9bSkettenis PCIE_CLIENT_INTR_MASK_LEGACY, (mask << 16) | mask); 14985f800b9bSkettenis intr_barrier(sc->sc_ih); 14995f800b9bSkettenis 15005f800b9bSkettenis di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); 15015f800b9bSkettenis di->di_func = func; 15025f800b9bSkettenis di->di_arg = arg; 15035f800b9bSkettenis di->di_ipl = level & IPL_IRQMASK; 15045f800b9bSkettenis di->di_flags = level & IPL_FLAGMASK; 15055f800b9bSkettenis di->di_pin = pin; 15065f800b9bSkettenis di->di_name = name; 15075f800b9bSkettenis if (name != NULL) 15085f800b9bSkettenis evcount_attach(&di->di_count, name, &di->di_pin); 15095f800b9bSkettenis di->di_sc = sc; 15105f800b9bSkettenis TAILQ_INSERT_TAIL(&sc->sc_intx[pin], di, di_next); 15115f800b9bSkettenis 15125f800b9bSkettenis /* Unmask the interrupt. */ 15135f800b9bSkettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 15145f800b9bSkettenis PCIE_CLIENT_INTR_MASK_LEGACY, mask << 16); 15155f800b9bSkettenis 15165f800b9bSkettenis return di; 15175f800b9bSkettenis } 15185f800b9bSkettenis 15195f800b9bSkettenis void 15205f800b9bSkettenis dwpcie_rk3568_intr_disestablish(void *cookie) 15215f800b9bSkettenis { 15225f800b9bSkettenis struct dwpcie_intx *di = cookie; 15235f800b9bSkettenis struct dwpcie_softc *sc = di->di_sc; 15245f800b9bSkettenis uint32_t mask = (1U << di->di_pin); 15255f800b9bSkettenis 15265f800b9bSkettenis /* Mask the interrupt. */ 15275f800b9bSkettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 15285f800b9bSkettenis PCIE_CLIENT_INTR_MASK_LEGACY, (mask << 16) | mask); 15295f800b9bSkettenis intr_barrier(sc->sc_ih); 15305f800b9bSkettenis 15315f800b9bSkettenis if (di->di_name) 15325f800b9bSkettenis evcount_detach(&di->di_count); 15335f800b9bSkettenis 15345f800b9bSkettenis TAILQ_REMOVE(&sc->sc_intx[di->di_pin], di, di_next); 15355f800b9bSkettenis 15365f800b9bSkettenis if (!TAILQ_EMPTY(&sc->sc_intx[di->di_pin])) { 15375f800b9bSkettenis /* Unmask the interrupt. */ 15385f800b9bSkettenis bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, 15395f800b9bSkettenis PCIE_CLIENT_INTR_MASK_LEGACY, mask << 16); 15405f800b9bSkettenis } 15415045af7fSjsg 15425045af7fSjsg free(di, M_DEVBUF, sizeof(*di)); 15435f800b9bSkettenis } 15445f800b9bSkettenis 15455f800b9bSkettenis void 15465f800b9bSkettenis dwpcie_rk3568_intr_barrier(void *cookie) 15475f800b9bSkettenis { 15485f800b9bSkettenis struct dwpcie_intx *di = cookie; 15495f800b9bSkettenis struct dwpcie_softc *sc = di->di_sc; 15505f800b9bSkettenis 15515f800b9bSkettenis intr_barrier(sc->sc_ih); 15525f800b9bSkettenis } 15535f800b9bSkettenis 15545f800b9bSkettenis int 1555a848a3cbSpatrick dwpcie_sc8280xp_init(struct dwpcie_softc *sc) 1556a848a3cbSpatrick { 1557a848a3cbSpatrick sc->sc_num_viewport = 8; 1558a848a3cbSpatrick 1559351aecf3Spatrick if (OF_getproplen(sc->sc_node, "msi-map") <= 0) 1560351aecf3Spatrick return dwpcie_msi_init(sc); 1561351aecf3Spatrick 1562a848a3cbSpatrick return 0; 1563a848a3cbSpatrick } 1564a848a3cbSpatrick 1565a848a3cbSpatrick void 1566a848a3cbSpatrick dwpcie_atu_write(struct dwpcie_softc *sc, int index, off_t reg, 1567a848a3cbSpatrick uint32_t val) 1568a848a3cbSpatrick { 1569a848a3cbSpatrick if (sc->sc_atu_unroll) { 1570a848a3cbSpatrick bus_space_write_4(sc->sc_iot, sc->sc_atu_ioh, 1571a848a3cbSpatrick IATU_OFFSET_UNROLL(index) + reg, val); 1572a848a3cbSpatrick return; 1573a848a3cbSpatrick } 1574a848a3cbSpatrick 1575a848a3cbSpatrick if (sc->sc_atu_viewport != index) { 1576a848a3cbSpatrick HWRITE4(sc, IATU_VIEWPORT, index); 1577a848a3cbSpatrick sc->sc_atu_viewport = index; 1578a848a3cbSpatrick } 1579a848a3cbSpatrick 1580a848a3cbSpatrick HWRITE4(sc, IATU_OFFSET_VIEWPORT + reg, val); 1581a848a3cbSpatrick } 1582a848a3cbSpatrick 1583a848a3cbSpatrick uint32_t 1584a848a3cbSpatrick dwpcie_atu_read(struct dwpcie_softc *sc, int index, off_t reg) 1585a848a3cbSpatrick { 1586a848a3cbSpatrick if (sc->sc_atu_unroll) { 1587a848a3cbSpatrick return bus_space_read_4(sc->sc_iot, sc->sc_atu_ioh, 1588a848a3cbSpatrick IATU_OFFSET_UNROLL(index) + reg); 1589a848a3cbSpatrick } 1590a848a3cbSpatrick 1591a848a3cbSpatrick if (sc->sc_atu_viewport != index) { 1592a848a3cbSpatrick HWRITE4(sc, IATU_VIEWPORT, index); 1593a848a3cbSpatrick sc->sc_atu_viewport = index; 1594a848a3cbSpatrick } 1595a848a3cbSpatrick 1596a848a3cbSpatrick return HREAD4(sc, IATU_OFFSET_VIEWPORT + reg); 1597a848a3cbSpatrick } 1598a848a3cbSpatrick 15995f3e3118Skettenis void 16005f3e3118Skettenis dwpcie_atu_disable(struct dwpcie_softc *sc, int index) 16015f3e3118Skettenis { 1602a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_REGION_CTRL_2, 0); 16035f3e3118Skettenis } 16045f3e3118Skettenis 16056a2b914cSpatrick void 16066a2b914cSpatrick dwpcie_atu_config(struct dwpcie_softc *sc, int index, int type, 16076a2b914cSpatrick uint64_t cpu_addr, uint64_t pci_addr, uint64_t size) 16086a2b914cSpatrick { 1609a848a3cbSpatrick uint32_t reg; 16106a2b914cSpatrick int timo; 16116a2b914cSpatrick 1612a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_LWR_BASE_ADDR, cpu_addr); 1613a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_UPPER_BASE_ADDR, cpu_addr >> 32); 1614a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_LIMIT_ADDR, cpu_addr + size - 1); 1615a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_LWR_TARGET_ADDR, pci_addr); 1616a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_UPPER_TARGET_ADDR, pci_addr >> 32); 1617a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_REGION_CTRL_1, type); 1618a848a3cbSpatrick dwpcie_atu_write(sc, index, IATU_REGION_CTRL_2, 1619a848a3cbSpatrick IATU_REGION_CTRL_2_REGION_EN); 16206a2b914cSpatrick 16216a2b914cSpatrick for (timo = 5; timo > 0; timo--) { 1622a848a3cbSpatrick reg = dwpcie_atu_read(sc, index, IATU_REGION_CTRL_2); 16236a2b914cSpatrick if (reg & IATU_REGION_CTRL_2_REGION_EN) 16246a2b914cSpatrick break; 16256a2b914cSpatrick delay(9000); 16266a2b914cSpatrick } 16276a2b914cSpatrick if (timo == 0) 16286a2b914cSpatrick printf("%s:%d: timeout\n", __func__, __LINE__); 16296a2b914cSpatrick } 16306a2b914cSpatrick 16316a2b914cSpatrick int 16326a2b914cSpatrick dwpcie_link_up(struct dwpcie_softc *sc) 16336a2b914cSpatrick { 16346a2b914cSpatrick uint32_t reg; 16356a2b914cSpatrick 16366a2b914cSpatrick reg = HREAD4(sc, PCIE_PHY_DEBUG_R1); 16376a2b914cSpatrick if ((reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) != 0 && 16386a2b914cSpatrick (reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING) == 0) 16396a2b914cSpatrick return 1; 16406a2b914cSpatrick return 0; 16417659d2d7Skettenis } 16427659d2d7Skettenis 16437659d2d7Skettenis void 16447659d2d7Skettenis dwpcie_attach_hook(struct device *parent, struct device *self, 16457659d2d7Skettenis struct pcibus_attach_args *pba) 16467659d2d7Skettenis { 16477659d2d7Skettenis } 16487659d2d7Skettenis 16497659d2d7Skettenis int 16507659d2d7Skettenis dwpcie_bus_maxdevs(void *v, int bus) 16517659d2d7Skettenis { 16527659d2d7Skettenis struct dwpcie_softc *sc = v; 16537659d2d7Skettenis 16547659d2d7Skettenis if (bus == sc->sc_bus || bus == sc->sc_bus + 1) 16557659d2d7Skettenis return 1; 16567659d2d7Skettenis return 32; 16577659d2d7Skettenis } 16587659d2d7Skettenis 1659e1e95ce2Spatrick int 1660e1e95ce2Spatrick dwpcie_find_node(int node, int bus, int device, int function) 1661e1e95ce2Spatrick { 1662e1e95ce2Spatrick uint32_t reg[5]; 1663e1e95ce2Spatrick uint32_t phys_hi; 1664e1e95ce2Spatrick int child; 1665e1e95ce2Spatrick 1666e1e95ce2Spatrick phys_hi = ((bus << 16) | (device << 11) | (function << 8)); 1667e1e95ce2Spatrick 1668e1e95ce2Spatrick for (child = OF_child(node); child; child = OF_peer(child)) { 1669e1e95ce2Spatrick if (OF_getpropintarray(child, "reg", 1670e1e95ce2Spatrick reg, sizeof(reg)) != sizeof(reg)) 1671e1e95ce2Spatrick continue; 1672e1e95ce2Spatrick 1673e1e95ce2Spatrick if (reg[0] == phys_hi) 1674e1e95ce2Spatrick return child; 1675e1e95ce2Spatrick 1676e1e95ce2Spatrick node = dwpcie_find_node(child, bus, device, function); 1677e1e95ce2Spatrick if (node) 1678e1e95ce2Spatrick return node; 1679e1e95ce2Spatrick } 1680e1e95ce2Spatrick 1681e1e95ce2Spatrick return 0; 1682e1e95ce2Spatrick } 1683e1e95ce2Spatrick 16847659d2d7Skettenis pcitag_t 16857659d2d7Skettenis dwpcie_make_tag(void *v, int bus, int device, int function) 16867659d2d7Skettenis { 1687e1e95ce2Spatrick struct dwpcie_softc *sc = v; 1688e1e95ce2Spatrick int node; 1689e1e95ce2Spatrick 1690e1e95ce2Spatrick node = dwpcie_find_node(sc->sc_node, bus, device, function); 1691e1e95ce2Spatrick return (((pcitag_t)node << 32) | 1692e1e95ce2Spatrick (bus << 24) | (device << 19) | (function << 16)); 16937659d2d7Skettenis } 16947659d2d7Skettenis 16957659d2d7Skettenis void 16967659d2d7Skettenis dwpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 16977659d2d7Skettenis { 16987659d2d7Skettenis if (bp != NULL) 16997659d2d7Skettenis *bp = (tag >> 24) & 0xff; 17007659d2d7Skettenis if (dp != NULL) 17017659d2d7Skettenis *dp = (tag >> 19) & 0x1f; 17027659d2d7Skettenis if (fp != NULL) 17037659d2d7Skettenis *fp = (tag >> 16) & 0x7; 17047659d2d7Skettenis } 17057659d2d7Skettenis 17067659d2d7Skettenis int 17077659d2d7Skettenis dwpcie_conf_size(void *v, pcitag_t tag) 17087659d2d7Skettenis { 17097659d2d7Skettenis return PCIE_CONFIG_SPACE_SIZE; 17107659d2d7Skettenis } 17117659d2d7Skettenis 17127659d2d7Skettenis pcireg_t 17137659d2d7Skettenis dwpcie_conf_read(void *v, pcitag_t tag, int reg) 17147659d2d7Skettenis { 17157659d2d7Skettenis struct dwpcie_softc *sc = v; 17167659d2d7Skettenis int bus, dev, fn; 17176a2b914cSpatrick uint32_t ret; 17187659d2d7Skettenis 17197659d2d7Skettenis dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 17207659d2d7Skettenis if (bus == sc->sc_bus) { 17217659d2d7Skettenis KASSERT(dev == 0); 1722f6d21d67Skettenis tag = dwpcie_make_tag(sc, 0, dev, fn); 1723e1e95ce2Spatrick return HREAD4(sc, PCITAG_OFFSET(tag) | reg); 17247659d2d7Skettenis } 17257659d2d7Skettenis 17266a2b914cSpatrick if (bus == sc->sc_bus + 1) { 17276a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17286a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_CFG0, 1729e1e95ce2Spatrick sc->sc_conf_base, PCITAG_OFFSET(tag), 1730e1e95ce2Spatrick sc->sc_conf_size); 17316a2b914cSpatrick } else { 17326a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17336a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_CFG1, 1734e1e95ce2Spatrick sc->sc_conf_base, PCITAG_OFFSET(tag), 1735e1e95ce2Spatrick sc->sc_conf_size); 17366a2b914cSpatrick } 173701dd2b7cSkettenis 173801dd2b7cSkettenis ret = bus_space_read_4(sc->sc_iot, sc->sc_conf_ioh, reg); 173901dd2b7cSkettenis 1740d2397242Skettenis if (sc->sc_num_viewport <= 2 && sc->sc_io_size > 0) { 17416a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17426a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 17436a2b914cSpatrick sc->sc_io_bus_addr, sc->sc_io_size); 174401dd2b7cSkettenis } 17456a2b914cSpatrick 17466a2b914cSpatrick return ret; 17477659d2d7Skettenis } 17487659d2d7Skettenis 17497659d2d7Skettenis void 17507659d2d7Skettenis dwpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 17517659d2d7Skettenis { 17527659d2d7Skettenis struct dwpcie_softc *sc = v; 17537659d2d7Skettenis int bus, dev, fn; 17547659d2d7Skettenis 17557659d2d7Skettenis dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 17567659d2d7Skettenis if (bus == sc->sc_bus) { 17577659d2d7Skettenis KASSERT(dev == 0); 1758f6d21d67Skettenis tag = dwpcie_make_tag(sc, 0, dev, fn); 1759e1e95ce2Spatrick HWRITE4(sc, PCITAG_OFFSET(tag) | reg, data); 17607659d2d7Skettenis return; 17617659d2d7Skettenis } 17627659d2d7Skettenis 17636a2b914cSpatrick if (bus == sc->sc_bus + 1) { 17646a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17656a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_CFG0, 1766e1e95ce2Spatrick sc->sc_conf_base, PCITAG_OFFSET(tag), 1767e1e95ce2Spatrick sc->sc_conf_size); 17686a2b914cSpatrick } else { 17696a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17706a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_CFG1, 1771e1e95ce2Spatrick sc->sc_conf_base, PCITAG_OFFSET(tag), 1772e1e95ce2Spatrick sc->sc_conf_size); 17736a2b914cSpatrick } 177401dd2b7cSkettenis 177501dd2b7cSkettenis bus_space_write_4(sc->sc_iot, sc->sc_conf_ioh, reg, data); 177601dd2b7cSkettenis 1777d2397242Skettenis if (sc->sc_num_viewport <= 2 && sc->sc_io_size > 0) { 17786a2b914cSpatrick dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 17796a2b914cSpatrick IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 17806a2b914cSpatrick sc->sc_io_bus_addr, sc->sc_io_size); 17817659d2d7Skettenis } 178201dd2b7cSkettenis } 17837659d2d7Skettenis 17847659d2d7Skettenis int 1785619b146dSpatrick dwpcie_probe_device_hook(void *v, struct pci_attach_args *pa) 1786619b146dSpatrick { 178719800b49Spatrick struct dwpcie_softc *sc = v; 178819800b49Spatrick uint16_t rid; 1789415019ceSpatrick int i; 179019800b49Spatrick 179119800b49Spatrick rid = pci_requester_id(pa->pa_pc, pa->pa_tag); 179219800b49Spatrick pa->pa_dmat = iommu_device_map_pci(sc->sc_node, rid, pa->pa_dmat); 179319800b49Spatrick 1794415019ceSpatrick for (i = 0; i < sc->sc_nranges; i++) { 1795415019ceSpatrick iommu_reserve_region_pci(sc->sc_node, rid, 1796415019ceSpatrick sc->sc_ranges[i].pci_base, sc->sc_ranges[i].size); 1797415019ceSpatrick } 1798415019ceSpatrick 1799619b146dSpatrick return 0; 1800619b146dSpatrick } 1801619b146dSpatrick 1802619b146dSpatrick int 18037659d2d7Skettenis dwpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 18047659d2d7Skettenis { 18057659d2d7Skettenis int pin = pa->pa_rawintrpin; 18067659d2d7Skettenis 18077659d2d7Skettenis if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX) 18087659d2d7Skettenis return -1; 18097659d2d7Skettenis 18107659d2d7Skettenis if (pa->pa_tag == 0) 18117659d2d7Skettenis return -1; 18127659d2d7Skettenis 1813e410b95bSkettenis ihp->ih_pc = pa->pa_pc; 1814e410b95bSkettenis ihp->ih_tag = pa->pa_intrtag; 1815e410b95bSkettenis ihp->ih_intrpin = pa->pa_intrpin; 1816e410b95bSkettenis ihp->ih_type = PCI_INTX; 1817e33d8a25Skettenis 1818e33d8a25Skettenis return 0; 18197659d2d7Skettenis } 18207659d2d7Skettenis 18217659d2d7Skettenis const char * 1822e410b95bSkettenis dwpcie_intr_string(void *v, pci_intr_handle_t ih) 18237659d2d7Skettenis { 1824e410b95bSkettenis switch (ih.ih_type) { 1825e33d8a25Skettenis case PCI_MSI: 18267659d2d7Skettenis return "msi"; 1827e33d8a25Skettenis case PCI_MSIX: 1828e33d8a25Skettenis return "msix"; 1829e33d8a25Skettenis } 18307659d2d7Skettenis 18317659d2d7Skettenis return "intx"; 18327659d2d7Skettenis } 18337659d2d7Skettenis 1834d5dfbc11Skettenis struct dwpcie_msi * 18359a76443bSkettenis dwpcie_msi_establish(struct dwpcie_softc *sc, pci_intr_handle_t *ihp, 18369a76443bSkettenis int level, int (*func)(void *), void *arg, char *name) 1837d5dfbc11Skettenis { 18389a76443bSkettenis pci_chipset_tag_t pc = ihp->ih_pc; 18399a76443bSkettenis pcitag_t tag = ihp->ih_tag; 1840d5dfbc11Skettenis struct dwpcie_msi *dm; 18419a76443bSkettenis uint64_t msi_mask; 18429a76443bSkettenis int vec = ihp->ih_intrpin; 18439a76443bSkettenis int base, mme, nvec, off; 18449a76443bSkettenis pcireg_t reg; 1845d5dfbc11Skettenis 18469a76443bSkettenis if (ihp->ih_type == PCI_MSI) { 18479a76443bSkettenis if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®) == 0) 18489a76443bSkettenis panic("%s: no msi capability", __func__); 18499a76443bSkettenis 18509a76443bSkettenis reg = pci_conf_read(ihp->ih_pc, ihp->ih_tag, off); 18519a76443bSkettenis mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT); 18529a76443bSkettenis if (vec >= (1 << mme)) 18539a76443bSkettenis return NULL; 18549a76443bSkettenis if (reg & PCI_MSI_MC_C64) 18559a76443bSkettenis base = pci_conf_read(pc, tag, off + PCI_MSI_MD64); 18569a76443bSkettenis else 18579a76443bSkettenis base = pci_conf_read(pc, tag, off + PCI_MSI_MD32); 18589a76443bSkettenis } else { 18599a76443bSkettenis mme = 0; 18609a76443bSkettenis base = 0; 18619a76443bSkettenis } 18629a76443bSkettenis 18639a76443bSkettenis if (vec == 0) { 18649a76443bSkettenis /* 18659a76443bSkettenis * Pre-allocate all the requested vectors. Remember 18669a76443bSkettenis * the number of requested vectors such that we can 18679a76443bSkettenis * deallocate them in one go. 18689a76443bSkettenis */ 18699a76443bSkettenis msi_mask = (1ULL << (1 << mme)) - 1; 18709a76443bSkettenis while (vec <= sc->sc_num_msi - (1 << mme)) { 18719a76443bSkettenis if ((sc->sc_msi_mask & (msi_mask << vec)) == 0) { 18729a76443bSkettenis sc->sc_msi_mask |= (msi_mask << vec); 1873d5dfbc11Skettenis break; 1874d5dfbc11Skettenis } 18759a76443bSkettenis vec += (1 << mme); 18769a76443bSkettenis } 18779a76443bSkettenis base = vec; 18789a76443bSkettenis nvec = (1 << mme); 18799a76443bSkettenis } else { 18809a76443bSkettenis KASSERT(ihp->ih_type == PCI_MSI); 18819a76443bSkettenis vec += base; 18829a76443bSkettenis nvec = 0; 18839a76443bSkettenis } 18849a76443bSkettenis 18859a76443bSkettenis if (vec >= sc->sc_num_msi) 1886d5dfbc11Skettenis return NULL; 1887d5dfbc11Skettenis 18889a76443bSkettenis if (ihp->ih_type == PCI_MSI) { 18899a76443bSkettenis if (reg & PCI_MSI_MC_C64) 18909a76443bSkettenis pci_conf_write(pc, tag, off + PCI_MSI_MD64, base); 18919a76443bSkettenis else 18929a76443bSkettenis pci_conf_write(pc, tag, off + PCI_MSI_MD32, base); 18939a76443bSkettenis } 18949a76443bSkettenis 18959a76443bSkettenis dm = &sc->sc_msi[vec]; 18969a76443bSkettenis KASSERT(dm->dm_func == NULL); 18979a76443bSkettenis 1898d5dfbc11Skettenis dm->dm_func = func; 1899d5dfbc11Skettenis dm->dm_arg = arg; 1900d5dfbc11Skettenis dm->dm_ipl = level & IPL_IRQMASK; 1901d5dfbc11Skettenis dm->dm_flags = level & IPL_FLAGMASK; 1902d5dfbc11Skettenis dm->dm_vec = vec; 19039a76443bSkettenis dm->dm_nvec = nvec; 1904d5dfbc11Skettenis dm->dm_name = name; 1905d5dfbc11Skettenis if (name != NULL) 1906d5dfbc11Skettenis evcount_attach(&dm->dm_count, name, &dm->dm_vec); 1907d5dfbc11Skettenis 1908d5dfbc11Skettenis /* Unmask the MSI. */ 19099a76443bSkettenis HCLR4(sc, PCIE_MSI_INTR_MASK(vec / 32), (1U << (vec % 32))); 1910d5dfbc11Skettenis 1911d5dfbc11Skettenis return dm; 1912d5dfbc11Skettenis } 1913d5dfbc11Skettenis 1914d5dfbc11Skettenis void 1915d5dfbc11Skettenis dwpcie_msi_disestablish(struct dwpcie_softc *sc, struct dwpcie_msi *dm) 1916d5dfbc11Skettenis { 19179a76443bSkettenis uint64_t msi_mask = (1ULL << dm->dm_nvec) - 1; 19189a76443bSkettenis 1919d5dfbc11Skettenis /* Mask the MSI. */ 19209a76443bSkettenis HSET4(sc, PCIE_MSI_INTR_MASK(dm->dm_vec / 32), 19219a76443bSkettenis (1U << (dm->dm_vec % 32))); 1922d5dfbc11Skettenis 1923d5dfbc11Skettenis if (dm->dm_name) 1924d5dfbc11Skettenis evcount_detach(&dm->dm_count); 1925d5dfbc11Skettenis dm->dm_func = NULL; 19269a76443bSkettenis 19279a76443bSkettenis /* 19289a76443bSkettenis * Unallocate all allocated vetcors if this is the first 19299a76443bSkettenis * vector for the device. 19309a76443bSkettenis */ 19319a76443bSkettenis sc->sc_msi_mask &= ~(msi_mask << dm->dm_vec); 1932d5dfbc11Skettenis } 1933d5dfbc11Skettenis 19347659d2d7Skettenis void * 1935e410b95bSkettenis dwpcie_intr_establish(void *v, pci_intr_handle_t ih, int level, 1936d67371fdSpatrick struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 19377659d2d7Skettenis { 19387659d2d7Skettenis struct dwpcie_softc *sc = v; 1939cc0ede06Spatrick struct dwpcie_intr_handle *pih; 1940d5dfbc11Skettenis void *cookie = NULL; 19417659d2d7Skettenis 1942e410b95bSkettenis KASSERT(ih.ih_type != PCI_NONE); 1943e410b95bSkettenis 1944e410b95bSkettenis if (ih.ih_type != PCI_INTX) { 1945d5dfbc11Skettenis struct dwpcie_msi *dm = NULL; 1946d5dfbc11Skettenis bus_dma_tag_t dmat = ih.ih_dmat; 1947d5dfbc11Skettenis bus_dma_segment_t seg; 1948d5dfbc11Skettenis bus_dmamap_t map; 19497659d2d7Skettenis uint64_t addr, data; 19507659d2d7Skettenis 1951d5dfbc11Skettenis if (sc->sc_msi_addr) { 19529a76443bSkettenis dm = dwpcie_msi_establish(sc, &ih, level, func, arg, name); 1953d5dfbc11Skettenis if (dm == NULL) 1954d5dfbc11Skettenis return NULL; 1955d5dfbc11Skettenis addr = sc->sc_msi_addr; 1956d5dfbc11Skettenis data = dm->dm_vec; 1957d5dfbc11Skettenis } else { 1958d5dfbc11Skettenis /* 1959d5dfbc11Skettenis * Assume hardware passes Requester ID as 1960d5dfbc11Skettenis * sideband data. 1961d5dfbc11Skettenis */ 196256d02c00Skettenis addr = ih.ih_intrpin; 1963e410b95bSkettenis data = pci_requester_id(ih.ih_pc, ih.ih_tag); 1964d67371fdSpatrick cookie = fdt_intr_establish_msi_cpu(sc->sc_node, &addr, 1965d67371fdSpatrick &data, level, ci, func, arg, (void *)name); 19667659d2d7Skettenis if (cookie == NULL) 19677659d2d7Skettenis return NULL; 1968d5dfbc11Skettenis } 19697659d2d7Skettenis 1970d5dfbc11Skettenis pih = malloc(sizeof(*pih), M_DEVBUF, M_WAITOK | M_ZERO); 1971cc0ede06Spatrick pih->pih_ih.ih_ic = &dwpcie_ic; 1972cc0ede06Spatrick pih->pih_ih.ih_ih = cookie; 1973d5dfbc11Skettenis pih->pih_sc = sc; 1974d5dfbc11Skettenis pih->pih_dm = dm; 19757659d2d7Skettenis 1976d5dfbc11Skettenis if (sc->sc_msi_addr == 0) { 1977d5dfbc11Skettenis if (bus_dmamap_create(dmat, sizeof(uint32_t), 1, 1978d5dfbc11Skettenis sizeof(uint32_t), 0, BUS_DMA_WAITOK, &map)) { 1979cc0ede06Spatrick free(pih, M_DEVBUF, sizeof(*pih)); 1980cc0ede06Spatrick fdt_intr_disestablish(cookie); 1981cc0ede06Spatrick return NULL; 1982cc0ede06Spatrick } 1983cc0ede06Spatrick 1984cc0ede06Spatrick memset(&seg, 0, sizeof(seg)); 1985cc0ede06Spatrick seg.ds_addr = addr; 1986cc0ede06Spatrick seg.ds_len = sizeof(uint32_t); 1987cc0ede06Spatrick 1988d5dfbc11Skettenis if (bus_dmamap_load_raw(dmat, map, &seg, 1, 1989d5dfbc11Skettenis sizeof(uint32_t), BUS_DMA_WAITOK)) { 1990d5dfbc11Skettenis bus_dmamap_destroy(dmat, map); 1991cc0ede06Spatrick free(pih, M_DEVBUF, sizeof(*pih)); 1992cc0ede06Spatrick fdt_intr_disestablish(cookie); 1993cc0ede06Spatrick return NULL; 1994cc0ede06Spatrick } 1995cc0ede06Spatrick 1996d5dfbc11Skettenis addr = map->dm_segs[0].ds_addr; 1997d5dfbc11Skettenis pih->pih_dmat = dmat; 1998d5dfbc11Skettenis pih->pih_map = map; 1999d5dfbc11Skettenis } 2000d5dfbc11Skettenis 2001e410b95bSkettenis if (ih.ih_type == PCI_MSIX) { 2002e410b95bSkettenis pci_msix_enable(ih.ih_pc, ih.ih_tag, 2003e410b95bSkettenis &sc->sc_bus_memt, ih.ih_intrpin, addr, data); 2004e33d8a25Skettenis } else 2005e410b95bSkettenis pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data); 20067659d2d7Skettenis } else { 20077659d2d7Skettenis int bus, dev, fn; 20087659d2d7Skettenis uint32_t reg[4]; 20097659d2d7Skettenis 2010e410b95bSkettenis dwpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn); 20117659d2d7Skettenis 20127659d2d7Skettenis reg[0] = bus << 16 | dev << 11 | fn << 8; 20137659d2d7Skettenis reg[1] = reg[2] = 0; 2014e410b95bSkettenis reg[3] = ih.ih_intrpin; 20157659d2d7Skettenis 2016d67371fdSpatrick cookie = fdt_intr_establish_imap_cpu(sc->sc_node, reg, 2017d67371fdSpatrick sizeof(reg), level, ci, func, arg, name); 2018cc0ede06Spatrick if (cookie == NULL) 2019cc0ede06Spatrick return NULL; 2020cc0ede06Spatrick 2021d5dfbc11Skettenis pih = malloc(sizeof(*pih), M_DEVBUF, M_WAITOK | M_ZERO); 2022cc0ede06Spatrick pih->pih_ih.ih_ic = &dwpcie_ic; 2023cc0ede06Spatrick pih->pih_ih.ih_ih = cookie; 20247659d2d7Skettenis } 20257659d2d7Skettenis 2026cc0ede06Spatrick return pih; 20277659d2d7Skettenis } 20287659d2d7Skettenis 20297659d2d7Skettenis void 20307659d2d7Skettenis dwpcie_intr_disestablish(void *v, void *cookie) 20317659d2d7Skettenis { 2032cc0ede06Spatrick struct dwpcie_intr_handle *pih = cookie; 2033cc0ede06Spatrick 2034d5dfbc11Skettenis if (pih->pih_dm) 2035d5dfbc11Skettenis dwpcie_msi_disestablish(pih->pih_sc, pih->pih_dm); 2036d5dfbc11Skettenis else 2037cc0ede06Spatrick fdt_intr_disestablish(pih->pih_ih.ih_ih); 2038d5dfbc11Skettenis 2039cc0ede06Spatrick if (pih->pih_dmat) { 2040cc0ede06Spatrick bus_dmamap_unload(pih->pih_dmat, pih->pih_map); 2041cc0ede06Spatrick bus_dmamap_destroy(pih->pih_dmat, pih->pih_map); 2042cc0ede06Spatrick } 2043d5dfbc11Skettenis 2044cc0ede06Spatrick free(pih, M_DEVBUF, sizeof(*pih)); 20457659d2d7Skettenis } 204671fe361bSkettenis 204771fe361bSkettenis int 204871fe361bSkettenis dwpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 204971fe361bSkettenis int flags, bus_space_handle_t *bshp) 205071fe361bSkettenis { 205171fe361bSkettenis struct dwpcie_softc *sc = t->bus_private; 205271fe361bSkettenis int i; 205371fe361bSkettenis 2054d43be508Skettenis for (i = 0; i < sc->sc_nranges; i++) { 205571fe361bSkettenis uint64_t pci_start = sc->sc_ranges[i].pci_base; 205671fe361bSkettenis uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 205771fe361bSkettenis uint64_t phys_start = sc->sc_ranges[i].phys_base; 205871fe361bSkettenis 205971fe361bSkettenis if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 206071fe361bSkettenis addr >= pci_start && addr + size <= pci_end) { 206171fe361bSkettenis return bus_space_map(sc->sc_iot, 206271fe361bSkettenis addr - pci_start + phys_start, size, flags, bshp); 206371fe361bSkettenis } 206471fe361bSkettenis } 206571fe361bSkettenis 206671fe361bSkettenis return ENXIO; 206771fe361bSkettenis } 206871fe361bSkettenis 206971fe361bSkettenis int 207071fe361bSkettenis dwpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 207171fe361bSkettenis int flags, bus_space_handle_t *bshp) 207271fe361bSkettenis { 207371fe361bSkettenis struct dwpcie_softc *sc = t->bus_private; 207471fe361bSkettenis int i; 207571fe361bSkettenis 2076d43be508Skettenis for (i = 0; i < sc->sc_nranges; i++) { 207771fe361bSkettenis uint64_t pci_start = sc->sc_ranges[i].pci_base; 207871fe361bSkettenis uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 207971fe361bSkettenis uint64_t phys_start = sc->sc_ranges[i].phys_base; 208071fe361bSkettenis 2081254dd109Skettenis if ((sc->sc_ranges[i].flags & 0x02000000) == 0x02000000 && 208271fe361bSkettenis addr >= pci_start && addr + size <= pci_end) { 208371fe361bSkettenis return bus_space_map(sc->sc_iot, 208471fe361bSkettenis addr - pci_start + phys_start, size, flags, bshp); 208571fe361bSkettenis } 208671fe361bSkettenis } 208771fe361bSkettenis 208871fe361bSkettenis return ENXIO; 208971fe361bSkettenis } 2090