1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun */ 26ef2ee5d0SMichal Meloun 27ef2ee5d0SMichal Meloun #include <sys/cdefs.h> 28ef2ee5d0SMichal Meloun /* 29ef2ee5d0SMichal Meloun * Nvidia Integrated PCI/PCI-Express controller driver. 30ef2ee5d0SMichal Meloun */ 31ef2ee5d0SMichal Meloun 32ef2ee5d0SMichal Meloun #include <sys/param.h> 33ef2ee5d0SMichal Meloun #include <sys/systm.h> 347709abd1SMichal Meloun #include <sys/bus.h> 357709abd1SMichal Meloun #include <sys/devmap.h> 367709abd1SMichal Meloun #include <sys/proc.h> 37ef2ee5d0SMichal Meloun #include <sys/kernel.h> 38ef2ee5d0SMichal Meloun #include <sys/malloc.h> 39ef2ee5d0SMichal Meloun #include <sys/module.h> 40ef2ee5d0SMichal Meloun #include <sys/mutex.h> 41ef2ee5d0SMichal Meloun #include <sys/rman.h> 42ef2ee5d0SMichal Meloun 43ef2ee5d0SMichal Meloun #include <machine/intr.h> 44ef2ee5d0SMichal Meloun 45ef2ee5d0SMichal Meloun #include <vm/vm.h> 467709abd1SMichal Meloun #include <vm/vm_extern.h> 477709abd1SMichal Meloun #include <vm/vm_kern.h> 48ef2ee5d0SMichal Meloun #include <vm/pmap.h> 49ef2ee5d0SMichal Meloun 50be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 511f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h> 52950a6087SEmmanuel Vadot #include <dev/phy/phy.h> 53b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h> 54ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 55ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 56ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_pci.h> 5779cceaacSMichal Meloun #include <dev/ofw/ofwpci.h> 58ef2ee5d0SMichal Meloun #include <dev/pci/pcivar.h> 59ef2ee5d0SMichal Meloun #include <dev/pci/pcireg.h> 60ef2ee5d0SMichal Meloun #include <dev/pci/pcib_private.h> 61ef2ee5d0SMichal Meloun 62ef2ee5d0SMichal Meloun #include <machine/resource.h> 63ef2ee5d0SMichal Meloun #include <machine/bus.h> 64ef2ee5d0SMichal Meloun 6579cceaacSMichal Meloun #include <arm/nvidia/tegra_pmc.h> 6679cceaacSMichal Meloun 67ef2ee5d0SMichal Meloun #include "ofw_bus_if.h" 687709abd1SMichal Meloun #include "msi_if.h" 69ef2ee5d0SMichal Meloun #include "pcib_if.h" 707709abd1SMichal Meloun #include "pic_if.h" 71ef2ee5d0SMichal Meloun 72ef2ee5d0SMichal Meloun #define AFI_AXI_BAR0_SZ 0x000 73ef2ee5d0SMichal Meloun #define AFI_AXI_BAR1_SZ 0x004 74ef2ee5d0SMichal Meloun #define AFI_AXI_BAR2_SZ 0x008 75ef2ee5d0SMichal Meloun #define AFI_AXI_BAR3_SZ 0x00c 76ef2ee5d0SMichal Meloun #define AFI_AXI_BAR4_SZ 0x010 77ef2ee5d0SMichal Meloun #define AFI_AXI_BAR5_SZ 0x014 78ef2ee5d0SMichal Meloun #define AFI_AXI_BAR0_START 0x018 79ef2ee5d0SMichal Meloun #define AFI_AXI_BAR1_START 0x01c 80ef2ee5d0SMichal Meloun #define AFI_AXI_BAR2_START 0x020 81ef2ee5d0SMichal Meloun #define AFI_AXI_BAR3_START 0x024 82ef2ee5d0SMichal Meloun #define AFI_AXI_BAR4_START 0x028 83ef2ee5d0SMichal Meloun #define AFI_AXI_BAR5_START 0x02c 84ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR0 0x030 85ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR1 0x034 86ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR2 0x038 87ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR3 0x03c 88ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR4 0x040 89ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR5 0x044 90ef2ee5d0SMichal Meloun #define AFI_MSI_BAR_SZ 0x060 91ef2ee5d0SMichal Meloun #define AFI_MSI_FPCI_BAR_ST 0x064 92ef2ee5d0SMichal Meloun #define AFI_MSI_AXI_BAR_ST 0x068 937709abd1SMichal Meloun #define AFI_MSI_VEC(x) (0x06c + 4 * (x)) 947709abd1SMichal Meloun #define AFI_MSI_EN_VEC(x) (0x08c + 4 * (x)) 957709abd1SMichal Meloun #define AFI_MSI_INTR_IN_REG 32 967709abd1SMichal Meloun #define AFI_MSI_REGS 8 97ef2ee5d0SMichal Meloun 98ef2ee5d0SMichal Meloun #define AFI_CONFIGURATION 0x0ac 99ef2ee5d0SMichal Meloun #define AFI_CONFIGURATION_EN_FPCI (1 << 0) 100ef2ee5d0SMichal Meloun 101ef2ee5d0SMichal Meloun #define AFI_FPCI_ERROR_MASKS 0x0b0 102ef2ee5d0SMichal Meloun #define AFI_INTR_MASK 0x0b4 103ef2ee5d0SMichal Meloun #define AFI_INTR_MASK_MSI_MASK (1 << 8) 104ef2ee5d0SMichal Meloun #define AFI_INTR_MASK_INT_MASK (1 << 0) 105ef2ee5d0SMichal Meloun 106ef2ee5d0SMichal Meloun #define AFI_INTR_CODE 0x0b8 107ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_MASK 0xf 108ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_INI_SLVERR 1 109ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_INI_DECERR 2 110ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_TGT_SLVERR 3 111ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_TGT_DECERR 4 112ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_TGT_WRERR 5 113ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_SM_MSG 6 114ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_DFPCI_DECERR 7 115ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_AXI_DECERR 8 116ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT 9 117ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE 10 118ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE 11 119ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE 12 120ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE 13 121ef2ee5d0SMichal Meloun #define AFI_INTR_CODE_INT_CODE_P2P_ERROR 14 122ef2ee5d0SMichal Meloun 123ef2ee5d0SMichal Meloun #define AFI_INTR_SIGNATURE 0x0bc 124ef2ee5d0SMichal Meloun #define AFI_UPPER_FPCI_ADDRESS 0x0c0 125ef2ee5d0SMichal Meloun #define AFI_SM_INTR_ENABLE 0x0c4 126ef2ee5d0SMichal Meloun #define AFI_SM_INTR_RP_DEASSERT (1 << 14) 127ef2ee5d0SMichal Meloun #define AFI_SM_INTR_RP_ASSERT (1 << 13) 128ef2ee5d0SMichal Meloun #define AFI_SM_INTR_HOTPLUG (1 << 12) 129ef2ee5d0SMichal Meloun #define AFI_SM_INTR_PME (1 << 11) 130ef2ee5d0SMichal Meloun #define AFI_SM_INTR_FATAL_ERROR (1 << 10) 131ef2ee5d0SMichal Meloun #define AFI_SM_INTR_UNCORR_ERROR (1 << 9) 132ef2ee5d0SMichal Meloun #define AFI_SM_INTR_CORR_ERROR (1 << 8) 133ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTD_DEASSERT (1 << 7) 134ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTC_DEASSERT (1 << 6) 135ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTB_DEASSERT (1 << 5) 136ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTA_DEASSERT (1 << 4) 137ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTD_ASSERT (1 << 3) 138ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTC_ASSERT (1 << 2) 139ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTB_ASSERT (1 << 1) 140ef2ee5d0SMichal Meloun #define AFI_SM_INTR_INTA_ASSERT (1 << 0) 141ef2ee5d0SMichal Meloun 142ef2ee5d0SMichal Meloun #define AFI_AFI_INTR_ENABLE 0x0c8 143ef2ee5d0SMichal Meloun #define AFI_AFI_INTR_ENABLE_CODE(code) (1 << (code)) 144ef2ee5d0SMichal Meloun 145ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG 0x0f8 146ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1)) 147ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0x6 148ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) 149ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1 (0x0 << 20) 150ef2ee5d0SMichal Meloun #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1 (0x1 << 20) 151ef2ee5d0SMichal Meloun 152ef2ee5d0SMichal Meloun #define AFI_FUSE 0x104 153ef2ee5d0SMichal Meloun #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) 154ef2ee5d0SMichal Meloun 155ef2ee5d0SMichal Meloun #define AFI_PEX0_CTRL 0x110 156ef2ee5d0SMichal Meloun #define AFI_PEX1_CTRL 0x118 157ef2ee5d0SMichal Meloun #define AFI_PEX2_CTRL 0x128 158ef2ee5d0SMichal Meloun #define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4) 159ef2ee5d0SMichal Meloun #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) 160ef2ee5d0SMichal Meloun #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) 161ef2ee5d0SMichal Meloun #define AFI_PEX_CTRL_RST_L (1 << 0) 162ef2ee5d0SMichal Meloun 163ef2ee5d0SMichal Meloun #define AFI_AXI_BAR6_SZ 0x134 164ef2ee5d0SMichal Meloun #define AFI_AXI_BAR7_SZ 0x138 165ef2ee5d0SMichal Meloun #define AFI_AXI_BAR8_SZ 0x13c 166ef2ee5d0SMichal Meloun #define AFI_AXI_BAR6_START 0x140 167ef2ee5d0SMichal Meloun #define AFI_AXI_BAR7_START 0x144 168ef2ee5d0SMichal Meloun #define AFI_AXI_BAR8_START 0x148 169ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR6 0x14c 170ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR7 0x150 171ef2ee5d0SMichal Meloun #define AFI_FPCI_BAR8 0x154 172ef2ee5d0SMichal Meloun #define AFI_PLLE_CONTROL 0x160 173ef2ee5d0SMichal Meloun #define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9) 174ef2ee5d0SMichal Meloun #define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8) 175ef2ee5d0SMichal Meloun #define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1) 176ef2ee5d0SMichal Meloun #define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0) 177ef2ee5d0SMichal Meloun 178ef2ee5d0SMichal Meloun #define AFI_PEXBIAS_CTRL 0x168 179ef2ee5d0SMichal Meloun 180ef2ee5d0SMichal Meloun /* Configuration space */ 181b9cbd68dSMichal Meloun #define RP_VEND_XP 0x0F00 182ef2ee5d0SMichal Meloun #define RP_VEND_XP_DL_UP (1 << 30) 183ef2ee5d0SMichal Meloun 184b9cbd68dSMichal Meloun #define RP_VEND_CTL2 0x0fa8 185b9cbd68dSMichal Meloun #define RP_VEND_CTL2_PCA_ENABLE (1 << 7) 186b9cbd68dSMichal Meloun 187b9cbd68dSMichal Meloun #define RP_PRIV_MISC 0x0FE0 188ef2ee5d0SMichal Meloun #define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0) 189ef2ee5d0SMichal Meloun #define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0) 190ef2ee5d0SMichal Meloun 191b9cbd68dSMichal Meloun #define RP_LINK_CONTROL_STATUS 0x0090 192ef2ee5d0SMichal Meloun #define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 193ef2ee5d0SMichal Meloun #define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 194ef2ee5d0SMichal Meloun 195b9cbd68dSMichal Meloun /* PADS space */ 196b9cbd68dSMichal Meloun #define PADS_REFCLK_CFG0 0x000c8 197b9cbd68dSMichal Meloun #define PADS_REFCLK_CFG1 0x000cc 198b9cbd68dSMichal Meloun 199b9cbd68dSMichal Meloun 200c7533311SMichal Meloun /* Wait 50 ms (per port) for link. */ 201c7533311SMichal Meloun #define TEGRA_PCIE_LINKUP_TIMEOUT 50000 202ef2ee5d0SMichal Meloun 203b9cbd68dSMichal Meloun /* FPCI Address space */ 204b9cbd68dSMichal Meloun #define FPCI_MAP_IO 0xFDFC000000ULL 205b9cbd68dSMichal Meloun #define FPCI_MAP_TYPE0_CONFIG 0xFDFC000000ULL 206b9cbd68dSMichal Meloun #define FPCI_MAP_TYPE1_CONFIG 0xFDFF000000ULL 207b9cbd68dSMichal Meloun #define FPCI_MAP_EXT_TYPE0_CONFIG 0xFE00000000ULL 208b9cbd68dSMichal Meloun #define FPCI_MAP_EXT_TYPE1_CONFIG 0xFE10000000ULL 209b9cbd68dSMichal Meloun 2107709abd1SMichal Meloun #define TEGRA_PCIB_MSI_ENABLE 2117709abd1SMichal Meloun 212ef2ee5d0SMichal Meloun #define DEBUG 213ef2ee5d0SMichal Meloun #ifdef DEBUG 214ef2ee5d0SMichal Meloun #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 215ef2ee5d0SMichal Meloun #else 216ef2ee5d0SMichal Meloun #define debugf(fmt, args...) 217ef2ee5d0SMichal Meloun #endif 218ef2ee5d0SMichal Meloun 219ef2ee5d0SMichal Meloun /* 220ef2ee5d0SMichal Meloun * Configuration space format: 221ef2ee5d0SMichal Meloun * [27:24] extended register 222ef2ee5d0SMichal Meloun * [23:16] bus 223ef2ee5d0SMichal Meloun * [15:11] slot (device) 224ef2ee5d0SMichal Meloun * [10: 8] function 225ef2ee5d0SMichal Meloun * [ 7: 0] register 226ef2ee5d0SMichal Meloun */ 227ef2ee5d0SMichal Meloun #define PCI_CFG_EXT_REG(reg) ((((reg) >> 8) & 0x0f) << 24) 228ef2ee5d0SMichal Meloun #define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) 229ef2ee5d0SMichal Meloun #define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) 230ef2ee5d0SMichal Meloun #define PCI_CFG_FUN(fun) (((fun) & 0x07) << 8) 231ef2ee5d0SMichal Meloun #define PCI_CFG_BASE_REG(reg) ((reg) & 0xff) 232ef2ee5d0SMichal Meloun 233b9cbd68dSMichal Meloun #define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)->pads_mem_res, (_r), (_v)) 234ef2ee5d0SMichal Meloun #define PADS_RD4(_sc, _r) bus_read_4((_sc)->pads_mem_res, (_r)) 235ef2ee5d0SMichal Meloun #define AFI_WR4(_sc, _r, _v) bus_write_4((_sc)->afi_mem_res, (_r), (_v)) 236ef2ee5d0SMichal Meloun #define AFI_RD4(_sc, _r) bus_read_4((_sc)->afi_mem_res, (_r)) 237ef2ee5d0SMichal Meloun 238ef2ee5d0SMichal Meloun static struct { 239ef2ee5d0SMichal Meloun bus_size_t axi_start; 240ef2ee5d0SMichal Meloun bus_size_t fpci_start; 241ef2ee5d0SMichal Meloun bus_size_t size; 242ef2ee5d0SMichal Meloun } bars[] = { 243ef2ee5d0SMichal Meloun {AFI_AXI_BAR0_START, AFI_FPCI_BAR0, AFI_AXI_BAR0_SZ}, /* BAR 0 */ 244ef2ee5d0SMichal Meloun {AFI_AXI_BAR1_START, AFI_FPCI_BAR1, AFI_AXI_BAR1_SZ}, /* BAR 1 */ 245ef2ee5d0SMichal Meloun {AFI_AXI_BAR2_START, AFI_FPCI_BAR2, AFI_AXI_BAR2_SZ}, /* BAR 2 */ 246ef2ee5d0SMichal Meloun {AFI_AXI_BAR3_START, AFI_FPCI_BAR3, AFI_AXI_BAR3_SZ}, /* BAR 3 */ 247ef2ee5d0SMichal Meloun {AFI_AXI_BAR4_START, AFI_FPCI_BAR4, AFI_AXI_BAR4_SZ}, /* BAR 4 */ 248ef2ee5d0SMichal Meloun {AFI_AXI_BAR5_START, AFI_FPCI_BAR5, AFI_AXI_BAR5_SZ}, /* BAR 5 */ 249ef2ee5d0SMichal Meloun {AFI_AXI_BAR6_START, AFI_FPCI_BAR6, AFI_AXI_BAR6_SZ}, /* BAR 6 */ 250ef2ee5d0SMichal Meloun {AFI_AXI_BAR7_START, AFI_FPCI_BAR7, AFI_AXI_BAR7_SZ}, /* BAR 7 */ 251ef2ee5d0SMichal Meloun {AFI_AXI_BAR8_START, AFI_FPCI_BAR8, AFI_AXI_BAR8_SZ}, /* BAR 8 */ 252ef2ee5d0SMichal Meloun {AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ}, /* MSI 9 */ 253ef2ee5d0SMichal Meloun }; 254ef2ee5d0SMichal Meloun 255b9cbd68dSMichal Meloun 256b9cbd68dSMichal Meloun struct pcie_soc { 257b9cbd68dSMichal Meloun char **regulator_names; 258b9cbd68dSMichal Meloun bool cml_clk; 259b9cbd68dSMichal Meloun bool pca_enable; 260b9cbd68dSMichal Meloun uint32_t pads_refclk_cfg0; 261b9cbd68dSMichal Meloun uint32_t pads_refclk_cfg1; 262b9cbd68dSMichal Meloun }; 263b9cbd68dSMichal Meloun 264b9cbd68dSMichal Meloun /* Tegra 124 config. */ 265b9cbd68dSMichal Meloun static char *tegra124_reg_names[] = { 266b9cbd68dSMichal Meloun "avddio-pex-supply", 267b9cbd68dSMichal Meloun "dvddio-pex-supply", 268b9cbd68dSMichal Meloun "avdd-pex-pll-supply", 269b9cbd68dSMichal Meloun "hvdd-pex-supply", 270b9cbd68dSMichal Meloun "hvdd-pex-pll-e-supply", 271b9cbd68dSMichal Meloun "vddio-pex-ctl-supply", 272b9cbd68dSMichal Meloun "avdd-pll-erefe-supply", 273b9cbd68dSMichal Meloun NULL 274b9cbd68dSMichal Meloun }; 275b9cbd68dSMichal Meloun 276b9cbd68dSMichal Meloun static struct pcie_soc tegra124_soc = { 277b9cbd68dSMichal Meloun .regulator_names = tegra124_reg_names, 278b9cbd68dSMichal Meloun .cml_clk = true, 279b9cbd68dSMichal Meloun .pca_enable = false, 280b9cbd68dSMichal Meloun .pads_refclk_cfg0 = 0x44ac44ac, 281b9cbd68dSMichal Meloun }; 282b9cbd68dSMichal Meloun 283b9cbd68dSMichal Meloun /* Tegra 210 config. */ 284b9cbd68dSMichal Meloun static char *tegra210_reg_names[] = { 285b9cbd68dSMichal Meloun "avdd-pll-uerefe-supply", 286b9cbd68dSMichal Meloun "hvddio-pex-supply", 287b9cbd68dSMichal Meloun "dvddio-pex-supply", 288b9cbd68dSMichal Meloun "dvdd-pex-pll-supply", 289b9cbd68dSMichal Meloun "hvdd-pex-pll-e-supply", 290b9cbd68dSMichal Meloun "vddio-pex-ctl-supply", 291b9cbd68dSMichal Meloun NULL 292b9cbd68dSMichal Meloun }; 293b9cbd68dSMichal Meloun 294b9cbd68dSMichal Meloun static struct pcie_soc tegra210_soc = { 295b9cbd68dSMichal Meloun .regulator_names = tegra210_reg_names, 296b9cbd68dSMichal Meloun .cml_clk = true, 297b9cbd68dSMichal Meloun .pca_enable = true, 298b9cbd68dSMichal Meloun .pads_refclk_cfg0 = 0x90b890b8, 299b9cbd68dSMichal Meloun }; 300b9cbd68dSMichal Meloun 301ef2ee5d0SMichal Meloun /* Compatible devices. */ 302ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 303b9cbd68dSMichal Meloun {"nvidia,tegra124-pcie", (uintptr_t)&tegra124_soc}, 304b9cbd68dSMichal Meloun {"nvidia,tegra210-pcie", (uintptr_t)&tegra210_soc}, 305ef2ee5d0SMichal Meloun {NULL, 0}, 306ef2ee5d0SMichal Meloun }; 307ef2ee5d0SMichal Meloun 3087709abd1SMichal Meloun #define TEGRA_FLAG_MSI_USED 0x0001 3097709abd1SMichal Meloun struct tegra_pcib_irqsrc { 3107709abd1SMichal Meloun struct intr_irqsrc isrc; 3117709abd1SMichal Meloun u_int irq; 3127709abd1SMichal Meloun u_int flags; 3137709abd1SMichal Meloun }; 3147709abd1SMichal Meloun 315ef2ee5d0SMichal Meloun struct tegra_pcib_port { 316ef2ee5d0SMichal Meloun int enabled; 317ef2ee5d0SMichal Meloun int port_idx; /* chip port index */ 318ef2ee5d0SMichal Meloun int num_lanes; /* number of lanes */ 319ef2ee5d0SMichal Meloun bus_size_t afi_pex_ctrl; /* offset of afi_pex_ctrl */ 320ee484d5bSOleksandr Tymoshenko phy_t phy; /* port phy */ 321ef2ee5d0SMichal Meloun 322ef2ee5d0SMichal Meloun /* Config space properties. */ 323ef2ee5d0SMichal Meloun bus_addr_t rp_base_addr; /* PA of config window */ 324ef2ee5d0SMichal Meloun bus_size_t rp_size; /* size of config window */ 325ef2ee5d0SMichal Meloun bus_space_handle_t cfg_handle; /* handle of config window */ 326ef2ee5d0SMichal Meloun }; 327ef2ee5d0SMichal Meloun 328ef2ee5d0SMichal Meloun #define TEGRA_PCIB_MAX_PORTS 3 3297709abd1SMichal Meloun #define TEGRA_PCIB_MAX_MSI AFI_MSI_INTR_IN_REG * AFI_MSI_REGS 330ef2ee5d0SMichal Meloun struct tegra_pcib_softc { 33179cceaacSMichal Meloun struct ofw_pci_softc ofw_pci; 332ef2ee5d0SMichal Meloun device_t dev; 333b9cbd68dSMichal Meloun struct pcie_soc *soc; 334ef2ee5d0SMichal Meloun struct mtx mtx; 335ef2ee5d0SMichal Meloun struct resource *pads_mem_res; 336ef2ee5d0SMichal Meloun struct resource *afi_mem_res; 337ef2ee5d0SMichal Meloun struct resource *cfg_mem_res; 338ef2ee5d0SMichal Meloun struct resource *irq_res; 339ef2ee5d0SMichal Meloun struct resource *msi_irq_res; 340ef2ee5d0SMichal Meloun void *intr_cookie; 341ef2ee5d0SMichal Meloun void *msi_intr_cookie; 342ef2ee5d0SMichal Meloun 34379cceaacSMichal Meloun struct ofw_pci_range mem_range; 34479cceaacSMichal Meloun struct ofw_pci_range pref_mem_range; 34579cceaacSMichal Meloun struct ofw_pci_range io_range; 346ef2ee5d0SMichal Meloun 347ef2ee5d0SMichal Meloun clk_t clk_pex; 348ef2ee5d0SMichal Meloun clk_t clk_afi; 349ef2ee5d0SMichal Meloun clk_t clk_pll_e; 350ef2ee5d0SMichal Meloun clk_t clk_cml; 351ef2ee5d0SMichal Meloun hwreset_t hwreset_pex; 352ef2ee5d0SMichal Meloun hwreset_t hwreset_afi; 353ef2ee5d0SMichal Meloun hwreset_t hwreset_pcie_x; 354b9cbd68dSMichal Meloun regulator_t regulators[16]; /* Safe maximum */ 355ef2ee5d0SMichal Meloun 3567709abd1SMichal Meloun vm_offset_t msi_page; /* VA of MSI page */ 357ef2ee5d0SMichal Meloun bus_addr_t cfg_base_addr; /* base address of config */ 358ef2ee5d0SMichal Meloun bus_size_t cfg_cur_offs; /* currently mapped window */ 359ef2ee5d0SMichal Meloun bus_space_handle_t cfg_handle; /* handle of config window */ 360ef2ee5d0SMichal Meloun bus_space_tag_t bus_tag; /* tag of config window */ 361ef2ee5d0SMichal Meloun int lanes_cfg; 362ef2ee5d0SMichal Meloun int num_ports; 363ef2ee5d0SMichal Meloun struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS]; 3647709abd1SMichal Meloun struct tegra_pcib_irqsrc *isrcs; 365ef2ee5d0SMichal Meloun }; 366ef2ee5d0SMichal Meloun 367ef2ee5d0SMichal Meloun static int 368ef2ee5d0SMichal Meloun tegra_pcib_maxslots(device_t dev) 369ef2ee5d0SMichal Meloun { 370ef2ee5d0SMichal Meloun return (16); 371ef2ee5d0SMichal Meloun } 372ef2ee5d0SMichal Meloun 373ef2ee5d0SMichal Meloun static int 374ef2ee5d0SMichal Meloun tegra_pcib_route_interrupt(device_t bus, device_t dev, int pin) 375ef2ee5d0SMichal Meloun { 376ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 3777709abd1SMichal Meloun u_int irq; 378ef2ee5d0SMichal Meloun 379ef2ee5d0SMichal Meloun sc = device_get_softc(bus); 3807709abd1SMichal Meloun irq = intr_map_clone_irq(rman_get_start(sc->irq_res)); 3817709abd1SMichal Meloun device_printf(bus, "route pin %d for device %d.%d to %u\n", 382ef2ee5d0SMichal Meloun pin, pci_get_slot(dev), pci_get_function(dev), 3837709abd1SMichal Meloun irq); 384ef2ee5d0SMichal Meloun 3857709abd1SMichal Meloun return (irq); 386ef2ee5d0SMichal Meloun } 387ef2ee5d0SMichal Meloun 388ef2ee5d0SMichal Meloun static int 389ef2ee5d0SMichal Meloun tegra_pcbib_map_cfg(struct tegra_pcib_softc *sc, u_int bus, u_int slot, 390ef2ee5d0SMichal Meloun u_int func, u_int reg) 391ef2ee5d0SMichal Meloun { 392ef2ee5d0SMichal Meloun bus_size_t offs; 393cb894f74SAndrew Turner int flags, rv; 394ef2ee5d0SMichal Meloun 395ef2ee5d0SMichal Meloun offs = sc->cfg_base_addr; 396ef2ee5d0SMichal Meloun offs |= PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) | 397ef2ee5d0SMichal Meloun PCI_CFG_EXT_REG(reg); 398ef2ee5d0SMichal Meloun if ((sc->cfg_handle != 0) && (sc->cfg_cur_offs == offs)) 399ef2ee5d0SMichal Meloun return (0); 400ef2ee5d0SMichal Meloun if (sc->cfg_handle != 0) 401ef2ee5d0SMichal Meloun bus_space_unmap(sc->bus_tag, sc->cfg_handle, 0x800); 402ef2ee5d0SMichal Meloun 403cb894f74SAndrew Turner #if defined(BUS_SPACE_MAP_NONPOSTED) 404cb894f74SAndrew Turner flags = BUS_SPACE_MAP_NONPOSTED; 405cb894f74SAndrew Turner #else 406cb894f74SAndrew Turner flags = 0; 407cb894f74SAndrew Turner #endif 408cb894f74SAndrew Turner rv = bus_space_map(sc->bus_tag, offs, 0x800, flags, &sc->cfg_handle); 409ef2ee5d0SMichal Meloun if (rv != 0) 410ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot map config space\n"); 411ef2ee5d0SMichal Meloun else 412ef2ee5d0SMichal Meloun sc->cfg_cur_offs = offs; 413ef2ee5d0SMichal Meloun return (rv); 414ef2ee5d0SMichal Meloun } 415ef2ee5d0SMichal Meloun 416ef2ee5d0SMichal Meloun static uint32_t 417ef2ee5d0SMichal Meloun tegra_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 418ef2ee5d0SMichal Meloun u_int reg, int bytes) 419ef2ee5d0SMichal Meloun { 420ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 421ef2ee5d0SMichal Meloun bus_space_handle_t hndl; 422ef2ee5d0SMichal Meloun uint32_t off; 423ef2ee5d0SMichal Meloun uint32_t val; 424ef2ee5d0SMichal Meloun int rv, i; 425ef2ee5d0SMichal Meloun 426ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 427ef2ee5d0SMichal Meloun if (bus == 0) { 428ef2ee5d0SMichal Meloun if (func != 0) 429ef2ee5d0SMichal Meloun return (0xFFFFFFFF); 430ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 431ef2ee5d0SMichal Meloun if ((sc->ports[i] != NULL) && 432ef2ee5d0SMichal Meloun (sc->ports[i]->port_idx == slot)) { 433ef2ee5d0SMichal Meloun hndl = sc->ports[i]->cfg_handle; 434ef2ee5d0SMichal Meloun off = reg & 0xFFF; 435ef2ee5d0SMichal Meloun break; 436ef2ee5d0SMichal Meloun } 437ef2ee5d0SMichal Meloun } 438ef2ee5d0SMichal Meloun if (i >= TEGRA_PCIB_MAX_PORTS) 439ef2ee5d0SMichal Meloun return (0xFFFFFFFF); 440ef2ee5d0SMichal Meloun } else { 441ef2ee5d0SMichal Meloun rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); 442ef2ee5d0SMichal Meloun if (rv != 0) 443ef2ee5d0SMichal Meloun return (0xFFFFFFFF); 444ef2ee5d0SMichal Meloun hndl = sc->cfg_handle; 445ef2ee5d0SMichal Meloun off = PCI_CFG_BASE_REG(reg); 446ef2ee5d0SMichal Meloun } 447ef2ee5d0SMichal Meloun 448ef2ee5d0SMichal Meloun val = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 449ef2ee5d0SMichal Meloun switch (bytes) { 450ef2ee5d0SMichal Meloun case 4: 451ef2ee5d0SMichal Meloun break; 452ef2ee5d0SMichal Meloun case 2: 453ef2ee5d0SMichal Meloun if (off & 3) 454ef2ee5d0SMichal Meloun val >>= 16; 455ef2ee5d0SMichal Meloun val &= 0xffff; 456ef2ee5d0SMichal Meloun break; 457ef2ee5d0SMichal Meloun case 1: 458ef2ee5d0SMichal Meloun val >>= ((off & 3) << 3); 459ef2ee5d0SMichal Meloun val &= 0xff; 460ef2ee5d0SMichal Meloun break; 461ef2ee5d0SMichal Meloun } 462ef2ee5d0SMichal Meloun return val; 463ef2ee5d0SMichal Meloun } 464ef2ee5d0SMichal Meloun 465ef2ee5d0SMichal Meloun static void 466ef2ee5d0SMichal Meloun tegra_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 467ef2ee5d0SMichal Meloun u_int reg, uint32_t val, int bytes) 468ef2ee5d0SMichal Meloun { 469ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 470ef2ee5d0SMichal Meloun bus_space_handle_t hndl; 471ef2ee5d0SMichal Meloun uint32_t off; 472ef2ee5d0SMichal Meloun uint32_t val2; 473ef2ee5d0SMichal Meloun int rv, i; 474ef2ee5d0SMichal Meloun 475ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 476ef2ee5d0SMichal Meloun if (bus == 0) { 477ef2ee5d0SMichal Meloun if (func != 0) 478ef2ee5d0SMichal Meloun return; 479ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 480ef2ee5d0SMichal Meloun if ((sc->ports[i] != NULL) && 481ef2ee5d0SMichal Meloun (sc->ports[i]->port_idx == slot)) { 482ef2ee5d0SMichal Meloun hndl = sc->ports[i]->cfg_handle; 483ef2ee5d0SMichal Meloun off = reg & 0xFFF; 484ef2ee5d0SMichal Meloun break; 485ef2ee5d0SMichal Meloun } 486ef2ee5d0SMichal Meloun } 487ef2ee5d0SMichal Meloun if (i >= TEGRA_PCIB_MAX_PORTS) 488ef2ee5d0SMichal Meloun return; 489ef2ee5d0SMichal Meloun } else { 490ef2ee5d0SMichal Meloun rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); 491ef2ee5d0SMichal Meloun if (rv != 0) 492ef2ee5d0SMichal Meloun return; 493ef2ee5d0SMichal Meloun hndl = sc->cfg_handle; 494ef2ee5d0SMichal Meloun off = PCI_CFG_BASE_REG(reg); 495ef2ee5d0SMichal Meloun } 496ef2ee5d0SMichal Meloun 497ef2ee5d0SMichal Meloun switch (bytes) { 498ef2ee5d0SMichal Meloun case 4: 499ef2ee5d0SMichal Meloun bus_space_write_4(sc->bus_tag, hndl, off, val); 500ef2ee5d0SMichal Meloun break; 501ef2ee5d0SMichal Meloun case 2: 502ef2ee5d0SMichal Meloun val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 503ef2ee5d0SMichal Meloun val2 &= ~(0xffff << ((off & 3) << 3)); 504ef2ee5d0SMichal Meloun val2 |= ((val & 0xffff) << ((off & 3) << 3)); 505ef2ee5d0SMichal Meloun bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); 506ef2ee5d0SMichal Meloun break; 507ef2ee5d0SMichal Meloun case 1: 508ef2ee5d0SMichal Meloun val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 509ef2ee5d0SMichal Meloun val2 &= ~(0xff << ((off & 3) << 3)); 510ef2ee5d0SMichal Meloun val2 |= ((val & 0xff) << ((off & 3) << 3)); 511ef2ee5d0SMichal Meloun bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); 512ef2ee5d0SMichal Meloun break; 513ef2ee5d0SMichal Meloun } 514ef2ee5d0SMichal Meloun } 515ef2ee5d0SMichal Meloun 516ef2ee5d0SMichal Meloun static int tegra_pci_intr(void *arg) 517ef2ee5d0SMichal Meloun { 518ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc = arg; 519ef2ee5d0SMichal Meloun uint32_t code, signature; 520ef2ee5d0SMichal Meloun 521ef2ee5d0SMichal Meloun code = bus_read_4(sc->afi_mem_res, AFI_INTR_CODE) & AFI_INTR_CODE_MASK; 522ef2ee5d0SMichal Meloun signature = bus_read_4(sc->afi_mem_res, AFI_INTR_SIGNATURE); 523ef2ee5d0SMichal Meloun bus_write_4(sc->afi_mem_res, AFI_INTR_CODE, 0); 524ef2ee5d0SMichal Meloun if (code == AFI_INTR_CODE_INT_CODE_SM_MSG) 525ef2ee5d0SMichal Meloun return(FILTER_STRAY); 526ef2ee5d0SMichal Meloun 527ef2ee5d0SMichal Meloun printf("tegra_pci_intr: code %x sig %x\n", code, signature); 528ef2ee5d0SMichal Meloun return (FILTER_HANDLED); 529ef2ee5d0SMichal Meloun } 530ef2ee5d0SMichal Meloun 5317709abd1SMichal Meloun /* ----------------------------------------------------------------------- 5327709abd1SMichal Meloun * 5337709abd1SMichal Meloun * PCI MSI interface 5347709abd1SMichal Meloun */ 535ef2ee5d0SMichal Meloun static int 5367709abd1SMichal Meloun tegra_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount, 5377709abd1SMichal Meloun int *irqs) 538ef2ee5d0SMichal Meloun { 5397709abd1SMichal Meloun phandle_t msi_parent; 540ef2ee5d0SMichal Meloun 5417709abd1SMichal Meloun /* XXXX ofw_bus_msimap() don't works for Tegra DT. 5427709abd1SMichal Meloun ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 5437709abd1SMichal Meloun NULL); 5447709abd1SMichal Meloun */ 5457709abd1SMichal Meloun msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 5467709abd1SMichal Meloun return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 5477709abd1SMichal Meloun irqs)); 548ef2ee5d0SMichal Meloun } 549ef2ee5d0SMichal Meloun 5507709abd1SMichal Meloun static int 5517709abd1SMichal Meloun tegra_pcib_release_msi(device_t pci, device_t child, int count, int *irqs) 5527709abd1SMichal Meloun { 5537709abd1SMichal Meloun phandle_t msi_parent; 554ef2ee5d0SMichal Meloun 5557709abd1SMichal Meloun /* XXXX ofw_bus_msimap() don't works for Tegra DT. 5567709abd1SMichal Meloun ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 5577709abd1SMichal Meloun NULL); 5587709abd1SMichal Meloun */ 5597709abd1SMichal Meloun msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 5607709abd1SMichal Meloun return (intr_release_msi(pci, child, msi_parent, count, irqs)); 5617709abd1SMichal Meloun } 5627709abd1SMichal Meloun 5637709abd1SMichal Meloun static int 5647709abd1SMichal Meloun tegra_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 5657709abd1SMichal Meloun uint32_t *data) 5667709abd1SMichal Meloun { 5677709abd1SMichal Meloun phandle_t msi_parent; 5687709abd1SMichal Meloun 5697709abd1SMichal Meloun /* XXXX ofw_bus_msimap() don't works for Tegra DT. 5707709abd1SMichal Meloun ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 5717709abd1SMichal Meloun NULL); 5727709abd1SMichal Meloun */ 5737709abd1SMichal Meloun msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 5747709abd1SMichal Meloun return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 5757709abd1SMichal Meloun } 5767709abd1SMichal Meloun 5777709abd1SMichal Meloun #ifdef TEGRA_PCIB_MSI_ENABLE 5787709abd1SMichal Meloun 5797709abd1SMichal Meloun /* -------------------------------------------------------------------------- 5807709abd1SMichal Meloun * 5817709abd1SMichal Meloun * Interrupts 5827709abd1SMichal Meloun * 5837709abd1SMichal Meloun */ 5847709abd1SMichal Meloun 5857709abd1SMichal Meloun static inline void 5867709abd1SMichal Meloun tegra_pcib_isrc_mask(struct tegra_pcib_softc *sc, 5877709abd1SMichal Meloun struct tegra_pcib_irqsrc *tgi, uint32_t val) 5887709abd1SMichal Meloun { 5897709abd1SMichal Meloun uint32_t reg; 5907709abd1SMichal Meloun int offs, bit; 5917709abd1SMichal Meloun 5927709abd1SMichal Meloun offs = tgi->irq / AFI_MSI_INTR_IN_REG; 5937709abd1SMichal Meloun bit = 1 << (tgi->irq % AFI_MSI_INTR_IN_REG); 5947709abd1SMichal Meloun 5957709abd1SMichal Meloun if (val != 0) 5967709abd1SMichal Meloun AFI_WR4(sc, AFI_MSI_VEC(offs), bit); 5977709abd1SMichal Meloun reg = AFI_RD4(sc, AFI_MSI_EN_VEC(offs)); 5987709abd1SMichal Meloun if (val != 0) 5997709abd1SMichal Meloun reg |= bit; 6007709abd1SMichal Meloun else 6017709abd1SMichal Meloun reg &= ~bit; 6027709abd1SMichal Meloun AFI_WR4(sc, AFI_MSI_EN_VEC(offs), reg); 6037709abd1SMichal Meloun } 6047709abd1SMichal Meloun 6057709abd1SMichal Meloun static int 6067709abd1SMichal Meloun tegra_pcib_msi_intr(void *arg) 6077709abd1SMichal Meloun { 6087709abd1SMichal Meloun u_int irq, i, bit, reg; 6097709abd1SMichal Meloun struct tegra_pcib_softc *sc; 6107709abd1SMichal Meloun struct trapframe *tf; 6117709abd1SMichal Meloun struct tegra_pcib_irqsrc *tgi; 6127709abd1SMichal Meloun 6137709abd1SMichal Meloun sc = (struct tegra_pcib_softc *)arg; 6147709abd1SMichal Meloun tf = curthread->td_intr_frame; 6157709abd1SMichal Meloun 6167709abd1SMichal Meloun for (i = 0; i < AFI_MSI_REGS; i++) { 6177709abd1SMichal Meloun reg = AFI_RD4(sc, AFI_MSI_VEC(i)); 6187709abd1SMichal Meloun /* Handle one vector. */ 6197709abd1SMichal Meloun while (reg != 0) { 6207709abd1SMichal Meloun bit = ffs(reg) - 1; 6217709abd1SMichal Meloun /* Send EOI */ 6227709abd1SMichal Meloun AFI_WR4(sc, AFI_MSI_VEC(i), 1 << bit); 6237709abd1SMichal Meloun irq = i * AFI_MSI_INTR_IN_REG + bit; 6247709abd1SMichal Meloun tgi = &sc->isrcs[irq]; 6257709abd1SMichal Meloun if (intr_isrc_dispatch(&tgi->isrc, tf) != 0) { 6267709abd1SMichal Meloun /* Disable stray. */ 6277709abd1SMichal Meloun tegra_pcib_isrc_mask(sc, tgi, 0); 6287709abd1SMichal Meloun device_printf(sc->dev, 6297709abd1SMichal Meloun "Stray irq %u disabled\n", irq); 6307709abd1SMichal Meloun } 6317709abd1SMichal Meloun reg = AFI_RD4(sc, AFI_MSI_VEC(i)); 6327709abd1SMichal Meloun } 6337709abd1SMichal Meloun } 6347709abd1SMichal Meloun return (FILTER_HANDLED); 6357709abd1SMichal Meloun } 6367709abd1SMichal Meloun 6377709abd1SMichal Meloun static int 6387709abd1SMichal Meloun tegra_pcib_msi_attach(struct tegra_pcib_softc *sc) 6397709abd1SMichal Meloun { 6407709abd1SMichal Meloun int error; 6417709abd1SMichal Meloun uint32_t irq; 6427709abd1SMichal Meloun const char *name; 6437709abd1SMichal Meloun 6447709abd1SMichal Meloun sc->isrcs = malloc(sizeof(*sc->isrcs) * TEGRA_PCIB_MAX_MSI, M_DEVBUF, 6457709abd1SMichal Meloun M_WAITOK | M_ZERO); 6467709abd1SMichal Meloun 6477709abd1SMichal Meloun name = device_get_nameunit(sc->dev); 6487709abd1SMichal Meloun for (irq = 0; irq < TEGRA_PCIB_MAX_MSI; irq++) { 6497709abd1SMichal Meloun sc->isrcs[irq].irq = irq; 6507709abd1SMichal Meloun error = intr_isrc_register(&sc->isrcs[irq].isrc, 6517709abd1SMichal Meloun sc->dev, 0, "%s,%u", name, irq); 6527709abd1SMichal Meloun if (error != 0) 6537709abd1SMichal Meloun return (error); /* XXX deregister ISRCs */ 6547709abd1SMichal Meloun } 6557709abd1SMichal Meloun if (intr_msi_register(sc->dev, 6567709abd1SMichal Meloun OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0) 6577709abd1SMichal Meloun return (ENXIO); 658ef2ee5d0SMichal Meloun 659ef2ee5d0SMichal Meloun return (0); 660ef2ee5d0SMichal Meloun } 661ef2ee5d0SMichal Meloun 662ef2ee5d0SMichal Meloun static int 6637709abd1SMichal Meloun tegra_pcib_msi_detach(struct tegra_pcib_softc *sc) 6647709abd1SMichal Meloun { 6657709abd1SMichal Meloun 6667709abd1SMichal Meloun /* 6677709abd1SMichal Meloun * There has not been established any procedure yet 6687709abd1SMichal Meloun * how to detach PIC from living system correctly. 6697709abd1SMichal Meloun */ 6707709abd1SMichal Meloun device_printf(sc->dev, "%s: not implemented yet\n", __func__); 6717709abd1SMichal Meloun return (EBUSY); 6727709abd1SMichal Meloun } 6737709abd1SMichal Meloun 6747709abd1SMichal Meloun static void 6757709abd1SMichal Meloun tegra_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc) 676ef2ee5d0SMichal Meloun { 677ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 6787709abd1SMichal Meloun struct tegra_pcib_irqsrc *tgi; 679ef2ee5d0SMichal Meloun 6807709abd1SMichal Meloun sc = device_get_softc(dev); 6817709abd1SMichal Meloun tgi = (struct tegra_pcib_irqsrc *)isrc; 6827709abd1SMichal Meloun tegra_pcib_isrc_mask(sc, tgi, 0); 6837709abd1SMichal Meloun } 6847709abd1SMichal Meloun 6857709abd1SMichal Meloun static void 6867709abd1SMichal Meloun tegra_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc) 6877709abd1SMichal Meloun { 6887709abd1SMichal Meloun struct tegra_pcib_softc *sc; 6897709abd1SMichal Meloun struct tegra_pcib_irqsrc *tgi; 6907709abd1SMichal Meloun 6917709abd1SMichal Meloun sc = device_get_softc(dev); 6927709abd1SMichal Meloun tgi = (struct tegra_pcib_irqsrc *)isrc; 6937709abd1SMichal Meloun tegra_pcib_isrc_mask(sc, tgi, 1); 6947709abd1SMichal Meloun } 6957709abd1SMichal Meloun 6967709abd1SMichal Meloun /* MSI interrupts are edge trigered -> do nothing */ 6977709abd1SMichal Meloun static void 6987709abd1SMichal Meloun tegra_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc) 6997709abd1SMichal Meloun { 7007709abd1SMichal Meloun } 7017709abd1SMichal Meloun 7027709abd1SMichal Meloun static void 7037709abd1SMichal Meloun tegra_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc) 7047709abd1SMichal Meloun { 7057709abd1SMichal Meloun } 7067709abd1SMichal Meloun 7077709abd1SMichal Meloun static void 7087709abd1SMichal Meloun tegra_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 7097709abd1SMichal Meloun { 7107709abd1SMichal Meloun } 7117709abd1SMichal Meloun 7127709abd1SMichal Meloun static int 7137709abd1SMichal Meloun tegra_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc, 7147709abd1SMichal Meloun struct resource *res, struct intr_map_data *data) 7157709abd1SMichal Meloun { 7167709abd1SMichal Meloun if (data == NULL || data->type != INTR_MAP_DATA_MSI) 7177709abd1SMichal Meloun return (ENOTSUP); 7187709abd1SMichal Meloun 7197709abd1SMichal Meloun if (isrc->isrc_handlers == 0) 7207709abd1SMichal Meloun tegra_pcib_msi_enable_intr(dev, isrc); 7217709abd1SMichal Meloun 7227709abd1SMichal Meloun return (0); 7237709abd1SMichal Meloun } 7247709abd1SMichal Meloun 7257709abd1SMichal Meloun static int 7267709abd1SMichal Meloun tegra_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 7277709abd1SMichal Meloun struct resource *res, struct intr_map_data *data) 7287709abd1SMichal Meloun { 7297709abd1SMichal Meloun struct tegra_pcib_softc *sc; 7307709abd1SMichal Meloun struct tegra_pcib_irqsrc *tgi; 7317709abd1SMichal Meloun 7327709abd1SMichal Meloun sc = device_get_softc(dev); 7337709abd1SMichal Meloun tgi = (struct tegra_pcib_irqsrc *)isrc; 7347709abd1SMichal Meloun 7357709abd1SMichal Meloun if (isrc->isrc_handlers == 0) 7367709abd1SMichal Meloun tegra_pcib_isrc_mask(sc, tgi, 0); 7377709abd1SMichal Meloun return (0); 7387709abd1SMichal Meloun } 7397709abd1SMichal Meloun 7407709abd1SMichal Meloun static int 7417709abd1SMichal Meloun tegra_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount, 7427709abd1SMichal Meloun device_t *pic, struct intr_irqsrc **srcs) 7437709abd1SMichal Meloun { 7447709abd1SMichal Meloun struct tegra_pcib_softc *sc; 7457709abd1SMichal Meloun int i, irq, end_irq; 7467709abd1SMichal Meloun bool found; 7477709abd1SMichal Meloun 7487709abd1SMichal Meloun KASSERT(powerof2(count), ("%s: bad count", __func__)); 7497709abd1SMichal Meloun KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__)); 750ef2ee5d0SMichal Meloun 751ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 752ef2ee5d0SMichal Meloun mtx_lock(&sc->mtx); 753ef2ee5d0SMichal Meloun 7547709abd1SMichal Meloun found = false; 755de2929ffSOleksandr Tymoshenko for (irq = 0; (irq + count - 1) < TEGRA_PCIB_MAX_MSI; irq++) { 7567709abd1SMichal Meloun /* Start on an aligned interrupt */ 7577709abd1SMichal Meloun if ((irq & (maxcount - 1)) != 0) 7587709abd1SMichal Meloun continue; 7597709abd1SMichal Meloun 7607709abd1SMichal Meloun /* Assume we found a valid range until shown otherwise */ 7617709abd1SMichal Meloun found = true; 7627709abd1SMichal Meloun 7637709abd1SMichal Meloun /* Check this range is valid */ 764de2929ffSOleksandr Tymoshenko for (end_irq = irq; end_irq < irq + count; end_irq++) { 7657709abd1SMichal Meloun /* This is already used */ 766de2929ffSOleksandr Tymoshenko if ((sc->isrcs[end_irq].flags & TEGRA_FLAG_MSI_USED) == 7677709abd1SMichal Meloun TEGRA_FLAG_MSI_USED) { 7687709abd1SMichal Meloun found = false; 7697709abd1SMichal Meloun break; 7707709abd1SMichal Meloun } 7717709abd1SMichal Meloun } 772de2929ffSOleksandr Tymoshenko 773de2929ffSOleksandr Tymoshenko if (found) 774de2929ffSOleksandr Tymoshenko break; 7757709abd1SMichal Meloun } 7767709abd1SMichal Meloun 7777709abd1SMichal Meloun /* Not enough interrupts were found */ 7787709abd1SMichal Meloun if (!found || irq == (TEGRA_PCIB_MAX_MSI - 1)) { 779ef2ee5d0SMichal Meloun mtx_unlock(&sc->mtx); 780ef2ee5d0SMichal Meloun return (ENXIO); 781ef2ee5d0SMichal Meloun } 782ef2ee5d0SMichal Meloun 7837709abd1SMichal Meloun for (i = 0; i < count; i++) { 7847709abd1SMichal Meloun /* Mark the interrupt as used */ 7857709abd1SMichal Meloun sc->isrcs[irq + i].flags |= TEGRA_FLAG_MSI_USED; 7867709abd1SMichal Meloun } 787ef2ee5d0SMichal Meloun mtx_unlock(&sc->mtx); 7887709abd1SMichal Meloun 7897709abd1SMichal Meloun for (i = 0; i < count; i++) 7907709abd1SMichal Meloun srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i]; 7917709abd1SMichal Meloun *pic = device_get_parent(dev); 792ef2ee5d0SMichal Meloun return (0); 793ef2ee5d0SMichal Meloun } 794ef2ee5d0SMichal Meloun 795ef2ee5d0SMichal Meloun static int 7967709abd1SMichal Meloun tegra_pcib_msi_release_msi(device_t dev, device_t child, int count, 7977709abd1SMichal Meloun struct intr_irqsrc **isrc) 798ef2ee5d0SMichal Meloun { 799ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 8007709abd1SMichal Meloun struct tegra_pcib_irqsrc *ti; 8017709abd1SMichal Meloun int i; 802ef2ee5d0SMichal Meloun 803ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 804ef2ee5d0SMichal Meloun mtx_lock(&sc->mtx); 8057709abd1SMichal Meloun for (i = 0; i < count; i++) { 8065031b2a0SOleksandr Tymoshenko ti = (struct tegra_pcib_irqsrc *)isrc[i]; 807ef2ee5d0SMichal Meloun 8087709abd1SMichal Meloun KASSERT((ti->flags & TEGRA_FLAG_MSI_USED) == TEGRA_FLAG_MSI_USED, 8097709abd1SMichal Meloun ("%s: Trying to release an unused MSI-X interrupt", 8107709abd1SMichal Meloun __func__)); 811ef2ee5d0SMichal Meloun 8127709abd1SMichal Meloun ti->flags &= ~TEGRA_FLAG_MSI_USED; 8137709abd1SMichal Meloun } 8145031b2a0SOleksandr Tymoshenko mtx_unlock(&sc->mtx); 8157709abd1SMichal Meloun return (0); 8167709abd1SMichal Meloun } 8177709abd1SMichal Meloun 8187709abd1SMichal Meloun static int 8197709abd1SMichal Meloun tegra_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 8207709abd1SMichal Meloun uint64_t *addr, uint32_t *data) 8217709abd1SMichal Meloun { 8227709abd1SMichal Meloun struct tegra_pcib_softc *sc = device_get_softc(dev); 8237709abd1SMichal Meloun struct tegra_pcib_irqsrc *ti = (struct tegra_pcib_irqsrc *)isrc; 8247709abd1SMichal Meloun 8257709abd1SMichal Meloun *addr = vtophys(sc->msi_page); 8267709abd1SMichal Meloun *data = ti->irq; 827ef2ee5d0SMichal Meloun return (0); 828ef2ee5d0SMichal Meloun } 829ef2ee5d0SMichal Meloun #endif 830ef2ee5d0SMichal Meloun 8317709abd1SMichal Meloun /* ------------------------------------------------------------------- */ 832ef2ee5d0SMichal Meloun static bus_size_t 833ef2ee5d0SMichal Meloun tegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port) 834ef2ee5d0SMichal Meloun { 8358df71ea1SFerhat Gecdogan switch (port) { 8368df71ea1SFerhat Gecdogan case 0: 837ef2ee5d0SMichal Meloun return (AFI_PEX0_CTRL); 8388df71ea1SFerhat Gecdogan case 1: 839ef2ee5d0SMichal Meloun return (AFI_PEX1_CTRL); 8408df71ea1SFerhat Gecdogan case 2: 841ef2ee5d0SMichal Meloun return (AFI_PEX2_CTRL); 8428df71ea1SFerhat Gecdogan default: 843ef2ee5d0SMichal Meloun panic("invalid port number: %d\n", port); 844ef2ee5d0SMichal Meloun } 8458df71ea1SFerhat Gecdogan } 846ef2ee5d0SMichal Meloun 847ef2ee5d0SMichal Meloun static int 848ef2ee5d0SMichal Meloun tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc) 849ef2ee5d0SMichal Meloun { 850b9cbd68dSMichal Meloun int i, rv; 851ef2ee5d0SMichal Meloun 852ef2ee5d0SMichal Meloun rv = hwreset_assert(sc->hwreset_pcie_x); 853ef2ee5d0SMichal Meloun if (rv != 0) { 854ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot assert 'pcie_x' reset\n"); 855ef2ee5d0SMichal Meloun return (rv); 856ef2ee5d0SMichal Meloun } 857ef2ee5d0SMichal Meloun rv = hwreset_assert(sc->hwreset_afi); 858ef2ee5d0SMichal Meloun if (rv != 0) { 859ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot assert 'afi' reset\n"); 860ef2ee5d0SMichal Meloun return (rv); 861ef2ee5d0SMichal Meloun } 862ef2ee5d0SMichal Meloun rv = hwreset_assert(sc->hwreset_pex); 863ef2ee5d0SMichal Meloun if (rv != 0) { 864ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot assert 'pex' reset\n"); 865ef2ee5d0SMichal Meloun return (rv); 866ef2ee5d0SMichal Meloun } 867ef2ee5d0SMichal Meloun 868ef2ee5d0SMichal Meloun tegra_powergate_power_off(TEGRA_POWERGATE_PCX); 869ef2ee5d0SMichal Meloun 870b9cbd68dSMichal Meloun /* Regulators. */ 871b9cbd68dSMichal Meloun for (i = 0; i < nitems(sc->regulators); i++) { 872b9cbd68dSMichal Meloun if (sc->regulators[i] == NULL) 873b9cbd68dSMichal Meloun continue; 874b9cbd68dSMichal Meloun rv = regulator_enable(sc->regulators[i]); 875ef2ee5d0SMichal Meloun if (rv != 0) { 876ef2ee5d0SMichal Meloun device_printf(sc->dev, 877b9cbd68dSMichal Meloun "Cannot enable '%s' regulator\n", 878b9cbd68dSMichal Meloun sc->soc->regulator_names[i]); 879ef2ee5d0SMichal Meloun return (rv); 880ef2ee5d0SMichal Meloun } 881ef2ee5d0SMichal Meloun } 882ef2ee5d0SMichal Meloun 883ef2ee5d0SMichal Meloun rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX, 884ef2ee5d0SMichal Meloun sc->clk_pex, sc->hwreset_pex); 885ef2ee5d0SMichal Meloun if (rv != 0) { 886ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'PCX' powergate\n"); 887ef2ee5d0SMichal Meloun return (rv); 888ef2ee5d0SMichal Meloun } 889ef2ee5d0SMichal Meloun 890ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->hwreset_afi); 891ef2ee5d0SMichal Meloun if (rv != 0) { 892ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot unreset 'afi' reset\n"); 893ef2ee5d0SMichal Meloun return (rv); 894ef2ee5d0SMichal Meloun } 895ef2ee5d0SMichal Meloun 896ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_afi); 897ef2ee5d0SMichal Meloun if (rv != 0) { 898ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'afi' clock\n"); 899ef2ee5d0SMichal Meloun return (rv); 900ef2ee5d0SMichal Meloun } 901b9cbd68dSMichal Meloun if (sc->soc->cml_clk) { 902ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_cml); 903ef2ee5d0SMichal Meloun if (rv != 0) { 904ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'cml' clock\n"); 905ef2ee5d0SMichal Meloun return (rv); 906ef2ee5d0SMichal Meloun } 907b9cbd68dSMichal Meloun } 908ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk_pll_e); 909ef2ee5d0SMichal Meloun if (rv != 0) { 910ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable 'pll_e' clock\n"); 911ef2ee5d0SMichal Meloun return (rv); 912ef2ee5d0SMichal Meloun } 913b9cbd68dSMichal Meloun 914ef2ee5d0SMichal Meloun return (0); 915ef2ee5d0SMichal Meloun } 916ef2ee5d0SMichal Meloun 917ef2ee5d0SMichal Meloun static struct tegra_pcib_port * 918ef2ee5d0SMichal Meloun tegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node) 919ef2ee5d0SMichal Meloun { 920ef2ee5d0SMichal Meloun struct tegra_pcib_port *port; 921ef2ee5d0SMichal Meloun uint32_t tmp[5]; 922ef2ee5d0SMichal Meloun char tmpstr[6]; 923ef2ee5d0SMichal Meloun int rv; 924ef2ee5d0SMichal Meloun 925ef2ee5d0SMichal Meloun port = malloc(sizeof(struct tegra_pcib_port), M_DEVBUF, M_WAITOK); 926ef2ee5d0SMichal Meloun 927ef2ee5d0SMichal Meloun rv = OF_getprop(node, "status", tmpstr, sizeof(tmpstr)); 928ef2ee5d0SMichal Meloun if (rv <= 0 || strcmp(tmpstr, "okay") == 0 || 929ef2ee5d0SMichal Meloun strcmp(tmpstr, "ok") == 0) 930ef2ee5d0SMichal Meloun port->enabled = 1; 931ef2ee5d0SMichal Meloun else 932ef2ee5d0SMichal Meloun port->enabled = 0; 933ef2ee5d0SMichal Meloun 934ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "assigned-addresses", tmp, sizeof(tmp)); 935ef2ee5d0SMichal Meloun if (rv != sizeof(tmp)) { 936ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot parse assigned-address: %d\n", 937ef2ee5d0SMichal Meloun rv); 938ef2ee5d0SMichal Meloun goto fail; 939ef2ee5d0SMichal Meloun } 940ef2ee5d0SMichal Meloun port->rp_base_addr = tmp[2]; 941ef2ee5d0SMichal Meloun port->rp_size = tmp[4]; 942ef2ee5d0SMichal Meloun port->port_idx = OFW_PCI_PHYS_HI_DEVICE(tmp[0]) - 1; 943ef2ee5d0SMichal Meloun if (port->port_idx >= TEGRA_PCIB_MAX_PORTS) { 944ef2ee5d0SMichal Meloun device_printf(sc->dev, "Invalid port index: %d\n", 945ef2ee5d0SMichal Meloun port->port_idx); 946ef2ee5d0SMichal Meloun goto fail; 947ef2ee5d0SMichal Meloun } 948ef2ee5d0SMichal Meloun /* XXX - TODO: 949ef2ee5d0SMichal Meloun * Implement proper function for parsing pci "reg" property: 950ef2ee5d0SMichal Meloun * - it have PCI bus format 951ef2ee5d0SMichal Meloun * - its relative to matching "assigned-addresses" 952ef2ee5d0SMichal Meloun */ 953ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "reg", tmp, sizeof(tmp)); 954ef2ee5d0SMichal Meloun if (rv != sizeof(tmp)) { 955ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot parse reg: %d\n", rv); 956ef2ee5d0SMichal Meloun goto fail; 957ef2ee5d0SMichal Meloun } 958ef2ee5d0SMichal Meloun port->rp_base_addr += tmp[2]; 959ef2ee5d0SMichal Meloun 960ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,num-lanes", &port->num_lanes, 961ef2ee5d0SMichal Meloun sizeof(port->num_lanes)); 962ef2ee5d0SMichal Meloun if (rv != sizeof(port->num_lanes)) { 963ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot parse nvidia,num-lanes: %d\n", 964ef2ee5d0SMichal Meloun rv); 965ef2ee5d0SMichal Meloun goto fail; 966ef2ee5d0SMichal Meloun } 967ef2ee5d0SMichal Meloun if (port->num_lanes > 4) { 968ef2ee5d0SMichal Meloun device_printf(sc->dev, "Invalid nvidia,num-lanes: %d\n", 969ef2ee5d0SMichal Meloun port->num_lanes); 970ef2ee5d0SMichal Meloun goto fail; 971ef2ee5d0SMichal Meloun } 972ef2ee5d0SMichal Meloun 973ef2ee5d0SMichal Meloun port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx); 974ef2ee5d0SMichal Meloun sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx); 975ef2ee5d0SMichal Meloun 976ee484d5bSOleksandr Tymoshenko /* Phy. */ 977ee484d5bSOleksandr Tymoshenko rv = phy_get_by_ofw_name(sc->dev, node, "pcie-0", &port->phy); 978ee484d5bSOleksandr Tymoshenko if (rv != 0) { 979ee484d5bSOleksandr Tymoshenko device_printf(sc->dev, 980ee484d5bSOleksandr Tymoshenko "Cannot get 'pcie-0' phy for port %d\n", 981ee484d5bSOleksandr Tymoshenko port->port_idx); 982ee484d5bSOleksandr Tymoshenko goto fail; 983ee484d5bSOleksandr Tymoshenko } 984ee484d5bSOleksandr Tymoshenko 985ef2ee5d0SMichal Meloun return (port); 986ef2ee5d0SMichal Meloun fail: 987ef2ee5d0SMichal Meloun free(port, M_DEVBUF); 988ef2ee5d0SMichal Meloun return (NULL); 989ef2ee5d0SMichal Meloun } 990ef2ee5d0SMichal Meloun 991ef2ee5d0SMichal Meloun static int 992ef2ee5d0SMichal Meloun tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node) 993ef2ee5d0SMichal Meloun { 994ef2ee5d0SMichal Meloun phandle_t child; 995ef2ee5d0SMichal Meloun struct tegra_pcib_port *port; 996b9cbd68dSMichal Meloun int i, rv; 997ef2ee5d0SMichal Meloun 998b9cbd68dSMichal Meloun /* Regulators. */ 999b9cbd68dSMichal Meloun for (i = 0; sc->soc->regulator_names[i] != NULL; i++) { 1000b9cbd68dSMichal Meloun if (i >= nitems(sc->regulators)) { 1001b9cbd68dSMichal Meloun device_printf(sc->dev, 1002b9cbd68dSMichal Meloun "Too many regulators present in DT.\n"); 1003b9cbd68dSMichal Meloun return (EOVERFLOW); 1004b9cbd68dSMichal Meloun } 1005b9cbd68dSMichal Meloun rv = regulator_get_by_ofw_property(sc->dev, 0, 1006b9cbd68dSMichal Meloun sc->soc->regulator_names[i], sc->regulators + i); 1007ef2ee5d0SMichal Meloun if (rv != 0) { 1008ef2ee5d0SMichal Meloun device_printf(sc->dev, 1009b9cbd68dSMichal Meloun "Cannot get '%s' regulator\n", 1010b9cbd68dSMichal Meloun sc->soc->regulator_names[i]); 1011ef2ee5d0SMichal Meloun return (ENXIO); 1012ef2ee5d0SMichal Meloun } 1013ef2ee5d0SMichal Meloun } 1014ef2ee5d0SMichal Meloun 1015ef2ee5d0SMichal Meloun /* Resets. */ 1016dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "pex", &sc->hwreset_pex); 1017ef2ee5d0SMichal Meloun if (rv != 0) { 1018ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'pex' reset\n"); 1019ef2ee5d0SMichal Meloun return (ENXIO); 1020ef2ee5d0SMichal Meloun } 1021dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "afi", &sc->hwreset_afi); 1022ef2ee5d0SMichal Meloun if (rv != 0) { 1023ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'afi' reset\n"); 1024ef2ee5d0SMichal Meloun return (ENXIO); 1025ef2ee5d0SMichal Meloun } 1026dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "pcie_x", &sc->hwreset_pcie_x); 1027ef2ee5d0SMichal Meloun if (rv != 0) { 1028ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'pcie_x' reset\n"); 1029ef2ee5d0SMichal Meloun return (ENXIO); 1030ef2ee5d0SMichal Meloun } 1031ef2ee5d0SMichal Meloun 1032ef2ee5d0SMichal Meloun /* Clocks. */ 1033dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "pex", &sc->clk_pex); 1034ef2ee5d0SMichal Meloun if (rv != 0) { 1035ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'pex' clock\n"); 1036ef2ee5d0SMichal Meloun return (ENXIO); 1037ef2ee5d0SMichal Meloun } 1038dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "afi", &sc->clk_afi); 1039ef2ee5d0SMichal Meloun if (rv != 0) { 1040ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'afi' clock\n"); 1041ef2ee5d0SMichal Meloun return (ENXIO); 1042ef2ee5d0SMichal Meloun } 1043dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "pll_e", &sc->clk_pll_e); 1044ef2ee5d0SMichal Meloun if (rv != 0) { 1045ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'pll_e' clock\n"); 1046ef2ee5d0SMichal Meloun return (ENXIO); 1047ef2ee5d0SMichal Meloun } 1048b9cbd68dSMichal Meloun if (sc->soc->cml_clk) { 1049dac93553SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "cml", &sc->clk_cml); 1050ef2ee5d0SMichal Meloun if (rv != 0) { 1051ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get 'cml' clock\n"); 1052ef2ee5d0SMichal Meloun return (ENXIO); 1053ef2ee5d0SMichal Meloun } 1054b9cbd68dSMichal Meloun } 1055ef2ee5d0SMichal Meloun 1056ef2ee5d0SMichal Meloun /* Ports */ 1057ef2ee5d0SMichal Meloun sc->num_ports = 0; 1058ef2ee5d0SMichal Meloun for (child = OF_child(node); child != 0; child = OF_peer(child)) { 1059ef2ee5d0SMichal Meloun port = tegra_pcib_parse_port(sc, child); 1060ef2ee5d0SMichal Meloun if (port == NULL) { 1061ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot parse PCIe port node\n"); 1062ef2ee5d0SMichal Meloun return (ENXIO); 1063ef2ee5d0SMichal Meloun } 1064ef2ee5d0SMichal Meloun sc->ports[sc->num_ports++] = port; 1065ef2ee5d0SMichal Meloun } 1066ef2ee5d0SMichal Meloun 1067ef2ee5d0SMichal Meloun return (0); 1068ef2ee5d0SMichal Meloun } 1069ef2ee5d0SMichal Meloun 1070ef2ee5d0SMichal Meloun static int 1071ef2ee5d0SMichal Meloun tegra_pcib_decode_ranges(struct tegra_pcib_softc *sc, 107279cceaacSMichal Meloun struct ofw_pci_range *ranges, int nranges) 1073ef2ee5d0SMichal Meloun { 1074ef2ee5d0SMichal Meloun int i; 1075ef2ee5d0SMichal Meloun 1076ef2ee5d0SMichal Meloun for (i = 2; i < nranges; i++) { 107779cceaacSMichal Meloun if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 107879cceaacSMichal Meloun OFW_PCI_PHYS_HI_SPACE_IO) { 1079ef2ee5d0SMichal Meloun if (sc->io_range.size != 0) { 1080ef2ee5d0SMichal Meloun device_printf(sc->dev, 1081ef2ee5d0SMichal Meloun "Duplicated IO range found in DT\n"); 1082ef2ee5d0SMichal Meloun return (ENXIO); 1083ef2ee5d0SMichal Meloun } 1084ef2ee5d0SMichal Meloun sc->io_range = ranges[i]; 1085ef2ee5d0SMichal Meloun } 108679cceaacSMichal Meloun if (((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == 108779cceaacSMichal Meloun OFW_PCI_PHYS_HI_SPACE_MEM32)) { 108879cceaacSMichal Meloun if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { 108979cceaacSMichal Meloun if (sc->pref_mem_range.size != 0) { 109079cceaacSMichal Meloun device_printf(sc->dev, 109179cceaacSMichal Meloun "Duplicated memory range found " 109279cceaacSMichal Meloun "in DT\n"); 109379cceaacSMichal Meloun return (ENXIO); 109479cceaacSMichal Meloun } 109579cceaacSMichal Meloun sc->pref_mem_range = ranges[i]; 109679cceaacSMichal Meloun } else { 1097ef2ee5d0SMichal Meloun if (sc->mem_range.size != 0) { 1098ef2ee5d0SMichal Meloun device_printf(sc->dev, 109979cceaacSMichal Meloun "Duplicated memory range found " 110079cceaacSMichal Meloun "in DT\n"); 1101ef2ee5d0SMichal Meloun return (ENXIO); 1102ef2ee5d0SMichal Meloun } 1103ef2ee5d0SMichal Meloun sc->mem_range = ranges[i]; 1104ef2ee5d0SMichal Meloun } 1105ef2ee5d0SMichal Meloun } 1106ef2ee5d0SMichal Meloun } 1107ef2ee5d0SMichal Meloun if ((sc->io_range.size == 0) || (sc->mem_range.size == 0) 1108ef2ee5d0SMichal Meloun || (sc->pref_mem_range.size == 0)) { 1109ef2ee5d0SMichal Meloun device_printf(sc->dev, 1110ef2ee5d0SMichal Meloun " Not all required ranges are found in DT\n"); 1111ef2ee5d0SMichal Meloun return (ENXIO); 1112ef2ee5d0SMichal Meloun } 1113ef2ee5d0SMichal Meloun return (0); 1114ef2ee5d0SMichal Meloun } 1115ef2ee5d0SMichal Meloun 1116ef2ee5d0SMichal Meloun /* 1117ef2ee5d0SMichal Meloun * Hardware config. 1118ef2ee5d0SMichal Meloun */ 1119ef2ee5d0SMichal Meloun static int 1120ef2ee5d0SMichal Meloun tegra_pcib_wait_for_link(struct tegra_pcib_softc *sc, 1121ef2ee5d0SMichal Meloun struct tegra_pcib_port *port) 1122ef2ee5d0SMichal Meloun { 1123ef2ee5d0SMichal Meloun uint32_t reg; 1124ef2ee5d0SMichal Meloun int i; 1125ef2ee5d0SMichal Meloun 1126ef2ee5d0SMichal Meloun /* Setup link detection. */ 1127ef2ee5d0SMichal Meloun reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1128ef2ee5d0SMichal Meloun RP_PRIV_MISC, 4); 1129ef2ee5d0SMichal Meloun reg &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT; 1130ef2ee5d0SMichal Meloun reg |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT; 1131ef2ee5d0SMichal Meloun tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0, 1132ef2ee5d0SMichal Meloun RP_PRIV_MISC, reg, 4); 1133ef2ee5d0SMichal Meloun 1134ef2ee5d0SMichal Meloun for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { 1135ef2ee5d0SMichal Meloun reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1136ef2ee5d0SMichal Meloun RP_VEND_XP, 4); 1137ef2ee5d0SMichal Meloun if (reg & RP_VEND_XP_DL_UP) 1138ef2ee5d0SMichal Meloun break; 1139c7533311SMichal Meloun DELAY(1); 1140ef2ee5d0SMichal Meloun } 1141ef2ee5d0SMichal Meloun if (i <= 0) 1142ef2ee5d0SMichal Meloun return (ETIMEDOUT); 1143ef2ee5d0SMichal Meloun 1144ef2ee5d0SMichal Meloun for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { 1145ef2ee5d0SMichal Meloun reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1146ef2ee5d0SMichal Meloun RP_LINK_CONTROL_STATUS, 4); 1147ef2ee5d0SMichal Meloun if (reg & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) 1148ef2ee5d0SMichal Meloun break; 1149ef2ee5d0SMichal Meloun 1150c7533311SMichal Meloun DELAY(1); 1151ef2ee5d0SMichal Meloun } 1152ef2ee5d0SMichal Meloun if (i <= 0) 1153ef2ee5d0SMichal Meloun return (ETIMEDOUT); 1154ef2ee5d0SMichal Meloun return (0); 1155ef2ee5d0SMichal Meloun } 1156ef2ee5d0SMichal Meloun 1157ef2ee5d0SMichal Meloun static void 1158ef2ee5d0SMichal Meloun tegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num) 1159ef2ee5d0SMichal Meloun { 1160ef2ee5d0SMichal Meloun struct tegra_pcib_port *port; 1161ef2ee5d0SMichal Meloun uint32_t reg; 1162ef2ee5d0SMichal Meloun int rv; 1163ef2ee5d0SMichal Meloun 1164ef2ee5d0SMichal Meloun port = sc->ports[port_num]; 1165ef2ee5d0SMichal Meloun 1166ef2ee5d0SMichal Meloun /* Put port to reset. */ 1167ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, port->afi_pex_ctrl); 1168ef2ee5d0SMichal Meloun reg &= ~AFI_PEX_CTRL_RST_L; 1169ef2ee5d0SMichal Meloun AFI_WR4(sc, port->afi_pex_ctrl, reg); 1170ef2ee5d0SMichal Meloun AFI_RD4(sc, port->afi_pex_ctrl); 1171ef2ee5d0SMichal Meloun DELAY(10); 1172ef2ee5d0SMichal Meloun 1173ef2ee5d0SMichal Meloun /* Enable clocks. */ 1174ef2ee5d0SMichal Meloun reg |= AFI_PEX_CTRL_REFCLK_EN; 1175ef2ee5d0SMichal Meloun reg |= AFI_PEX_CTRL_CLKREQ_EN; 1176ef2ee5d0SMichal Meloun reg |= AFI_PEX_CTRL_OVERRIDE_EN; 1177ef2ee5d0SMichal Meloun AFI_WR4(sc, port->afi_pex_ctrl, reg); 1178ef2ee5d0SMichal Meloun AFI_RD4(sc, port->afi_pex_ctrl); 1179ef2ee5d0SMichal Meloun DELAY(100); 1180ef2ee5d0SMichal Meloun 1181ef2ee5d0SMichal Meloun /* Release reset. */ 1182ef2ee5d0SMichal Meloun reg |= AFI_PEX_CTRL_RST_L; 1183ef2ee5d0SMichal Meloun AFI_WR4(sc, port->afi_pex_ctrl, reg); 1184ef2ee5d0SMichal Meloun 1185b9cbd68dSMichal Meloun if (sc->soc->pca_enable) { 1186b9cbd68dSMichal Meloun reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1187b9cbd68dSMichal Meloun RP_VEND_CTL2, 4); 1188b9cbd68dSMichal Meloun reg |= RP_VEND_CTL2_PCA_ENABLE; 1189b9cbd68dSMichal Meloun tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0, 1190b9cbd68dSMichal Meloun RP_VEND_CTL2, reg, 4); 1191b9cbd68dSMichal Meloun } 1192b9cbd68dSMichal Meloun 1193ef2ee5d0SMichal Meloun rv = tegra_pcib_wait_for_link(sc, port); 1194ef2ee5d0SMichal Meloun if (bootverbose) 1195ef2ee5d0SMichal Meloun device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n", 1196ef2ee5d0SMichal Meloun port->port_idx, port->num_lanes, 1197ef2ee5d0SMichal Meloun port->num_lanes > 1 ? "s": "", 1198ef2ee5d0SMichal Meloun rv == 0 ? "up": "down"); 1199ef2ee5d0SMichal Meloun } 1200ef2ee5d0SMichal Meloun 1201ef2ee5d0SMichal Meloun static void 1202ef2ee5d0SMichal Meloun tegra_pcib_port_disable(struct tegra_pcib_softc *sc, uint32_t port_num) 1203ef2ee5d0SMichal Meloun { 1204ef2ee5d0SMichal Meloun struct tegra_pcib_port *port; 1205ef2ee5d0SMichal Meloun uint32_t reg; 1206ef2ee5d0SMichal Meloun 1207ef2ee5d0SMichal Meloun port = sc->ports[port_num]; 1208ef2ee5d0SMichal Meloun 1209ef2ee5d0SMichal Meloun /* Put port to reset. */ 1210ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, port->afi_pex_ctrl); 1211ef2ee5d0SMichal Meloun reg &= ~AFI_PEX_CTRL_RST_L; 1212ef2ee5d0SMichal Meloun AFI_WR4(sc, port->afi_pex_ctrl, reg); 1213ef2ee5d0SMichal Meloun AFI_RD4(sc, port->afi_pex_ctrl); 1214ef2ee5d0SMichal Meloun DELAY(10); 1215ef2ee5d0SMichal Meloun 1216ef2ee5d0SMichal Meloun /* Disable clocks. */ 1217ef2ee5d0SMichal Meloun reg &= ~AFI_PEX_CTRL_CLKREQ_EN; 1218ef2ee5d0SMichal Meloun reg &= ~AFI_PEX_CTRL_REFCLK_EN; 1219ef2ee5d0SMichal Meloun AFI_WR4(sc, port->afi_pex_ctrl, reg); 1220ef2ee5d0SMichal Meloun 1221ef2ee5d0SMichal Meloun if (bootverbose) 1222ef2ee5d0SMichal Meloun device_printf(sc->dev, " port %d (%d lane%s): Disabled\n", 1223ef2ee5d0SMichal Meloun port->port_idx, port->num_lanes, 1224ef2ee5d0SMichal Meloun port->num_lanes > 1 ? "s": ""); 1225ef2ee5d0SMichal Meloun } 1226ef2ee5d0SMichal Meloun 1227ef2ee5d0SMichal Meloun static void 1228ef2ee5d0SMichal Meloun tegra_pcib_set_bar(struct tegra_pcib_softc *sc, int bar, uint32_t axi, 1229ef2ee5d0SMichal Meloun uint64_t fpci, uint32_t size, int is_memory) 1230ef2ee5d0SMichal Meloun { 1231ef2ee5d0SMichal Meloun uint32_t fpci_reg; 1232ef2ee5d0SMichal Meloun uint32_t axi_reg; 1233ef2ee5d0SMichal Meloun uint32_t size_reg; 1234ef2ee5d0SMichal Meloun 1235ef2ee5d0SMichal Meloun axi_reg = axi & ~0xFFF; 1236ef2ee5d0SMichal Meloun size_reg = size >> 12; 1237ef2ee5d0SMichal Meloun fpci_reg = (uint32_t)(fpci >> 8) & ~0xF; 1238ef2ee5d0SMichal Meloun fpci_reg |= is_memory ? 0x1 : 0x0; 1239ef2ee5d0SMichal Meloun AFI_WR4(sc, bars[bar].axi_start, axi_reg); 1240ef2ee5d0SMichal Meloun AFI_WR4(sc, bars[bar].size, size_reg); 1241ef2ee5d0SMichal Meloun AFI_WR4(sc, bars[bar].fpci_start, fpci_reg); 1242ef2ee5d0SMichal Meloun } 1243ef2ee5d0SMichal Meloun 1244ef2ee5d0SMichal Meloun static int 124504d18df9SAndrew Turner tegra_pcib_enable(struct tegra_pcib_softc *sc) 1246ef2ee5d0SMichal Meloun { 1247ef2ee5d0SMichal Meloun int rv; 1248ef2ee5d0SMichal Meloun int i; 1249ef2ee5d0SMichal Meloun uint32_t reg; 1250ef2ee5d0SMichal Meloun 1251ef2ee5d0SMichal Meloun rv = tegra_pcib_enable_fdt_resources(sc); 1252ef2ee5d0SMichal Meloun if (rv != 0) { 1253ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot enable FDT resources\n"); 1254ef2ee5d0SMichal Meloun return (rv); 1255ef2ee5d0SMichal Meloun } 1256b9cbd68dSMichal Meloun 1257ef2ee5d0SMichal Meloun /* Enable PLLE control. */ 1258ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, AFI_PLLE_CONTROL); 1259ef2ee5d0SMichal Meloun reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; 1260ef2ee5d0SMichal Meloun reg |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; 1261ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_PLLE_CONTROL, reg); 1262ef2ee5d0SMichal Meloun 1263ef2ee5d0SMichal Meloun /* Set bias pad. */ 1264ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_PEXBIAS_CTRL, 0); 1265ef2ee5d0SMichal Meloun 1266ef2ee5d0SMichal Meloun /* Configure mode and ports. */ 1267ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, AFI_PCIE_CONFIG); 1268ef2ee5d0SMichal Meloun reg &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; 1269ef2ee5d0SMichal Meloun if (sc->lanes_cfg == 0x14) { 1270ef2ee5d0SMichal Meloun if (bootverbose) 1271ef2ee5d0SMichal Meloun device_printf(sc->dev, 1272ef2ee5d0SMichal Meloun "Using x1,x4 configuration\n"); 1273ef2ee5d0SMichal Meloun reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1; 1274ef2ee5d0SMichal Meloun } else if (sc->lanes_cfg == 0x12) { 1275ef2ee5d0SMichal Meloun if (bootverbose) 1276ef2ee5d0SMichal Meloun device_printf(sc->dev, 1277ef2ee5d0SMichal Meloun "Using x1,x2 configuration\n"); 1278ef2ee5d0SMichal Meloun reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1; 1279ef2ee5d0SMichal Meloun } else { 1280ef2ee5d0SMichal Meloun device_printf(sc->dev, 1281ef2ee5d0SMichal Meloun "Unsupported lanes configuration: 0x%X\n", sc->lanes_cfg); 1282ef2ee5d0SMichal Meloun } 1283ef2ee5d0SMichal Meloun reg |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL; 1284ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1285ef2ee5d0SMichal Meloun if ((sc->ports[i] != NULL)) 1286ef2ee5d0SMichal Meloun reg &= 1287ef2ee5d0SMichal Meloun ~AFI_PCIE_CONFIG_PCIE_DISABLE(sc->ports[i]->port_idx); 1288ef2ee5d0SMichal Meloun } 1289ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_PCIE_CONFIG, reg); 1290ef2ee5d0SMichal Meloun 1291ef2ee5d0SMichal Meloun /* Enable Gen2 support. */ 1292ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, AFI_FUSE); 1293ef2ee5d0SMichal Meloun reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; 1294ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_FUSE, reg); 1295ef2ee5d0SMichal Meloun 1296ee484d5bSOleksandr Tymoshenko for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1297ee484d5bSOleksandr Tymoshenko if (sc->ports[i] != NULL) { 1298f8759facSMichal Meloun rv = phy_enable(sc->ports[i]->phy); 1299ef2ee5d0SMichal Meloun if (rv != 0) { 1300ee484d5bSOleksandr Tymoshenko device_printf(sc->dev, 1301ee484d5bSOleksandr Tymoshenko "Cannot enable phy for port %d\n", 1302ee484d5bSOleksandr Tymoshenko sc->ports[i]->port_idx); 1303ef2ee5d0SMichal Meloun return (rv); 1304ef2ee5d0SMichal Meloun } 1305ee484d5bSOleksandr Tymoshenko } 1306ee484d5bSOleksandr Tymoshenko } 1307ee484d5bSOleksandr Tymoshenko 1308b9cbd68dSMichal Meloun /* Configure PCIe reference clock */ 1309b9cbd68dSMichal Meloun PADS_WR4(sc, PADS_REFCLK_CFG0, sc->soc->pads_refclk_cfg0); 1310b9cbd68dSMichal Meloun if (sc->num_ports > 2) 1311b9cbd68dSMichal Meloun PADS_WR4(sc, PADS_REFCLK_CFG1, sc->soc->pads_refclk_cfg1); 1312b9cbd68dSMichal Meloun 1313ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->hwreset_pcie_x); 1314ef2ee5d0SMichal Meloun if (rv != 0) { 1315ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n"); 1316ef2ee5d0SMichal Meloun return (rv); 1317ef2ee5d0SMichal Meloun } 1318ef2ee5d0SMichal Meloun 1319ef2ee5d0SMichal Meloun /* Enable config space. */ 1320ef2ee5d0SMichal Meloun reg = AFI_RD4(sc, AFI_CONFIGURATION); 1321ef2ee5d0SMichal Meloun reg |= AFI_CONFIGURATION_EN_FPCI; 1322ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_CONFIGURATION, reg); 1323ef2ee5d0SMichal Meloun 1324ef2ee5d0SMichal Meloun /* Enable AFI errors. */ 1325ef2ee5d0SMichal Meloun reg = 0; 1326ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_SLVERR); 1327ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_DECERR); 1328ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_SLVERR); 1329ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_DECERR); 1330ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_WRERR); 1331ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_SM_MSG); 1332ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_DFPCI_DECERR); 1333ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_AXI_DECERR); 1334ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT); 1335ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE); 1336ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE); 1337ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE); 1338ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE); 1339ef2ee5d0SMichal Meloun reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_P2P_ERROR); 1340ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_AFI_INTR_ENABLE, reg); 1341ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_SM_INTR_ENABLE, 0xffffffff); 1342ef2ee5d0SMichal Meloun 1343ef2ee5d0SMichal Meloun /* Enable INT, disable MSI. */ 1344ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_INTR_MASK, AFI_INTR_MASK_INT_MASK); 1345ef2ee5d0SMichal Meloun 1346ef2ee5d0SMichal Meloun /* Mask all FPCI errors. */ 1347ef2ee5d0SMichal Meloun AFI_WR4(sc, AFI_FPCI_ERROR_MASKS, 0); 1348ef2ee5d0SMichal Meloun 1349ef2ee5d0SMichal Meloun /* Setup AFI translation windows. */ 1350ef2ee5d0SMichal Meloun /* BAR 0 - type 1 extended configuration. */ 1351ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 0, rman_get_start(sc->cfg_mem_res), 1352ef2ee5d0SMichal Meloun FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0); 1353ef2ee5d0SMichal Meloun 1354ef2ee5d0SMichal Meloun /* BAR 1 - downstream I/O. */ 135579cceaacSMichal Meloun tegra_pcib_set_bar(sc, 1, sc->io_range.host, FPCI_MAP_IO, 1356ef2ee5d0SMichal Meloun sc->io_range.size, 0); 1357ef2ee5d0SMichal Meloun 1358ef2ee5d0SMichal Meloun /* BAR 2 - downstream prefetchable memory 1:1. */ 135979cceaacSMichal Meloun tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host, 136079cceaacSMichal Meloun sc->pref_mem_range.host, sc->pref_mem_range.size, 1); 1361ef2ee5d0SMichal Meloun 1362ef2ee5d0SMichal Meloun /* BAR 3 - downstream not prefetchable memory 1:1 .*/ 136379cceaacSMichal Meloun tegra_pcib_set_bar(sc, 3, sc->mem_range.host, 136479cceaacSMichal Meloun sc->mem_range.host, sc->mem_range.size, 1); 1365ef2ee5d0SMichal Meloun 1366ef2ee5d0SMichal Meloun /* BAR 3-8 clear. */ 1367ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0); 1368ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 5, 0, 0, 0, 0); 1369ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 6, 0, 0, 0, 0); 1370ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 7, 0, 0, 0, 0); 1371ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 8, 0, 0, 0, 0); 1372ef2ee5d0SMichal Meloun 1373ef2ee5d0SMichal Meloun /* MSI BAR - clear. */ 1374ef2ee5d0SMichal Meloun tegra_pcib_set_bar(sc, 9, 0, 0, 0, 0); 1375ef2ee5d0SMichal Meloun return(0); 1376ef2ee5d0SMichal Meloun } 1377ef2ee5d0SMichal Meloun 13787709abd1SMichal Meloun #ifdef TEGRA_PCIB_MSI_ENABLE 13797709abd1SMichal Meloun static int 13807709abd1SMichal Meloun tegra_pcib_attach_msi(device_t dev) 13817709abd1SMichal Meloun { 13827709abd1SMichal Meloun struct tegra_pcib_softc *sc; 13837709abd1SMichal Meloun uint32_t reg; 13847709abd1SMichal Meloun int i, rv; 13857709abd1SMichal Meloun 13867709abd1SMichal Meloun sc = device_get_softc(dev); 13877709abd1SMichal Meloun 1388f49fd63aSJohn Baldwin sc->msi_page = (uintptr_t)kmem_alloc_contig(PAGE_SIZE, M_WAITOK, 0, 138944d0efb2SAlan Cox BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); 13907709abd1SMichal Meloun 13917709abd1SMichal Meloun /* MSI BAR */ 13927709abd1SMichal Meloun tegra_pcib_set_bar(sc, 9, vtophys(sc->msi_page), vtophys(sc->msi_page), 13937709abd1SMichal Meloun PAGE_SIZE, 0); 13947709abd1SMichal Meloun 1395415e8d12SGordon Bergling /* Disable and clear all interrupts. */ 13967709abd1SMichal Meloun for (i = 0; i < AFI_MSI_REGS; i++) { 13977709abd1SMichal Meloun AFI_WR4(sc, AFI_MSI_EN_VEC(i), 0); 13987709abd1SMichal Meloun AFI_WR4(sc, AFI_MSI_VEC(i), 0xFFFFFFFF); 13997709abd1SMichal Meloun } 14007709abd1SMichal Meloun rv = bus_setup_intr(dev, sc->msi_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 14017709abd1SMichal Meloun tegra_pcib_msi_intr, NULL, sc, &sc->msi_intr_cookie); 14027709abd1SMichal Meloun if (rv != 0) { 14037709abd1SMichal Meloun device_printf(dev, "cannot setup MSI interrupt handler\n"); 14047709abd1SMichal Meloun rv = ENXIO; 14057709abd1SMichal Meloun goto out; 14067709abd1SMichal Meloun } 14077709abd1SMichal Meloun 14087709abd1SMichal Meloun if (tegra_pcib_msi_attach(sc) != 0) { 14097709abd1SMichal Meloun device_printf(dev, "WARNING: unable to attach PIC\n"); 14107709abd1SMichal Meloun tegra_pcib_msi_detach(sc); 14117709abd1SMichal Meloun goto out; 14127709abd1SMichal Meloun } 14137709abd1SMichal Meloun 14147709abd1SMichal Meloun /* Unmask MSI interrupt. */ 14157709abd1SMichal Meloun reg = AFI_RD4(sc, AFI_INTR_MASK); 14167709abd1SMichal Meloun reg |= AFI_INTR_MASK_MSI_MASK; 14177709abd1SMichal Meloun AFI_WR4(sc, AFI_INTR_MASK, reg); 14187709abd1SMichal Meloun 14197709abd1SMichal Meloun out: 14207709abd1SMichal Meloun return (rv); 14217709abd1SMichal Meloun } 14227709abd1SMichal Meloun #endif 14237709abd1SMichal Meloun 1424ef2ee5d0SMichal Meloun static int 1425ef2ee5d0SMichal Meloun tegra_pcib_probe(device_t dev) 1426ef2ee5d0SMichal Meloun { 1427ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 1428ef2ee5d0SMichal Meloun return (ENXIO); 1429ef2ee5d0SMichal Meloun 1430ef2ee5d0SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 1431ef2ee5d0SMichal Meloun device_set_desc(dev, "Nvidia Integrated PCI/PCI-E Controller"); 1432ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 1433ef2ee5d0SMichal Meloun } 1434ef2ee5d0SMichal Meloun return (ENXIO); 1435ef2ee5d0SMichal Meloun } 1436ef2ee5d0SMichal Meloun 1437ef2ee5d0SMichal Meloun static int 1438ef2ee5d0SMichal Meloun tegra_pcib_attach(device_t dev) 1439ef2ee5d0SMichal Meloun { 1440ef2ee5d0SMichal Meloun struct tegra_pcib_softc *sc; 1441ef2ee5d0SMichal Meloun phandle_t node; 1442ef2ee5d0SMichal Meloun int rv; 1443ef2ee5d0SMichal Meloun int rid; 1444ef2ee5d0SMichal Meloun struct tegra_pcib_port *port; 1445ef2ee5d0SMichal Meloun int i; 1446ef2ee5d0SMichal Meloun 1447ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 1448ef2ee5d0SMichal Meloun sc->dev = dev; 1449ef2ee5d0SMichal Meloun mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF); 1450ef2ee5d0SMichal Meloun 1451ef2ee5d0SMichal Meloun node = ofw_bus_get_node(dev); 1452b9cbd68dSMichal Meloun sc->soc = (struct pcie_soc *)ofw_bus_search_compatible(dev, 1453b9cbd68dSMichal Meloun compat_data)->ocd_data; 1454ef2ee5d0SMichal Meloun 1455ef2ee5d0SMichal Meloun rv = tegra_pcib_parse_fdt_resources(sc, node); 1456ef2ee5d0SMichal Meloun if (rv != 0) { 1457ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get FDT resources\n"); 1458ef2ee5d0SMichal Meloun return (rv); 1459ef2ee5d0SMichal Meloun } 1460ef2ee5d0SMichal Meloun 1461ef2ee5d0SMichal Meloun /* Allocate bus_space resources. */ 1462ef2ee5d0SMichal Meloun rid = 0; 1463ef2ee5d0SMichal Meloun sc->pads_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1464ef2ee5d0SMichal Meloun RF_ACTIVE); 1465ef2ee5d0SMichal Meloun if (sc->pads_mem_res == NULL) { 1466ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate PADS register\n"); 1467ef2ee5d0SMichal Meloun rv = ENXIO; 1468ef2ee5d0SMichal Meloun goto out; 1469ef2ee5d0SMichal Meloun } 1470ef2ee5d0SMichal Meloun /* 1471ef2ee5d0SMichal Meloun * XXX - FIXME 1472ef2ee5d0SMichal Meloun * tag for config space is not filled when RF_ALLOCATED flag is used. 1473ef2ee5d0SMichal Meloun */ 1474ef2ee5d0SMichal Meloun sc->bus_tag = rman_get_bustag(sc->pads_mem_res); 1475ef2ee5d0SMichal Meloun 1476ef2ee5d0SMichal Meloun rid = 1; 1477ef2ee5d0SMichal Meloun sc->afi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1478ef2ee5d0SMichal Meloun RF_ACTIVE); 1479ef2ee5d0SMichal Meloun if (sc->afi_mem_res == NULL) { 1480ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate AFI register\n"); 1481ef2ee5d0SMichal Meloun rv = ENXIO; 1482ef2ee5d0SMichal Meloun goto out; 1483ef2ee5d0SMichal Meloun } 1484ef2ee5d0SMichal Meloun 1485ef2ee5d0SMichal Meloun rid = 2; 1486ef2ee5d0SMichal Meloun sc->cfg_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1487ef2ee5d0SMichal Meloun RF_ALLOCATED); 1488ef2ee5d0SMichal Meloun if (sc->cfg_mem_res == NULL) { 1489ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate config space memory\n"); 1490ef2ee5d0SMichal Meloun rv = ENXIO; 1491ef2ee5d0SMichal Meloun goto out; 1492ef2ee5d0SMichal Meloun } 1493ef2ee5d0SMichal Meloun sc->cfg_base_addr = rman_get_start(sc->cfg_mem_res); 1494ef2ee5d0SMichal Meloun 1495ef2ee5d0SMichal Meloun /* Map RP slots */ 1496ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1497ef2ee5d0SMichal Meloun if (sc->ports[i] == NULL) 1498ef2ee5d0SMichal Meloun continue; 1499ef2ee5d0SMichal Meloun port = sc->ports[i]; 1500ef2ee5d0SMichal Meloun rv = bus_space_map(sc->bus_tag, port->rp_base_addr, 1501ef2ee5d0SMichal Meloun port->rp_size, 0, &port->cfg_handle); 1502ef2ee5d0SMichal Meloun if (rv != 0) { 1503ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot allocate memory for " 1504ef2ee5d0SMichal Meloun "port: %d\n", i); 1505ef2ee5d0SMichal Meloun rv = ENXIO; 1506ef2ee5d0SMichal Meloun goto out; 1507ef2ee5d0SMichal Meloun } 1508ef2ee5d0SMichal Meloun } 1509ef2ee5d0SMichal Meloun 1510ef2ee5d0SMichal Meloun /* 151179cceaacSMichal Meloun * Get PCI interrupt 1512ef2ee5d0SMichal Meloun */ 1513ef2ee5d0SMichal Meloun rid = 0; 1514ef2ee5d0SMichal Meloun sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1515ef2ee5d0SMichal Meloun RF_ACTIVE | RF_SHAREABLE); 1516ef2ee5d0SMichal Meloun if (sc->irq_res == NULL) { 1517ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate IRQ resources\n"); 1518ef2ee5d0SMichal Meloun rv = ENXIO; 1519ef2ee5d0SMichal Meloun goto out; 1520ef2ee5d0SMichal Meloun } 1521ef2ee5d0SMichal Meloun 1522ef2ee5d0SMichal Meloun rid = 1; 1523ef2ee5d0SMichal Meloun sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1524ef2ee5d0SMichal Meloun RF_ACTIVE); 1525ef2ee5d0SMichal Meloun if (sc->irq_res == NULL) { 1526ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate MSI IRQ resources\n"); 1527ef2ee5d0SMichal Meloun rv = ENXIO; 1528ef2ee5d0SMichal Meloun goto out; 1529ef2ee5d0SMichal Meloun } 1530ef2ee5d0SMichal Meloun 153179cceaacSMichal Meloun sc->ofw_pci.sc_range_mask = 0x3; 153224042910SMarcin Wojtas rv = ofw_pcib_init(dev); 153379cceaacSMichal Meloun if (rv != 0) 153479cceaacSMichal Meloun goto out; 153579cceaacSMichal Meloun 153679cceaacSMichal Meloun rv = tegra_pcib_decode_ranges(sc, sc->ofw_pci.sc_range, 153779cceaacSMichal Meloun sc->ofw_pci.sc_nrange); 153879cceaacSMichal Meloun if (rv != 0) 153979cceaacSMichal Meloun goto out; 154079cceaacSMichal Meloun 1541ef2ee5d0SMichal Meloun if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 1542ef2ee5d0SMichal Meloun tegra_pci_intr, NULL, sc, &sc->intr_cookie)) { 1543ef2ee5d0SMichal Meloun device_printf(dev, "cannot setup interrupt handler\n"); 1544ef2ee5d0SMichal Meloun rv = ENXIO; 1545ef2ee5d0SMichal Meloun goto out; 1546ef2ee5d0SMichal Meloun } 1547ef2ee5d0SMichal Meloun 1548ef2ee5d0SMichal Meloun /* 1549ef2ee5d0SMichal Meloun * Enable PCIE device. 1550ef2ee5d0SMichal Meloun */ 155104d18df9SAndrew Turner rv = tegra_pcib_enable(sc); 1552ef2ee5d0SMichal Meloun if (rv != 0) 1553ef2ee5d0SMichal Meloun goto out; 1554ef2ee5d0SMichal Meloun for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1555ef2ee5d0SMichal Meloun if (sc->ports[i] == NULL) 1556ef2ee5d0SMichal Meloun continue; 1557ef2ee5d0SMichal Meloun if (sc->ports[i]->enabled) 1558ef2ee5d0SMichal Meloun tegra_pcib_port_enable(sc, i); 1559ef2ee5d0SMichal Meloun else 1560ef2ee5d0SMichal Meloun tegra_pcib_port_disable(sc, i); 1561ef2ee5d0SMichal Meloun } 1562ef2ee5d0SMichal Meloun 15637709abd1SMichal Meloun #ifdef TEGRA_PCIB_MSI_ENABLE 15647709abd1SMichal Meloun rv = tegra_pcib_attach_msi(dev); 15657709abd1SMichal Meloun if (rv != 0) 15667709abd1SMichal Meloun goto out; 15677709abd1SMichal Meloun #endif 15685b56413dSWarner Losh device_add_child(dev, "pci", DEVICE_UNIT_ANY); 1569*18250ec6SJohn Baldwin bus_attach_children(dev); 1570ef2ee5d0SMichal Meloun 1571*18250ec6SJohn Baldwin return (0); 1572ef2ee5d0SMichal Meloun 1573ef2ee5d0SMichal Meloun out: 1574ef2ee5d0SMichal Meloun 1575ef2ee5d0SMichal Meloun return (rv); 1576ef2ee5d0SMichal Meloun } 1577ef2ee5d0SMichal Meloun 1578ef2ee5d0SMichal Meloun static device_method_t tegra_pcib_methods[] = { 1579ef2ee5d0SMichal Meloun /* Device interface */ 1580ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, tegra_pcib_probe), 1581ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, tegra_pcib_attach), 1582ef2ee5d0SMichal Meloun 1583ef2ee5d0SMichal Meloun /* Bus interface */ 1584ef2ee5d0SMichal Meloun DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1585ef2ee5d0SMichal Meloun DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 1586ef2ee5d0SMichal Meloun 1587ef2ee5d0SMichal Meloun /* pcib interface */ 1588ef2ee5d0SMichal Meloun DEVMETHOD(pcib_maxslots, tegra_pcib_maxslots), 1589ef2ee5d0SMichal Meloun DEVMETHOD(pcib_read_config, tegra_pcib_read_config), 1590ef2ee5d0SMichal Meloun DEVMETHOD(pcib_write_config, tegra_pcib_write_config), 1591ef2ee5d0SMichal Meloun DEVMETHOD(pcib_route_interrupt, tegra_pcib_route_interrupt), 1592ef2ee5d0SMichal Meloun DEVMETHOD(pcib_alloc_msi, tegra_pcib_alloc_msi), 1593ef2ee5d0SMichal Meloun DEVMETHOD(pcib_release_msi, tegra_pcib_release_msi), 1594ef2ee5d0SMichal Meloun DEVMETHOD(pcib_map_msi, tegra_pcib_map_msi), 159528586889SWarner Losh DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), 15967709abd1SMichal Meloun 15977709abd1SMichal Meloun #ifdef TEGRA_PCIB_MSI_ENABLE 15987709abd1SMichal Meloun /* MSI/MSI-X */ 15997709abd1SMichal Meloun DEVMETHOD(msi_alloc_msi, tegra_pcib_msi_alloc_msi), 16007709abd1SMichal Meloun DEVMETHOD(msi_release_msi, tegra_pcib_msi_release_msi), 16017709abd1SMichal Meloun DEVMETHOD(msi_map_msi, tegra_pcib_msi_map_msi), 16027709abd1SMichal Meloun 16037709abd1SMichal Meloun /* Interrupt controller interface */ 16047709abd1SMichal Meloun DEVMETHOD(pic_disable_intr, tegra_pcib_msi_disable_intr), 16057709abd1SMichal Meloun DEVMETHOD(pic_enable_intr, tegra_pcib_msi_enable_intr), 16067709abd1SMichal Meloun DEVMETHOD(pic_setup_intr, tegra_pcib_msi_setup_intr), 16077709abd1SMichal Meloun DEVMETHOD(pic_teardown_intr, tegra_pcib_msi_teardown_intr), 16087709abd1SMichal Meloun DEVMETHOD(pic_post_filter, tegra_pcib_msi_post_filter), 16097709abd1SMichal Meloun DEVMETHOD(pic_post_ithread, tegra_pcib_msi_post_ithread), 16107709abd1SMichal Meloun DEVMETHOD(pic_pre_ithread, tegra_pcib_msi_pre_ithread), 1611ef2ee5d0SMichal Meloun #endif 1612ef2ee5d0SMichal Meloun 1613ef2ee5d0SMichal Meloun /* OFW bus interface */ 1614ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 1615ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 1616ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 1617ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 1618ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 1619ef2ee5d0SMichal Meloun 1620ef2ee5d0SMichal Meloun DEVMETHOD_END 1621ef2ee5d0SMichal Meloun }; 1622ef2ee5d0SMichal Meloun 162387380273SEmmanuel Vadot DEFINE_CLASS_1(pcib, tegra_pcib_driver, tegra_pcib_methods, 162424042910SMarcin Wojtas sizeof(struct tegra_pcib_softc), ofw_pcib_driver); 1625289f133bSJohn Baldwin DRIVER_MODULE(tegra_pcib, simplebus, tegra_pcib_driver, NULL, NULL); 1626