1296936Smmel/*- 2296936Smmel * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3296936Smmel * All rights reserved. 4296936Smmel * 5296936Smmel * Redistribution and use in source and binary forms, with or without 6296936Smmel * modification, are permitted provided that the following conditions 7296936Smmel * are met: 8296936Smmel * 1. Redistributions of source code must retain the above copyright 9296936Smmel * notice, this list of conditions and the following disclaimer. 10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright 11296936Smmel * notice, this list of conditions and the following disclaimer in the 12296936Smmel * documentation and/or other materials provided with the distribution. 13296936Smmel * 14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17296936Smmel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296936Smmel * SUCH DAMAGE. 25296936Smmel */ 26296936Smmel 27296936Smmel#include <sys/cdefs.h> 28296936Smmel__FBSDID("$FreeBSD: releng/11.0/sys/arm/nvidia/tegra_pcie.c 298627 2016-04-26 11:53:37Z br $"); 29296936Smmel 30296936Smmel/* 31296936Smmel * Nvidia Integrated PCI/PCI-Express controller driver. 32296936Smmel */ 33296936Smmel 34296936Smmel#include <sys/param.h> 35296936Smmel#include <sys/systm.h> 36296936Smmel#include <sys/kernel.h> 37296936Smmel#include <sys/lock.h> 38296936Smmel#include <sys/malloc.h> 39296936Smmel#include <sys/module.h> 40296936Smmel#include <sys/mutex.h> 41296936Smmel#include <sys/queue.h> 42296936Smmel#include <sys/bus.h> 43296936Smmel#include <sys/rman.h> 44296936Smmel#include <sys/endian.h> 45298627Sbr#include <sys/devmap.h> 46296936Smmel 47296936Smmel#include <machine/intr.h> 48296936Smmel 49296936Smmel#include <vm/vm.h> 50296936Smmel#include <vm/pmap.h> 51296936Smmel 52296936Smmel#include <dev/extres/clk/clk.h> 53296936Smmel#include <dev/extres/hwreset/hwreset.h> 54296936Smmel#include <dev/extres/phy/phy.h> 55296936Smmel#include <dev/extres/regulator/regulator.h> 56296936Smmel#include <dev/fdt/fdt_common.h> 57296936Smmel#include <dev/ofw/ofw_bus.h> 58296936Smmel#include <dev/ofw/ofw_bus_subr.h> 59296936Smmel#include <dev/ofw/ofw_pci.h> 60296936Smmel#include <dev/pci/pcivar.h> 61296936Smmel#include <dev/pci/pcireg.h> 62296936Smmel#include <dev/pci/pcib_private.h> 63296936Smmel 64296936Smmel#include <machine/resource.h> 65296936Smmel#include <machine/bus.h> 66296936Smmel 67296936Smmel#include "ofw_bus_if.h" 68296936Smmel#include "pcib_if.h" 69296936Smmel 70296936Smmel#include <arm/nvidia/tegra_pmc.h> 71296936Smmel 72296936Smmel/* --- Move to ofw_pci.c/.h ----------------------- */ 73296936Smmel 74296936Smmelstruct tegra_pci_range { 75296936Smmel /* parsed phys.hi */ 76296936Smmel int nonrelocatable; 77296936Smmel int prefetchable; 78296936Smmel int aliased; 79296936Smmel int space_code; /* In native format (not shifted)*/ 80296936Smmel int bus; 81296936Smmel int device; 82296936Smmel int function; 83296936Smmel int reg; 84296936Smmel pci_addr_t pci_addr; /* PCI Address */ 85296936Smmel bus_addr_t host_addr; /* Host bus address*/ 86296936Smmel bus_size_t size; /* Range size */ 87296936Smmel}; 88296936Smmel 89296936Smmelstatic int 90296936Smmeltegra_pci_get_ranges(phandle_t node, struct tegra_pci_range **ranges) 91296936Smmel{ 92296936Smmel int host_address_cells, pci_address_cells, size_cells; 93296936Smmel cell_t *base_ranges; 94296936Smmel ssize_t nbase_ranges; 95296936Smmel int nranges; 96296936Smmel int i, j, k; 97296936Smmel uint32_t flags; 98296936Smmel uint64_t tmp; 99296936Smmel 100296936Smmel host_address_cells = 1; 101296936Smmel pci_address_cells = 3; 102296936Smmel size_cells = 2; 103296936Smmel OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells, 104296936Smmel sizeof(host_address_cells)); 105296936Smmel OF_getencprop(node, "#address-cells", &pci_address_cells, 106296936Smmel sizeof(pci_address_cells)); 107296936Smmel OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells)); 108296936Smmel 109296936Smmel nbase_ranges = OF_getproplen(node, "ranges"); 110296936Smmel if (nbase_ranges <= 0) 111296936Smmel return (-1); 112296936Smmel nranges = nbase_ranges / sizeof(cell_t) / 113296936Smmel (pci_address_cells + host_address_cells + size_cells); 114296936Smmel 115296936Smmel *ranges = malloc(nranges * sizeof(struct tegra_pci_range), 116296936Smmel M_DEVBUF, M_WAITOK); 117296936Smmel base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); 118296936Smmel OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 119296936Smmel 120296936Smmel for (i = 0, j = 0; i < nranges; i++) { 121296936Smmel flags = base_ranges[j++]; 122296936Smmel (*ranges)[i].nonrelocatable = 123296936Smmel flags & OFW_PCI_PHYS_HI_NONRELOCATABLE ? 1 : 0; 124296936Smmel (*ranges)[i].prefetchable = 125296936Smmel flags & OFW_PCI_PHYS_HI_PREFETCHABLE ? 1 : 0; 126296936Smmel (*ranges)[i].aliased = 127296936Smmel flags & OFW_PCI_PHYS_HI_ALIASED ? 1 : 0; 128296936Smmel (*ranges)[i].space_code = flags & OFW_PCI_PHYS_HI_SPACEMASK; 129296936Smmel (*ranges)[i].bus = OFW_PCI_PHYS_HI_BUS(flags); 130296936Smmel (*ranges)[i].device = OFW_PCI_PHYS_HI_DEVICE(flags); 131296936Smmel (*ranges)[i].function = OFW_PCI_PHYS_HI_FUNCTION(flags); 132296936Smmel (*ranges)[i].reg = flags & OFW_PCI_PHYS_HI_REGISTERMASK; 133296936Smmel 134296936Smmel tmp = 0; 135296936Smmel for (k = 0; k < pci_address_cells - 1; k++) { 136296936Smmel tmp <<= 32; 137296936Smmel tmp |= base_ranges[j++]; 138296936Smmel } 139296936Smmel (*ranges)[i].pci_addr = (pci_addr_t)tmp; 140296936Smmel 141296936Smmel tmp = 0; 142296936Smmel for (k = 0; k < host_address_cells; k++) { 143296936Smmel tmp <<= 32; 144296936Smmel tmp |= base_ranges[j++]; 145296936Smmel } 146296936Smmel (*ranges)[i].host_addr = (bus_addr_t)tmp; 147296936Smmel tmp = 0; 148296936Smmel 149296936Smmel for (k = 0; k < size_cells; k++) { 150296936Smmel tmp <<= 32; 151296936Smmel tmp |= base_ranges[j++]; 152296936Smmel } 153296936Smmel (*ranges)[i].size = (bus_size_t)tmp; 154296936Smmel } 155296936Smmel 156296936Smmel free(base_ranges, M_DEVBUF); 157296936Smmel return (nranges); 158296936Smmel} 159296936Smmel 160296936Smmel/* -------------------------------------------------------------------------- */ 161296936Smmel#define AFI_AXI_BAR0_SZ 0x000 162296936Smmel#define AFI_AXI_BAR1_SZ 0x004 163296936Smmel#define AFI_AXI_BAR2_SZ 0x008 164296936Smmel#define AFI_AXI_BAR3_SZ 0x00c 165296936Smmel#define AFI_AXI_BAR4_SZ 0x010 166296936Smmel#define AFI_AXI_BAR5_SZ 0x014 167296936Smmel#define AFI_AXI_BAR0_START 0x018 168296936Smmel#define AFI_AXI_BAR1_START 0x01c 169296936Smmel#define AFI_AXI_BAR2_START 0x020 170296936Smmel#define AFI_AXI_BAR3_START 0x024 171296936Smmel#define AFI_AXI_BAR4_START 0x028 172296936Smmel#define AFI_AXI_BAR5_START 0x02c 173296936Smmel#define AFI_FPCI_BAR0 0x030 174296936Smmel#define AFI_FPCI_BAR1 0x034 175296936Smmel#define AFI_FPCI_BAR2 0x038 176296936Smmel#define AFI_FPCI_BAR3 0x03c 177296936Smmel#define AFI_FPCI_BAR4 0x040 178296936Smmel#define AFI_FPCI_BAR5 0x044 179296936Smmel#define AFI_MSI_BAR_SZ 0x060 180296936Smmel#define AFI_MSI_FPCI_BAR_ST 0x064 181296936Smmel#define AFI_MSI_AXI_BAR_ST 0x068 182296936Smmel 183296936Smmel 184296936Smmel#define AFI_AXI_BAR6_SZ 0x134 185296936Smmel#define AFI_AXI_BAR7_SZ 0x138 186296936Smmel#define AFI_AXI_BAR8_SZ 0x13c 187296936Smmel#define AFI_AXI_BAR6_START 0x140 188296936Smmel#define AFI_AXI_BAR7_START 0x144 189296936Smmel#define AFI_AXI_BAR8_START 0x148 190296936Smmel#define AFI_FPCI_BAR6 0x14c 191296936Smmel#define AFI_FPCI_BAR7 0x150 192296936Smmel#define AFI_FPCI_BAR8 0x154 193296936Smmel 194296936Smmel#define AFI_CONFIGURATION 0x0ac 195296936Smmel#define AFI_CONFIGURATION_EN_FPCI (1 << 0) 196296936Smmel 197296936Smmel#define AFI_FPCI_ERROR_MASKS 0x0b0 198296936Smmel#define AFI_INTR_MASK 0x0b4 199296936Smmel#define AFI_INTR_MASK_MSI_MASK (1 << 8) 200296936Smmel#define AFI_INTR_MASK_INT_MASK (1 << 0) 201296936Smmel 202296936Smmel#define AFI_INTR_CODE 0x0b8 203296936Smmel#define AFI_INTR_CODE_MASK 0xf 204296936Smmel#define AFI_INTR_CODE_INT_CODE_INI_SLVERR 1 205296936Smmel#define AFI_INTR_CODE_INT_CODE_INI_DECERR 2 206296936Smmel#define AFI_INTR_CODE_INT_CODE_TGT_SLVERR 3 207296936Smmel#define AFI_INTR_CODE_INT_CODE_TGT_DECERR 4 208296936Smmel#define AFI_INTR_CODE_INT_CODE_TGT_WRERR 5 209296936Smmel#define AFI_INTR_CODE_INT_CODE_SM_MSG 6 210296936Smmel#define AFI_INTR_CODE_INT_CODE_DFPCI_DECERR 7 211296936Smmel#define AFI_INTR_CODE_INT_CODE_AXI_DECERR 8 212296936Smmel#define AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT 9 213296936Smmel#define AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE 10 214296936Smmel#define AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE 11 215296936Smmel#define AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE 12 216296936Smmel#define AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE 13 217296936Smmel#define AFI_INTR_CODE_INT_CODE_P2P_ERROR 14 218296936Smmel 219296936Smmel 220296936Smmel#define AFI_INTR_SIGNATURE 0x0bc 221296936Smmel#define AFI_UPPER_FPCI_ADDRESS 0x0c0 222296936Smmel#define AFI_SM_INTR_ENABLE 0x0c4 223296936Smmel#define AFI_SM_INTR_RP_DEASSERT (1 << 14) 224296936Smmel#define AFI_SM_INTR_RP_ASSERT (1 << 13) 225296936Smmel#define AFI_SM_INTR_HOTPLUG (1 << 12) 226296936Smmel#define AFI_SM_INTR_PME (1 << 11) 227296936Smmel#define AFI_SM_INTR_FATAL_ERROR (1 << 10) 228296936Smmel#define AFI_SM_INTR_UNCORR_ERROR (1 << 9) 229296936Smmel#define AFI_SM_INTR_CORR_ERROR (1 << 8) 230296936Smmel#define AFI_SM_INTR_INTD_DEASSERT (1 << 7) 231296936Smmel#define AFI_SM_INTR_INTC_DEASSERT (1 << 6) 232296936Smmel#define AFI_SM_INTR_INTB_DEASSERT (1 << 5) 233296936Smmel#define AFI_SM_INTR_INTA_DEASSERT (1 << 4) 234296936Smmel#define AFI_SM_INTR_INTD_ASSERT (1 << 3) 235296936Smmel#define AFI_SM_INTR_INTC_ASSERT (1 << 2) 236296936Smmel#define AFI_SM_INTR_INTB_ASSERT (1 << 1) 237296936Smmel#define AFI_SM_INTR_INTA_ASSERT (1 << 0) 238296936Smmel 239296936Smmel#define AFI_AFI_INTR_ENABLE 0x0c8 240296936Smmel#define AFI_AFI_INTR_ENABLE_CODE(code) (1 << (code)) 241296936Smmel 242296936Smmel#define AFI_PCIE_CONFIG 0x0f8 243296936Smmel#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1)) 244296936Smmel#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0x6 245296936Smmel#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) 246296936Smmel#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1 (0x0 << 20) 247296936Smmel#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1 (0x1 << 20) 248296936Smmel 249296936Smmel#define AFI_FUSE 0x104 250296936Smmel#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) 251296936Smmel 252296936Smmel#define AFI_PEX0_CTRL 0x110 253296936Smmel#define AFI_PEX1_CTRL 0x118 254296936Smmel#define AFI_PEX2_CTRL 0x128 255296936Smmel#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4) 256296936Smmel#define AFI_PEX_CTRL_REFCLK_EN (1 << 3) 257296936Smmel#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) 258296936Smmel#define AFI_PEX_CTRL_RST_L (1 << 0) 259296936Smmel 260296936Smmel#define AFI_AXI_BAR6_SZ 0x134 261296936Smmel#define AFI_AXI_BAR7_SZ 0x138 262296936Smmel#define AFI_AXI_BAR8_SZ 0x13c 263296936Smmel#define AFI_AXI_BAR6_START 0x140 264296936Smmel#define AFI_AXI_BAR7_START 0x144 265296936Smmel#define AFI_AXI_BAR8_START 0x148 266296936Smmel#define AFI_FPCI_BAR6 0x14c 267296936Smmel#define AFI_FPCI_BAR7 0x150 268296936Smmel#define AFI_FPCI_BAR8 0x154 269296936Smmel#define AFI_PLLE_CONTROL 0x160 270296936Smmel#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9) 271296936Smmel#define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8) 272296936Smmel#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1) 273296936Smmel#define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0) 274296936Smmel 275296936Smmel#define AFI_PEXBIAS_CTRL 0x168 276296936Smmel 277296936Smmel/* FPCI Address space */ 278296936Smmel#define FPCI_MAP_IO 0xfdfc000000ULL 279296936Smmel#define FPCI_MAP_TYPE0_CONFIG 0xfdfc000000ULL 280296936Smmel#define FPCI_MAP_TYPE1_CONFIG 0xfdff000000ULL 281296936Smmel#define FPCI_MAP_EXT_TYPE0_CONFIG 0xfe00000000ULL 282296936Smmel#define FPCI_MAP_EXT_TYPE1_CONFIG 0xfe10000000ULL 283296936Smmel 284296936Smmel/* Configuration space */ 285296936Smmel#define RP_VEND_XP 0x00000F00 286296936Smmel#define RP_VEND_XP_DL_UP (1 << 30) 287296936Smmel 288296936Smmel#define RP_PRIV_MISC 0x00000FE0 289296936Smmel#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0) 290296936Smmel#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0) 291296936Smmel 292296936Smmel#define RP_LINK_CONTROL_STATUS 0x00000090 293296936Smmel#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 294296936Smmel#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 295296936Smmel 296296936Smmel#define TEGRA_PCIE_LINKUP_TIMEOUT 200 297296936Smmel 298296936Smmel#define DEBUG 299296936Smmel#ifdef DEBUG 300296936Smmel#define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 301296936Smmel#else 302296936Smmel#define debugf(fmt, args...) 303296936Smmel#endif 304296936Smmel 305296936Smmel/* 306296936Smmel * Configuration space format: 307296936Smmel * [27:24] extended register 308296936Smmel * [23:16] bus 309296936Smmel * [15:11] slot (device) 310296936Smmel * [10: 8] function 311296936Smmel * [ 7: 0] register 312296936Smmel */ 313296936Smmel#define PCI_CFG_EXT_REG(reg) ((((reg) >> 8) & 0x0f) << 24) 314296936Smmel#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) 315296936Smmel#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) 316296936Smmel#define PCI_CFG_FUN(fun) (((fun) & 0x07) << 8) 317296936Smmel#define PCI_CFG_BASE_REG(reg) ((reg) & 0xff) 318296936Smmel 319296936Smmel#define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)-pads_mem_res, (_r), (_v)) 320296936Smmel#define PADS_RD4(_sc, _r) bus_read_4((_sc)->pads_mem_res, (_r)) 321296936Smmel#define AFI_WR4(_sc, _r, _v) bus_write_4((_sc)->afi_mem_res, (_r), (_v)) 322296936Smmel#define AFI_RD4(_sc, _r) bus_read_4((_sc)->afi_mem_res, (_r)) 323296936Smmel 324296936Smmelstatic struct { 325296936Smmel bus_size_t axi_start; 326296936Smmel bus_size_t fpci_start; 327296936Smmel bus_size_t size; 328296936Smmel} bars[] = { 329296936Smmel {AFI_AXI_BAR0_START, AFI_FPCI_BAR0, AFI_AXI_BAR0_SZ}, /* BAR 0 */ 330296936Smmel {AFI_AXI_BAR1_START, AFI_FPCI_BAR1, AFI_AXI_BAR1_SZ}, /* BAR 1 */ 331296936Smmel {AFI_AXI_BAR2_START, AFI_FPCI_BAR2, AFI_AXI_BAR2_SZ}, /* BAR 2 */ 332296936Smmel {AFI_AXI_BAR3_START, AFI_FPCI_BAR3, AFI_AXI_BAR3_SZ}, /* BAR 3 */ 333296936Smmel {AFI_AXI_BAR4_START, AFI_FPCI_BAR4, AFI_AXI_BAR4_SZ}, /* BAR 4 */ 334296936Smmel {AFI_AXI_BAR5_START, AFI_FPCI_BAR5, AFI_AXI_BAR5_SZ}, /* BAR 5 */ 335296936Smmel {AFI_AXI_BAR6_START, AFI_FPCI_BAR6, AFI_AXI_BAR6_SZ}, /* BAR 6 */ 336296936Smmel {AFI_AXI_BAR7_START, AFI_FPCI_BAR7, AFI_AXI_BAR7_SZ}, /* BAR 7 */ 337296936Smmel {AFI_AXI_BAR8_START, AFI_FPCI_BAR8, AFI_AXI_BAR8_SZ}, /* BAR 8 */ 338296936Smmel {AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ}, /* MSI 9 */ 339296936Smmel}; 340296936Smmel 341296936Smmel/* Compatible devices. */ 342296936Smmelstatic struct ofw_compat_data compat_data[] = { 343296936Smmel {"nvidia,tegra124-pcie", 1}, 344296936Smmel {NULL, 0}, 345296936Smmel}; 346296936Smmel 347296936Smmelstruct tegra_pcib_port { 348296936Smmel int enabled; 349296936Smmel int port_idx; /* chip port index */ 350296936Smmel int num_lanes; /* number of lanes */ 351296936Smmel bus_size_t afi_pex_ctrl; /* offset of afi_pex_ctrl */ 352296936Smmel 353296936Smmel /* Config space properties. */ 354296936Smmel bus_addr_t rp_base_addr; /* PA of config window */ 355296936Smmel bus_size_t rp_size; /* size of config window */ 356296936Smmel bus_space_handle_t cfg_handle; /* handle of config window */ 357296936Smmel}; 358296936Smmel 359296936Smmel#define TEGRA_PCIB_MAX_PORTS 3 360296936Smmelstruct tegra_pcib_softc { 361296936Smmel device_t dev; 362296936Smmel struct mtx mtx; 363296936Smmel struct ofw_bus_iinfo pci_iinfo; 364296936Smmel struct rman pref_mem_rman; 365296936Smmel struct rman mem_rman; 366296936Smmel struct rman io_rman; 367296936Smmel struct resource *pads_mem_res; 368296936Smmel struct resource *afi_mem_res; 369296936Smmel struct resource *cfg_mem_res; 370296936Smmel struct resource *irq_res; 371296936Smmel struct resource *msi_irq_res; 372296936Smmel void *intr_cookie; 373296936Smmel void *msi_intr_cookie; 374296936Smmel 375296936Smmel struct tegra_pci_range mem_range; 376296936Smmel struct tegra_pci_range pref_mem_range; 377296936Smmel struct tegra_pci_range io_range; 378296936Smmel 379296936Smmel phy_t phy; 380296936Smmel clk_t clk_pex; 381296936Smmel clk_t clk_afi; 382296936Smmel clk_t clk_pll_e; 383296936Smmel clk_t clk_cml; 384296936Smmel hwreset_t hwreset_pex; 385296936Smmel hwreset_t hwreset_afi; 386296936Smmel hwreset_t hwreset_pcie_x; 387296936Smmel regulator_t supply_avddio_pex; 388296936Smmel regulator_t supply_dvddio_pex; 389296936Smmel regulator_t supply_avdd_pex_pll; 390296936Smmel regulator_t supply_hvdd_pex; 391296936Smmel regulator_t supply_hvdd_pex_pll_e; 392296936Smmel regulator_t supply_vddio_pex_ctl; 393296936Smmel regulator_t supply_avdd_pll_erefe; 394296936Smmel 395296936Smmel int busnr; /* host bridge bus number */ 396296936Smmel uint32_t msi_bitmap; 397296936Smmel bus_addr_t cfg_base_addr; /* base address of config */ 398296936Smmel bus_size_t cfg_cur_offs; /* currently mapped window */ 399296936Smmel bus_space_handle_t cfg_handle; /* handle of config window */ 400296936Smmel bus_space_tag_t bus_tag; /* tag of config window */ 401296936Smmel int lanes_cfg; 402296936Smmel int num_ports; 403296936Smmel struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS]; 404296936Smmel}; 405296936Smmel 406296936Smmel/* ------------------------------------------------------------------------- */ 407296936Smmel/* 408296936Smmel * Resource manager 409296936Smmel */ 410296936Smmelstatic int 411296936Smmeltegra_pcib_rman_init(struct tegra_pcib_softc *sc) 412296936Smmel{ 413296936Smmel int err; 414296936Smmel char buf[64]; 415296936Smmel 416296936Smmel /* Memory management. */ 417296936Smmel sc->pref_mem_rman.rm_type = RMAN_ARRAY; 418296936Smmel snprintf(buf, sizeof(buf), "%s prefetchable memory space", 419296936Smmel device_get_nameunit(sc->dev)); 420296936Smmel sc->pref_mem_rman.rm_descr = strdup(buf, M_DEVBUF); 421296936Smmel err = rman_init(&sc->pref_mem_rman); 422296936Smmel if (err) 423296936Smmel return (err); 424296936Smmel 425296936Smmel sc->mem_rman.rm_type = RMAN_ARRAY; 426296936Smmel snprintf(buf, sizeof(buf), "%s non prefetchable memory space", 427296936Smmel device_get_nameunit(sc->dev)); 428296936Smmel sc->mem_rman.rm_descr = strdup(buf, M_DEVBUF); 429296936Smmel err = rman_init(&sc->mem_rman); 430296936Smmel if (err) 431296936Smmel return (err); 432296936Smmel 433296936Smmel sc->io_rman.rm_type = RMAN_ARRAY; 434296936Smmel snprintf(buf, sizeof(buf), "%s I/O space", 435296936Smmel device_get_nameunit(sc->dev)); 436296936Smmel sc->io_rman.rm_descr = strdup(buf, M_DEVBUF); 437296936Smmel err = rman_init(&sc->io_rman); 438296936Smmel if (err) { 439296936Smmel rman_fini(&sc->mem_rman); 440296936Smmel return (err); 441296936Smmel } 442296936Smmel 443296936Smmel err = rman_manage_region(&sc->pref_mem_rman, 444296936Smmel sc->pref_mem_range.host_addr, 445296936Smmel sc->pref_mem_range.host_addr + sc->pref_mem_range.size - 1); 446296936Smmel if (err) 447296936Smmel goto error; 448296936Smmel err = rman_manage_region(&sc->mem_rman, 449296936Smmel sc->mem_range.host_addr, 450296936Smmel sc->mem_range.host_addr + sc->mem_range.size - 1); 451296936Smmel if (err) 452296936Smmel goto error; 453296936Smmel err = rman_manage_region(&sc->io_rman, 454296936Smmel sc->io_range.pci_addr, 455296936Smmel sc->io_range.pci_addr + sc->io_range.size - 1); 456296936Smmel if (err) 457296936Smmel goto error; 458296936Smmel return (0); 459296936Smmel 460296936Smmelerror: 461296936Smmel rman_fini(&sc->pref_mem_rman); 462296936Smmel rman_fini(&sc->mem_rman); 463296936Smmel rman_fini(&sc->io_rman); 464296936Smmel return (err); 465296936Smmel} 466296936Smmel 467296936Smmelstatic struct rman * 468296936Smmeltegra_pcib_rman(struct tegra_pcib_softc *sc, int type, u_int flags) 469296936Smmel{ 470296936Smmel 471296936Smmel switch (type) { 472296936Smmel case SYS_RES_IOPORT: 473296936Smmel return (&sc->io_rman); 474296936Smmel case SYS_RES_MEMORY: 475296936Smmel if (flags & RF_PREFETCHABLE) 476296936Smmel return (&sc->pref_mem_rman); 477296936Smmel else 478296936Smmel return (&sc->mem_rman); 479296936Smmel default: 480296936Smmel break; 481296936Smmel } 482296936Smmel 483296936Smmel return (NULL); 484296936Smmel} 485296936Smmel 486296936Smmelstatic struct resource * 487296936Smmeltegra_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 488296936Smmel rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 489296936Smmel{ 490296936Smmel struct tegra_pcib_softc *sc; 491296936Smmel struct rman *rm; 492296936Smmel struct resource *res; 493296936Smmel 494297011Smmel debugf("%s: enter %d start %#jx end %#jx count %#jx\n", __func__, 495296936Smmel type, start, end, count); 496296936Smmel sc = device_get_softc(dev); 497296936Smmel 498296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 499296936Smmel if (type == PCI_RES_BUS) { 500296936Smmel return (pci_domain_alloc_bus(0, child, rid, start, end, count, 501296936Smmel flags)); 502296936Smmel } 503296936Smmel#endif 504296936Smmel 505296936Smmel rm = tegra_pcib_rman(sc, type, flags); 506296936Smmel 507296936Smmel if (rm == NULL) { 508296936Smmel res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 509296936Smmel type, rid, start, end, count, flags); 510296936Smmel 511296936Smmel return (res); 512296936Smmel } 513296936Smmel 514296936Smmel if (bootverbose) { 515296936Smmel device_printf(dev, 516297011Smmel "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n", 517296936Smmel start, end, count); 518296936Smmel } 519296936Smmel 520296936Smmel res = rman_reserve_resource(rm, start, end, count, flags, child); 521296936Smmel if (res == NULL) 522296936Smmel goto fail; 523296936Smmel rman_set_rid(res, *rid); 524296936Smmel if (flags & RF_ACTIVE) { 525296936Smmel if (bus_activate_resource(child, type, *rid, res)) { 526296936Smmel rman_release_resource(res); 527296936Smmel goto fail; 528296936Smmel } 529296936Smmel } 530296936Smmel return (res); 531296936Smmel 532296936Smmelfail: 533296936Smmel if (bootverbose) { 534296936Smmel device_printf(dev, "%s FAIL: type=%d, rid=%d, " 535297011Smmel "start=%016jx, end=%016jx, count=%016jx, flags=%x\n", 536296936Smmel __func__, type, *rid, start, end, count, flags); 537296936Smmel } 538296936Smmel 539296936Smmel return (NULL); 540296936Smmel} 541296936Smmel 542296936Smmelstatic int 543296936Smmeltegra_pcib_release_resource(device_t dev, device_t child, int type, int rid, 544296936Smmel struct resource *res) 545296936Smmel{ 546296936Smmel struct tegra_pcib_softc *sc; 547296936Smmel struct rman *rm; 548296936Smmel 549296936Smmel sc = device_get_softc(dev); 550296936Smmel debugf("%s: %d rid %x\n", __func__, type, rid); 551296936Smmel 552296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 553296936Smmel if (type == PCI_RES_BUS) 554296936Smmel return (pci_domain_release_bus(0, child, rid, res)); 555296936Smmel#endif 556296936Smmel 557296936Smmel rm = tegra_pcib_rman(sc, type, rman_get_flags(res)); 558296936Smmel if (rm != NULL) { 559296936Smmel KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); 560296936Smmel rman_release_resource(res); 561296936Smmel } 562296936Smmel 563296936Smmel return (bus_generic_release_resource(dev, child, type, rid, res)); 564296936Smmel} 565296936Smmel 566296936Smmelstatic int 567296936Smmeltegra_pcib_adjust_resource(device_t dev, device_t child, int type, 568297011Smmel struct resource *res, rman_res_t start, rman_res_t end) 569296936Smmel{ 570296936Smmel struct tegra_pcib_softc *sc; 571296936Smmel struct rman *rm; 572296936Smmel 573296936Smmel sc = device_get_softc(dev); 574297011Smmel debugf("%s: %d start %jx end %jx \n", __func__, type, start, end); 575296936Smmel 576296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 577296936Smmel if (type == PCI_RES_BUS) 578296936Smmel return (pci_domain_adjust_bus(0, child, res, start, end)); 579296936Smmel#endif 580296936Smmel 581296936Smmel rm = tegra_pcib_rman(sc, type, rman_get_flags(res)); 582296936Smmel if (rm != NULL) 583296936Smmel return (rman_adjust_resource(res, start, end)); 584296936Smmel return (bus_generic_adjust_resource(dev, child, type, res, start, end)); 585296936Smmel} 586296936Smmelextern bus_space_tag_t fdtbus_bs_tag; 587296936Smmelstatic int 588296936Smmeltegra_pcib_pcie_activate_resource(device_t dev, device_t child, int type, 589296936Smmel int rid, struct resource *r) 590296936Smmel{ 591296936Smmel struct tegra_pcib_softc *sc; 592296936Smmel vm_offset_t start; 593296936Smmel void *p; 594296936Smmel int rv; 595296936Smmel 596296936Smmel sc = device_get_softc(dev); 597296936Smmel rv = rman_activate_resource(r); 598296936Smmel if (rv != 0) 599296936Smmel return (rv); 600296936Smmel switch(type) { 601296936Smmel case SYS_RES_IOPORT: 602296936Smmel start = rman_get_start(r) + sc->io_range.host_addr; 603296936Smmel break; 604296936Smmel default: 605296936Smmel start = rman_get_start(r); 606296936Smmel rman_get_start(r); 607296936Smmel break; 608296936Smmel } 609296936Smmel 610296936Smmel if (bootverbose) 611297011Smmel printf("%s: start %zx, len %jd\n", __func__, start, 612296936Smmel rman_get_size(r)); 613296936Smmel 614296936Smmel p = pmap_mapdev(start, (vm_size_t)rman_get_size(r)); 615296936Smmel rman_set_virtual(r, p); 616296936Smmel rman_set_bustag(r, fdtbus_bs_tag); 617296936Smmel rman_set_bushandle(r, (u_long)p); 618296936Smmel return (0); 619296936Smmel} 620296936Smmel 621296936Smmel/* ------------------------------------------------------------------------- */ 622296936Smmel/* 623296936Smmel * IVARs 624296936Smmel */ 625296936Smmelstatic int 626296936Smmeltegra_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 627296936Smmel{ 628296936Smmel struct tegra_pcib_softc *sc = device_get_softc(dev); 629296936Smmel 630296936Smmel switch (which) { 631296936Smmel case PCIB_IVAR_BUS: 632296936Smmel *result = sc->busnr; 633296936Smmel return (0); 634296936Smmel case PCIB_IVAR_DOMAIN: 635296936Smmel *result = device_get_unit(dev); 636296936Smmel return (0); 637296936Smmel } 638296936Smmel 639296936Smmel return (ENOENT); 640296936Smmel} 641296936Smmel 642296936Smmelstatic int 643296936Smmeltegra_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 644296936Smmel{ 645296936Smmel struct tegra_pcib_softc *sc = device_get_softc(dev); 646296936Smmel 647296936Smmel switch (which) { 648296936Smmel case PCIB_IVAR_BUS: 649296936Smmel sc->busnr = value; 650296936Smmel return (0); 651296936Smmel } 652296936Smmel 653296936Smmel return (ENOENT); 654296936Smmel} 655296936Smmel 656296936Smmelstatic int 657296936Smmeltegra_pcib_maxslots(device_t dev) 658296936Smmel{ 659296936Smmel return (16); 660296936Smmel} 661296936Smmel 662296936Smmel 663296936Smmelstatic int 664296936Smmeltegra_pcib_route_interrupt(device_t bus, device_t dev, int pin) 665296936Smmel{ 666296936Smmel struct tegra_pcib_softc *sc; 667296936Smmel 668296936Smmel sc = device_get_softc(bus); 669297011Smmel device_printf(bus, "route pin %d for device %d.%d to %ju\n", 670296936Smmel pin, pci_get_slot(dev), pci_get_function(dev), 671296936Smmel rman_get_start(sc->irq_res)); 672296936Smmel 673296936Smmel return (rman_get_start(sc->irq_res)); 674296936Smmel} 675296936Smmel 676296936Smmelstatic int 677296936Smmeltegra_pcbib_map_cfg(struct tegra_pcib_softc *sc, u_int bus, u_int slot, 678296936Smmel u_int func, u_int reg) 679296936Smmel{ 680296936Smmel bus_size_t offs; 681296936Smmel int rv; 682296936Smmel 683296936Smmel offs = sc->cfg_base_addr; 684296936Smmel offs |= PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) | 685296936Smmel PCI_CFG_EXT_REG(reg); 686296936Smmel if ((sc->cfg_handle != 0) && (sc->cfg_cur_offs == offs)) 687296936Smmel return (0); 688296936Smmel if (sc->cfg_handle != 0) 689296936Smmel bus_space_unmap(sc->bus_tag, sc->cfg_handle, 0x800); 690296936Smmel 691296936Smmel rv = bus_space_map(sc->bus_tag, offs, 0x800, 0, &sc->cfg_handle); 692296936Smmel if (rv != 0) 693296936Smmel device_printf(sc->dev, "Cannot map config space\n"); 694296936Smmel else 695296936Smmel sc->cfg_cur_offs = offs; 696296936Smmel return (rv); 697296936Smmel} 698296936Smmel 699296936Smmelstatic uint32_t 700296936Smmeltegra_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 701296936Smmel u_int reg, int bytes) 702296936Smmel{ 703296936Smmel struct tegra_pcib_softc *sc; 704296936Smmel bus_space_handle_t hndl; 705296936Smmel uint32_t off; 706296936Smmel uint32_t val; 707296936Smmel int rv, i; 708296936Smmel 709296936Smmel sc = device_get_softc(dev); 710296936Smmel if (bus == 0) { 711296936Smmel if (func != 0) 712296936Smmel return (0xFFFFFFFF); 713296936Smmel for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 714296936Smmel if ((sc->ports[i] != NULL) && 715296936Smmel (sc->ports[i]->port_idx == slot)) { 716296936Smmel hndl = sc->ports[i]->cfg_handle; 717296936Smmel off = reg & 0xFFF; 718296936Smmel break; 719296936Smmel } 720296936Smmel } 721296936Smmel if (i >= TEGRA_PCIB_MAX_PORTS) 722296936Smmel return (0xFFFFFFFF); 723296936Smmel } else { 724296936Smmel rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); 725296936Smmel if (rv != 0) 726296936Smmel return (0xFFFFFFFF); 727296936Smmel hndl = sc->cfg_handle; 728296936Smmel off = PCI_CFG_BASE_REG(reg); 729296936Smmel } 730296936Smmel 731296936Smmel val = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 732296936Smmel switch (bytes) { 733296936Smmel case 4: 734296936Smmel break; 735296936Smmel case 2: 736296936Smmel if (off & 3) 737296936Smmel val >>= 16; 738296936Smmel val &= 0xffff; 739296936Smmel break; 740296936Smmel case 1: 741296936Smmel val >>= ((off & 3) << 3); 742296936Smmel val &= 0xff; 743296936Smmel break; 744296936Smmel } 745296936Smmel return val; 746296936Smmel} 747296936Smmel 748296936Smmelstatic void 749296936Smmeltegra_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 750296936Smmel u_int reg, uint32_t val, int bytes) 751296936Smmel{ 752296936Smmel struct tegra_pcib_softc *sc; 753296936Smmel bus_space_handle_t hndl; 754296936Smmel uint32_t off; 755296936Smmel uint32_t val2; 756296936Smmel int rv, i; 757296936Smmel 758296936Smmel sc = device_get_softc(dev); 759296936Smmel if (bus == 0) { 760296936Smmel if (func != 0) 761296936Smmel return; 762296936Smmel for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 763296936Smmel if ((sc->ports[i] != NULL) && 764296936Smmel (sc->ports[i]->port_idx == slot)) { 765296936Smmel hndl = sc->ports[i]->cfg_handle; 766296936Smmel off = reg & 0xFFF; 767296936Smmel break; 768296936Smmel } 769296936Smmel } 770296936Smmel if (i >= TEGRA_PCIB_MAX_PORTS) 771296936Smmel return; 772296936Smmel } else { 773296936Smmel rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); 774296936Smmel if (rv != 0) 775296936Smmel return; 776296936Smmel hndl = sc->cfg_handle; 777296936Smmel off = PCI_CFG_BASE_REG(reg); 778296936Smmel } 779296936Smmel 780296936Smmel switch (bytes) { 781296936Smmel case 4: 782296936Smmel bus_space_write_4(sc->bus_tag, hndl, off, val); 783296936Smmel break; 784296936Smmel case 2: 785296936Smmel val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 786296936Smmel val2 &= ~(0xffff << ((off & 3) << 3)); 787296936Smmel val2 |= ((val & 0xffff) << ((off & 3) << 3)); 788296936Smmel bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); 789296936Smmel break; 790296936Smmel case 1: 791296936Smmel val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); 792296936Smmel val2 &= ~(0xff << ((off & 3) << 3)); 793296936Smmel val2 |= ((val & 0xff) << ((off & 3) << 3)); 794296936Smmel bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); 795296936Smmel break; 796296936Smmel } 797296936Smmel} 798296936Smmel 799296936Smmelstatic int tegra_pci_intr(void *arg) 800296936Smmel{ 801296936Smmel struct tegra_pcib_softc *sc = arg; 802296936Smmel uint32_t code, signature; 803296936Smmel 804296936Smmel code = bus_read_4(sc->afi_mem_res, AFI_INTR_CODE) & AFI_INTR_CODE_MASK; 805296936Smmel signature = bus_read_4(sc->afi_mem_res, AFI_INTR_SIGNATURE); 806296936Smmel bus_write_4(sc->afi_mem_res, AFI_INTR_CODE, 0); 807296936Smmel if (code == AFI_INTR_CODE_INT_CODE_SM_MSG) 808296936Smmel return(FILTER_STRAY); 809296936Smmel 810296936Smmel printf("tegra_pci_intr: code %x sig %x\n", code, signature); 811296936Smmel return (FILTER_HANDLED); 812296936Smmel} 813296936Smmel 814296936Smmel#if defined(TEGRA_PCI_MSI) 815296936Smmelstatic int 816296936Smmeltegra_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, 817296936Smmel uint32_t *data) 818296936Smmel{ 819296936Smmel struct tegra_pcib_softc *sc; 820296936Smmel 821296936Smmel sc = device_get_softc(dev); 822296936Smmel irq = irq - MSI_IRQ; 823296936Smmel 824296936Smmel /* validate parameters */ 825296936Smmel if (isclr(&sc->msi_bitmap, irq)) { 826296936Smmel device_printf(dev, "invalid MSI 0x%x\n", irq); 827296936Smmel return (EINVAL); 828296936Smmel } 829296936Smmel 830296936Smmel tegra_msi_data(irq, addr, data); 831296936Smmel 832296936Smmel debugf("%s: irq: %d addr: %jx data: %x\n", 833296936Smmel __func__, irq, *addr, *data); 834296936Smmel 835296936Smmel return (0); 836296936Smmel} 837296936Smmel 838296936Smmelstatic int 839296936Smmeltegra_pcib_alloc_msi(device_t dev, device_t child, int count, 840296936Smmel int maxcount __unused, int *irqs) 841296936Smmel{ 842296936Smmel struct tegra_pcib_softc *sc; 843296936Smmel u_int start = 0, i; 844296936Smmel 845296936Smmel if (powerof2(count) == 0 || count > MSI_IRQ_NUM) 846296936Smmel return (EINVAL); 847296936Smmel 848296936Smmel sc = device_get_softc(dev); 849296936Smmel mtx_lock(&sc->mtx); 850296936Smmel 851296936Smmel for (start = 0; (start + count) < MSI_IRQ_NUM; start++) { 852296936Smmel for (i = start; i < start + count; i++) { 853296936Smmel if (isset(&sc->msi_bitmap, i)) 854296936Smmel break; 855296936Smmel } 856296936Smmel if (i == start + count) 857296936Smmel break; 858296936Smmel } 859296936Smmel 860296936Smmel if ((start + count) == MSI_IRQ_NUM) { 861296936Smmel mtx_unlock(&sc->mtx); 862296936Smmel return (ENXIO); 863296936Smmel } 864296936Smmel 865296936Smmel for (i = start; i < start + count; i++) { 866296936Smmel setbit(&sc->msi_bitmap, i); 867296936Smmel irqs[i] = MSI_IRQ + i; 868296936Smmel } 869296936Smmel debugf("%s: start: %x count: %x\n", __func__, start, count); 870296936Smmel 871296936Smmel mtx_unlock(&sc->mtx); 872296936Smmel return (0); 873296936Smmel} 874296936Smmel 875296936Smmelstatic int 876296936Smmeltegra_pcib_release_msi(device_t dev, device_t child, int count, int *irqs) 877296936Smmel{ 878296936Smmel struct tegra_pcib_softc *sc; 879296936Smmel u_int i; 880296936Smmel 881296936Smmel sc = device_get_softc(dev); 882296936Smmel mtx_lock(&sc->mtx); 883296936Smmel 884296936Smmel for (i = 0; i < count; i++) 885296936Smmel clrbit(&sc->msi_bitmap, irqs[i] - MSI_IRQ); 886296936Smmel 887296936Smmel mtx_unlock(&sc->mtx); 888296936Smmel return (0); 889296936Smmel} 890296936Smmel#endif 891296936Smmel 892296936Smmelstatic bus_size_t 893296936Smmeltegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port) 894296936Smmel{ 895296936Smmel if (port >= TEGRA_PCIB_MAX_PORTS) 896296936Smmel panic("invalid port number: %d\n", port); 897296936Smmel 898296936Smmel if (port == 0) 899296936Smmel return (AFI_PEX0_CTRL); 900296936Smmel else if (port == 1) 901296936Smmel return (AFI_PEX1_CTRL); 902296936Smmel else if (port == 2) 903296936Smmel return (AFI_PEX2_CTRL); 904296936Smmel else 905296936Smmel panic("invalid port number: %d\n", port); 906296936Smmel} 907296936Smmel 908296936Smmelstatic int 909296936Smmeltegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc) 910296936Smmel{ 911296936Smmel int rv; 912296936Smmel 913296936Smmel rv = hwreset_assert(sc->hwreset_pcie_x); 914296936Smmel if (rv != 0) { 915296936Smmel device_printf(sc->dev, "Cannot assert 'pcie_x' reset\n"); 916296936Smmel return (rv); 917296936Smmel } 918296936Smmel rv = hwreset_assert(sc->hwreset_afi); 919296936Smmel if (rv != 0) { 920296936Smmel device_printf(sc->dev, "Cannot assert 'afi' reset\n"); 921296936Smmel return (rv); 922296936Smmel } 923296936Smmel rv = hwreset_assert(sc->hwreset_pex); 924296936Smmel if (rv != 0) { 925296936Smmel device_printf(sc->dev, "Cannot assert 'pex' reset\n"); 926296936Smmel return (rv); 927296936Smmel } 928296936Smmel 929296936Smmel tegra_powergate_power_off(TEGRA_POWERGATE_PCX); 930296936Smmel 931296936Smmel /* Power supplies. */ 932296936Smmel rv = regulator_enable(sc->supply_avddio_pex); 933296936Smmel if (rv != 0) { 934296936Smmel device_printf(sc->dev, 935296936Smmel "Cannot enable 'avddio_pex' regulator\n"); 936296936Smmel return (rv); 937296936Smmel } 938296936Smmel rv = regulator_enable(sc->supply_dvddio_pex); 939296936Smmel if (rv != 0) { 940296936Smmel device_printf(sc->dev, 941296936Smmel "Cannot enable 'dvddio_pex' regulator\n"); 942296936Smmel return (rv); 943296936Smmel } 944296936Smmel rv = regulator_enable(sc->supply_avdd_pex_pll); 945296936Smmel if (rv != 0) { 946296936Smmel device_printf(sc->dev, 947296936Smmel "Cannot enable 'avdd-pex-pll' regulator\n"); 948296936Smmel return (rv); 949296936Smmel } 950296936Smmel 951296936Smmel rv = regulator_enable(sc->supply_hvdd_pex); 952296936Smmel if (rv != 0) { 953296936Smmel device_printf(sc->dev, 954296936Smmel "Cannot enable 'hvdd-pex-supply' regulator\n"); 955296936Smmel return (rv); 956296936Smmel } 957296936Smmel rv = regulator_enable(sc->supply_hvdd_pex_pll_e); 958296936Smmel if (rv != 0) { 959296936Smmel device_printf(sc->dev, 960296936Smmel "Cannot enable 'hvdd-pex-pll-e-supply' regulator\n"); 961296936Smmel return (rv); 962296936Smmel } 963296936Smmel rv = regulator_enable(sc->supply_vddio_pex_ctl); 964296936Smmel if (rv != 0) { 965296936Smmel device_printf(sc->dev, 966296936Smmel "Cannot enable 'vddio-pex-ctl' regulator\n"); 967296936Smmel return (rv); 968296936Smmel } 969296936Smmel rv = regulator_enable(sc->supply_avdd_pll_erefe); 970296936Smmel if (rv != 0) { 971296936Smmel device_printf(sc->dev, 972296936Smmel "Cannot enable 'avdd-pll-erefe-supply' regulator\n"); 973296936Smmel return (rv); 974296936Smmel } 975296936Smmel 976296936Smmel rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX, 977296936Smmel sc->clk_pex, sc->hwreset_pex); 978296936Smmel if (rv != 0) { 979296936Smmel device_printf(sc->dev, "Cannot enable 'PCX' powergate\n"); 980296936Smmel return (rv); 981296936Smmel } 982296936Smmel 983296936Smmel rv = hwreset_deassert(sc->hwreset_afi); 984296936Smmel if (rv != 0) { 985296936Smmel device_printf(sc->dev, "Cannot unreset 'afi' reset\n"); 986296936Smmel return (rv); 987296936Smmel } 988296936Smmel 989296936Smmel rv = clk_enable(sc->clk_afi); 990296936Smmel if (rv != 0) { 991296936Smmel device_printf(sc->dev, "Cannot enable 'afi' clock\n"); 992296936Smmel return (rv); 993296936Smmel } 994296936Smmel 995296936Smmel rv = clk_enable(sc->clk_cml); 996296936Smmel if (rv != 0) { 997296936Smmel device_printf(sc->dev, "Cannot enable 'cml' clock\n"); 998296936Smmel return (rv); 999296936Smmel } 1000296936Smmel 1001296936Smmel rv = clk_enable(sc->clk_pll_e); 1002296936Smmel if (rv != 0) { 1003296936Smmel device_printf(sc->dev, "Cannot enable 'pll_e' clock\n"); 1004296936Smmel return (rv); 1005296936Smmel } 1006296936Smmel return (0); 1007296936Smmel} 1008296936Smmel 1009296936Smmelstatic struct tegra_pcib_port * 1010296936Smmeltegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node) 1011296936Smmel{ 1012296936Smmel struct tegra_pcib_port *port; 1013296936Smmel uint32_t tmp[5]; 1014296936Smmel char tmpstr[6]; 1015296936Smmel int rv; 1016296936Smmel 1017296936Smmel port = malloc(sizeof(struct tegra_pcib_port), M_DEVBUF, M_WAITOK); 1018296936Smmel 1019296936Smmel rv = OF_getprop(node, "status", tmpstr, sizeof(tmpstr)); 1020296936Smmel if (rv <= 0 || strcmp(tmpstr, "okay") == 0 || 1021296936Smmel strcmp(tmpstr, "ok") == 0) 1022296936Smmel port->enabled = 1; 1023296936Smmel else 1024296936Smmel port->enabled = 0; 1025296936Smmel 1026296936Smmel rv = OF_getencprop(node, "assigned-addresses", tmp, sizeof(tmp)); 1027296936Smmel if (rv != sizeof(tmp)) { 1028296936Smmel device_printf(sc->dev, "Cannot parse assigned-address: %d\n", 1029296936Smmel rv); 1030296936Smmel goto fail; 1031296936Smmel } 1032296936Smmel port->rp_base_addr = tmp[2]; 1033296936Smmel port->rp_size = tmp[4]; 1034296936Smmel port->port_idx = OFW_PCI_PHYS_HI_DEVICE(tmp[0]) - 1; 1035296936Smmel if (port->port_idx >= TEGRA_PCIB_MAX_PORTS) { 1036296936Smmel device_printf(sc->dev, "Invalid port index: %d\n", 1037296936Smmel port->port_idx); 1038296936Smmel goto fail; 1039296936Smmel } 1040296936Smmel /* XXX - TODO: 1041296936Smmel * Implement proper function for parsing pci "reg" property: 1042296936Smmel * - it have PCI bus format 1043296936Smmel * - its relative to matching "assigned-addresses" 1044296936Smmel */ 1045296936Smmel rv = OF_getencprop(node, "reg", tmp, sizeof(tmp)); 1046296936Smmel if (rv != sizeof(tmp)) { 1047296936Smmel device_printf(sc->dev, "Cannot parse reg: %d\n", rv); 1048296936Smmel goto fail; 1049296936Smmel } 1050296936Smmel port->rp_base_addr += tmp[2]; 1051296936Smmel 1052296936Smmel rv = OF_getencprop(node, "nvidia,num-lanes", &port->num_lanes, 1053296936Smmel sizeof(port->num_lanes)); 1054296936Smmel if (rv != sizeof(port->num_lanes)) { 1055296936Smmel device_printf(sc->dev, "Cannot parse nvidia,num-lanes: %d\n", 1056296936Smmel rv); 1057296936Smmel goto fail; 1058296936Smmel } 1059296936Smmel if (port->num_lanes > 4) { 1060296936Smmel device_printf(sc->dev, "Invalid nvidia,num-lanes: %d\n", 1061296936Smmel port->num_lanes); 1062296936Smmel goto fail; 1063296936Smmel } 1064296936Smmel 1065296936Smmel port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx); 1066296936Smmel sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx); 1067296936Smmel 1068296936Smmel return (port); 1069296936Smmelfail: 1070296936Smmel free(port, M_DEVBUF); 1071296936Smmel return (NULL); 1072296936Smmel} 1073296936Smmel 1074296936Smmel 1075296936Smmelstatic int 1076296936Smmeltegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node) 1077296936Smmel{ 1078296936Smmel phandle_t child; 1079296936Smmel struct tegra_pcib_port *port; 1080296936Smmel int rv; 1081296936Smmel 1082296936Smmel /* Power supplies. */ 1083296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "avddio-pex-supply", 1084296936Smmel &sc->supply_avddio_pex); 1085296936Smmel if (rv != 0) { 1086296936Smmel device_printf(sc->dev, 1087296936Smmel "Cannot get 'avddio-pex' regulator\n"); 1088296936Smmel return (ENXIO); 1089296936Smmel } 1090296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "dvddio-pex-supply", 1091296936Smmel &sc->supply_dvddio_pex); 1092296936Smmel if (rv != 0) { 1093296936Smmel device_printf(sc->dev, 1094296936Smmel "Cannot get 'dvddio-pex' regulator\n"); 1095296936Smmel return (ENXIO); 1096296936Smmel } 1097296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "avdd-pex-pll-supply", 1098296936Smmel &sc->supply_avdd_pex_pll); 1099296936Smmel if (rv != 0) { 1100296936Smmel device_printf(sc->dev, 1101296936Smmel "Cannot get 'avdd-pex-pll' regulator\n"); 1102296936Smmel return (ENXIO); 1103296936Smmel } 1104296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-supply", 1105296936Smmel &sc->supply_hvdd_pex); 1106296936Smmel if (rv != 0) { 1107296936Smmel device_printf(sc->dev, 1108296936Smmel "Cannot get 'hvdd-pex' regulator\n"); 1109296936Smmel return (ENXIO); 1110296936Smmel } 1111296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-pll-e-supply", 1112296936Smmel &sc->supply_hvdd_pex_pll_e); 1113296936Smmel if (rv != 0) { 1114296936Smmel device_printf(sc->dev, 1115296936Smmel "Cannot get 'hvdd-pex-pll-e' regulator\n"); 1116296936Smmel return (ENXIO); 1117296936Smmel } 1118296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "vddio-pex-ctl-supply", 1119296936Smmel &sc->supply_vddio_pex_ctl); 1120296936Smmel if (rv != 0) { 1121296936Smmel device_printf(sc->dev, 1122296936Smmel "Cannot get 'vddio-pex-ctl' regulator\n"); 1123296936Smmel return (ENXIO); 1124296936Smmel } 1125296936Smmel rv = regulator_get_by_ofw_property(sc->dev, "avdd-pll-erefe-supply", 1126296936Smmel &sc->supply_avdd_pll_erefe); 1127296936Smmel if (rv != 0) { 1128296936Smmel device_printf(sc->dev, 1129296936Smmel "Cannot get 'avdd-pll-erefe' regulator\n"); 1130296936Smmel return (ENXIO); 1131296936Smmel } 1132296936Smmel 1133296936Smmel /* Resets. */ 1134296936Smmel rv = hwreset_get_by_ofw_name(sc->dev, "pex", &sc->hwreset_pex); 1135296936Smmel if (rv != 0) { 1136296936Smmel device_printf(sc->dev, "Cannot get 'pex' reset\n"); 1137296936Smmel return (ENXIO); 1138296936Smmel } 1139296936Smmel rv = hwreset_get_by_ofw_name(sc->dev, "afi", &sc->hwreset_afi); 1140296936Smmel if (rv != 0) { 1141296936Smmel device_printf(sc->dev, "Cannot get 'afi' reset\n"); 1142296936Smmel return (ENXIO); 1143296936Smmel } 1144296936Smmel rv = hwreset_get_by_ofw_name(sc->dev, "pcie_x", &sc->hwreset_pcie_x); 1145296936Smmel if (rv != 0) { 1146296936Smmel device_printf(sc->dev, "Cannot get 'pcie_x' reset\n"); 1147296936Smmel return (ENXIO); 1148296936Smmel } 1149296936Smmel 1150296936Smmel /* Clocks. */ 1151296936Smmel rv = clk_get_by_ofw_name(sc->dev, "pex", &sc->clk_pex); 1152296936Smmel if (rv != 0) { 1153296936Smmel device_printf(sc->dev, "Cannot get 'pex' clock\n"); 1154296936Smmel return (ENXIO); 1155296936Smmel } 1156296936Smmel rv = clk_get_by_ofw_name(sc->dev, "afi", &sc->clk_afi); 1157296936Smmel if (rv != 0) { 1158296936Smmel device_printf(sc->dev, "Cannot get 'afi' clock\n"); 1159296936Smmel return (ENXIO); 1160296936Smmel } 1161296936Smmel rv = clk_get_by_ofw_name(sc->dev, "pll_e", &sc->clk_pll_e); 1162296936Smmel if (rv != 0) { 1163296936Smmel device_printf(sc->dev, "Cannot get 'pll_e' clock\n"); 1164296936Smmel return (ENXIO); 1165296936Smmel } 1166296936Smmel rv = clk_get_by_ofw_name(sc->dev, "cml", &sc->clk_cml); 1167296936Smmel if (rv != 0) { 1168296936Smmel device_printf(sc->dev, "Cannot get 'cml' clock\n"); 1169296936Smmel return (ENXIO); 1170296936Smmel } 1171296936Smmel 1172296936Smmel /* Phy. */ 1173296936Smmel rv = phy_get_by_ofw_name(sc->dev, "pcie", &sc->phy); 1174296936Smmel if (rv != 0) { 1175296936Smmel device_printf(sc->dev, "Cannot get 'pcie' phy\n"); 1176296936Smmel return (ENXIO); 1177296936Smmel } 1178296936Smmel 1179296936Smmel /* Ports */ 1180296936Smmel sc->num_ports = 0; 1181296936Smmel for (child = OF_child(node); child != 0; child = OF_peer(child)) { 1182296936Smmel port = tegra_pcib_parse_port(sc, child); 1183296936Smmel if (port == NULL) { 1184296936Smmel device_printf(sc->dev, "Cannot parse PCIe port node\n"); 1185296936Smmel return (ENXIO); 1186296936Smmel } 1187296936Smmel sc->ports[sc->num_ports++] = port; 1188296936Smmel } 1189296936Smmel 1190296936Smmel return (0); 1191296936Smmel} 1192296936Smmel 1193296936Smmelstatic int 1194296936Smmeltegra_pcib_decode_ranges(struct tegra_pcib_softc *sc, 1195296936Smmel struct tegra_pci_range *ranges, int nranges) 1196296936Smmel{ 1197296936Smmel int i; 1198296936Smmel 1199296936Smmel for (i = 2; i < nranges; i++) { 1200296936Smmel if (ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_IO) { 1201296936Smmel if (sc->io_range.size != 0) { 1202296936Smmel device_printf(sc->dev, 1203296936Smmel "Duplicated IO range found in DT\n"); 1204296936Smmel return (ENXIO); 1205296936Smmel } 1206296936Smmel sc->io_range = ranges[i]; 1207296936Smmel } 1208296936Smmel if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) && 1209296936Smmel !ranges[i].prefetchable) { 1210296936Smmel if (sc->mem_range.size != 0) { 1211296936Smmel device_printf(sc->dev, 1212296936Smmel "Duplicated memory range found in DT\n"); 1213296936Smmel return (ENXIO); 1214296936Smmel } 1215296936Smmel sc->mem_range = ranges[i]; 1216296936Smmel } 1217296936Smmel if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) && 1218296936Smmel ranges[i].prefetchable) { 1219296936Smmel if (sc->pref_mem_range.size != 0) { 1220296936Smmel device_printf(sc->dev, 1221296936Smmel "Duplicated memory range found in DT\n"); 1222296936Smmel return (ENXIO); 1223296936Smmel } 1224296936Smmel sc->pref_mem_range = ranges[i]; 1225296936Smmel } 1226296936Smmel } 1227296936Smmel if ((sc->io_range.size == 0) || (sc->mem_range.size == 0) 1228296936Smmel || (sc->pref_mem_range.size == 0)) { 1229296936Smmel device_printf(sc->dev, 1230296936Smmel " Not all required ranges are found in DT\n"); 1231296936Smmel return (ENXIO); 1232296936Smmel } 1233296936Smmel return (0); 1234296936Smmel} 1235296936Smmel 1236296936Smmel/* 1237296936Smmel * Hardware config. 1238296936Smmel */ 1239296936Smmelstatic int 1240296936Smmeltegra_pcib_wait_for_link(struct tegra_pcib_softc *sc, 1241296936Smmel struct tegra_pcib_port *port) 1242296936Smmel{ 1243296936Smmel uint32_t reg; 1244296936Smmel int i; 1245296936Smmel 1246296936Smmel 1247296936Smmel /* Setup link detection. */ 1248296936Smmel reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1249296936Smmel RP_PRIV_MISC, 4); 1250296936Smmel reg &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT; 1251296936Smmel reg |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT; 1252296936Smmel tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0, 1253296936Smmel RP_PRIV_MISC, reg, 4); 1254296936Smmel 1255296936Smmel for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { 1256296936Smmel reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1257296936Smmel RP_VEND_XP, 4); 1258296936Smmel if (reg & RP_VEND_XP_DL_UP) 1259296936Smmel break; 1260296936Smmel 1261296936Smmel } 1262296936Smmel if (i <= 0) 1263296936Smmel return (ETIMEDOUT); 1264296936Smmel 1265296936Smmel for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { 1266296936Smmel reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, 1267296936Smmel RP_LINK_CONTROL_STATUS, 4); 1268296936Smmel if (reg & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) 1269296936Smmel break; 1270296936Smmel 1271296936Smmel } 1272296936Smmel if (i <= 0) 1273296936Smmel return (ETIMEDOUT); 1274296936Smmel return (0); 1275296936Smmel} 1276296936Smmel 1277296936Smmelstatic void 1278296936Smmeltegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num) 1279296936Smmel{ 1280296936Smmel struct tegra_pcib_port *port; 1281296936Smmel uint32_t reg; 1282296936Smmel int rv; 1283296936Smmel 1284296936Smmel port = sc->ports[port_num]; 1285296936Smmel 1286296936Smmel /* Put port to reset. */ 1287296936Smmel reg = AFI_RD4(sc, port->afi_pex_ctrl); 1288296936Smmel reg &= ~AFI_PEX_CTRL_RST_L; 1289296936Smmel AFI_WR4(sc, port->afi_pex_ctrl, reg); 1290296936Smmel AFI_RD4(sc, port->afi_pex_ctrl); 1291296936Smmel DELAY(10); 1292296936Smmel 1293296936Smmel /* Enable clocks. */ 1294296936Smmel reg |= AFI_PEX_CTRL_REFCLK_EN; 1295296936Smmel reg |= AFI_PEX_CTRL_CLKREQ_EN; 1296296936Smmel reg |= AFI_PEX_CTRL_OVERRIDE_EN; 1297296936Smmel AFI_WR4(sc, port->afi_pex_ctrl, reg); 1298296936Smmel AFI_RD4(sc, port->afi_pex_ctrl); 1299296936Smmel DELAY(100); 1300296936Smmel 1301296936Smmel /* Release reset. */ 1302296936Smmel reg |= AFI_PEX_CTRL_RST_L; 1303296936Smmel AFI_WR4(sc, port->afi_pex_ctrl, reg); 1304296936Smmel 1305296936Smmel rv = tegra_pcib_wait_for_link(sc, port); 1306296936Smmel if (bootverbose) 1307296936Smmel device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n", 1308296936Smmel port->port_idx, port->num_lanes, 1309296936Smmel port->num_lanes > 1 ? "s": "", 1310296936Smmel rv == 0 ? "up": "down"); 1311296936Smmel} 1312296936Smmel 1313296936Smmel 1314296936Smmelstatic void 1315296936Smmeltegra_pcib_port_disable(struct tegra_pcib_softc *sc, uint32_t port_num) 1316296936Smmel{ 1317296936Smmel struct tegra_pcib_port *port; 1318296936Smmel uint32_t reg; 1319296936Smmel 1320296936Smmel port = sc->ports[port_num]; 1321296936Smmel 1322296936Smmel /* Put port to reset. */ 1323296936Smmel reg = AFI_RD4(sc, port->afi_pex_ctrl); 1324296936Smmel reg &= ~AFI_PEX_CTRL_RST_L; 1325296936Smmel AFI_WR4(sc, port->afi_pex_ctrl, reg); 1326296936Smmel AFI_RD4(sc, port->afi_pex_ctrl); 1327296936Smmel DELAY(10); 1328296936Smmel 1329296936Smmel /* Disable clocks. */ 1330296936Smmel reg &= ~AFI_PEX_CTRL_CLKREQ_EN; 1331296936Smmel reg &= ~AFI_PEX_CTRL_REFCLK_EN; 1332296936Smmel AFI_WR4(sc, port->afi_pex_ctrl, reg); 1333296936Smmel 1334296936Smmel if (bootverbose) 1335296936Smmel device_printf(sc->dev, " port %d (%d lane%s): Disabled\n", 1336296936Smmel port->port_idx, port->num_lanes, 1337296936Smmel port->num_lanes > 1 ? "s": ""); 1338296936Smmel} 1339296936Smmel 1340296936Smmelstatic void 1341296936Smmeltegra_pcib_set_bar(struct tegra_pcib_softc *sc, int bar, uint32_t axi, 1342296936Smmel uint64_t fpci, uint32_t size, int is_memory) 1343296936Smmel{ 1344296936Smmel uint32_t fpci_reg; 1345296936Smmel uint32_t axi_reg; 1346296936Smmel uint32_t size_reg; 1347296936Smmel 1348296936Smmel axi_reg = axi & ~0xFFF; 1349296936Smmel size_reg = size >> 12; 1350296936Smmel fpci_reg = (uint32_t)(fpci >> 8) & ~0xF; 1351296936Smmel fpci_reg |= is_memory ? 0x1 : 0x0; 1352296936Smmel AFI_WR4(sc, bars[bar].axi_start, axi_reg); 1353296936Smmel AFI_WR4(sc, bars[bar].size, size_reg); 1354296936Smmel AFI_WR4(sc, bars[bar].fpci_start, fpci_reg); 1355296936Smmel} 1356296936Smmel 1357296936Smmelstatic int 1358296936Smmeltegra_pcib_enable(struct tegra_pcib_softc *sc, uint32_t port) 1359296936Smmel{ 1360296936Smmel int rv; 1361296936Smmel int i; 1362296936Smmel uint32_t reg; 1363296936Smmel 1364296936Smmel rv = tegra_pcib_enable_fdt_resources(sc); 1365296936Smmel if (rv != 0) { 1366296936Smmel device_printf(sc->dev, "Cannot enable FDT resources\n"); 1367296936Smmel return (rv); 1368296936Smmel } 1369296936Smmel /* Enable PLLE control. */ 1370296936Smmel reg = AFI_RD4(sc, AFI_PLLE_CONTROL); 1371296936Smmel reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; 1372296936Smmel reg |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; 1373296936Smmel AFI_WR4(sc, AFI_PLLE_CONTROL, reg); 1374296936Smmel 1375296936Smmel /* Set bias pad. */ 1376296936Smmel AFI_WR4(sc, AFI_PEXBIAS_CTRL, 0); 1377296936Smmel 1378296936Smmel /* Configure mode and ports. */ 1379296936Smmel reg = AFI_RD4(sc, AFI_PCIE_CONFIG); 1380296936Smmel reg &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; 1381296936Smmel if (sc->lanes_cfg == 0x14) { 1382296936Smmel if (bootverbose) 1383296936Smmel device_printf(sc->dev, 1384296936Smmel "Using x1,x4 configuration\n"); 1385296936Smmel reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1; 1386296936Smmel } else if (sc->lanes_cfg == 0x12) { 1387296936Smmel if (bootverbose) 1388296936Smmel device_printf(sc->dev, 1389296936Smmel "Using x1,x2 configuration\n"); 1390296936Smmel reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1; 1391296936Smmel } else { 1392296936Smmel device_printf(sc->dev, 1393296936Smmel "Unsupported lanes configuration: 0x%X\n", sc->lanes_cfg); 1394296936Smmel } 1395296936Smmel reg |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL; 1396296936Smmel for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1397296936Smmel if ((sc->ports[i] != NULL)) 1398296936Smmel reg &= 1399296936Smmel ~AFI_PCIE_CONFIG_PCIE_DISABLE(sc->ports[i]->port_idx); 1400296936Smmel } 1401296936Smmel AFI_WR4(sc, AFI_PCIE_CONFIG, reg); 1402296936Smmel 1403296936Smmel /* Enable Gen2 support. */ 1404296936Smmel reg = AFI_RD4(sc, AFI_FUSE); 1405296936Smmel reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; 1406296936Smmel AFI_WR4(sc, AFI_FUSE, reg); 1407296936Smmel 1408296936Smmel /* Enable PCIe phy. */ 1409296936Smmel rv = phy_enable(sc->dev, sc->phy); 1410296936Smmel if (rv != 0) { 1411296936Smmel device_printf(sc->dev, "Cannot enable phy\n"); 1412296936Smmel return (rv); 1413296936Smmel } 1414296936Smmel 1415296936Smmel rv = hwreset_deassert(sc->hwreset_pcie_x); 1416296936Smmel if (rv != 0) { 1417296936Smmel device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n"); 1418296936Smmel return (rv); 1419296936Smmel } 1420296936Smmel 1421296936Smmel /* Enable config space. */ 1422296936Smmel reg = AFI_RD4(sc, AFI_CONFIGURATION); 1423296936Smmel reg |= AFI_CONFIGURATION_EN_FPCI; 1424296936Smmel AFI_WR4(sc, AFI_CONFIGURATION, reg); 1425296936Smmel 1426296936Smmel /* Enable AFI errors. */ 1427296936Smmel reg = 0; 1428296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_SLVERR); 1429296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_DECERR); 1430296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_SLVERR); 1431296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_DECERR); 1432296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_WRERR); 1433296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_SM_MSG); 1434296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_DFPCI_DECERR); 1435296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_AXI_DECERR); 1436296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT); 1437296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE); 1438296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE); 1439296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE); 1440296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE); 1441296936Smmel reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_P2P_ERROR); 1442296936Smmel AFI_WR4(sc, AFI_AFI_INTR_ENABLE, reg); 1443296936Smmel AFI_WR4(sc, AFI_SM_INTR_ENABLE, 0xffffffff); 1444296936Smmel 1445296936Smmel /* Enable INT, disable MSI. */ 1446296936Smmel AFI_WR4(sc, AFI_INTR_MASK, AFI_INTR_MASK_INT_MASK); 1447296936Smmel 1448296936Smmel /* Mask all FPCI errors. */ 1449296936Smmel AFI_WR4(sc, AFI_FPCI_ERROR_MASKS, 0); 1450296936Smmel 1451296936Smmel /* Setup AFI translation windows. */ 1452296936Smmel /* BAR 0 - type 1 extended configuration. */ 1453296936Smmel tegra_pcib_set_bar(sc, 0, rman_get_start(sc->cfg_mem_res), 1454296936Smmel FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0); 1455296936Smmel 1456296936Smmel /* BAR 1 - downstream I/O. */ 1457296936Smmel tegra_pcib_set_bar(sc, 1, sc->io_range.host_addr, FPCI_MAP_IO, 1458296936Smmel sc->io_range.size, 0); 1459296936Smmel 1460296936Smmel /* BAR 2 - downstream prefetchable memory 1:1. */ 1461296936Smmel tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host_addr, 1462296936Smmel sc->pref_mem_range.host_addr, sc->pref_mem_range.size, 1); 1463296936Smmel 1464296936Smmel /* BAR 3 - downstream not prefetchable memory 1:1 .*/ 1465296936Smmel tegra_pcib_set_bar(sc, 3, sc->mem_range.host_addr, 1466296936Smmel sc->mem_range.host_addr, sc->mem_range.size, 1); 1467296936Smmel 1468296936Smmel /* BAR 3-8 clear. */ 1469296936Smmel tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0); 1470296936Smmel tegra_pcib_set_bar(sc, 5, 0, 0, 0, 0); 1471296936Smmel tegra_pcib_set_bar(sc, 6, 0, 0, 0, 0); 1472296936Smmel tegra_pcib_set_bar(sc, 7, 0, 0, 0, 0); 1473296936Smmel tegra_pcib_set_bar(sc, 8, 0, 0, 0, 0); 1474296936Smmel 1475296936Smmel /* MSI BAR - clear. */ 1476296936Smmel tegra_pcib_set_bar(sc, 9, 0, 0, 0, 0); 1477296936Smmel return(0); 1478296936Smmel} 1479296936Smmel 1480296936Smmelstatic int 1481296936Smmeltegra_pcib_probe(device_t dev) 1482296936Smmel{ 1483296936Smmel if (!ofw_bus_status_okay(dev)) 1484296936Smmel return (ENXIO); 1485296936Smmel 1486296936Smmel if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 1487296936Smmel device_set_desc(dev, "Nvidia Integrated PCI/PCI-E Controller"); 1488296936Smmel return (BUS_PROBE_DEFAULT); 1489296936Smmel } 1490296936Smmel return (ENXIO); 1491296936Smmel} 1492296936Smmel 1493296936Smmelstatic int 1494296936Smmeltegra_pcib_attach(device_t dev) 1495296936Smmel{ 1496296936Smmel struct tegra_pcib_softc *sc; 1497296936Smmel phandle_t node; 1498296936Smmel uint32_t unit; 1499296936Smmel int rv; 1500296936Smmel int rid; 1501296936Smmel int nranges; 1502296936Smmel struct tegra_pci_range *ranges; 1503296936Smmel struct tegra_pcib_port *port; 1504296936Smmel int i; 1505296936Smmel 1506296936Smmel sc = device_get_softc(dev); 1507296936Smmel sc->dev = dev; 1508296936Smmel unit = fdt_get_unit(dev); 1509296936Smmel mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF); 1510296936Smmel 1511296936Smmel 1512296936Smmel node = ofw_bus_get_node(dev); 1513296936Smmel 1514296936Smmel rv = tegra_pcib_parse_fdt_resources(sc, node); 1515296936Smmel if (rv != 0) { 1516296936Smmel device_printf(dev, "Cannot get FDT resources\n"); 1517296936Smmel return (rv); 1518296936Smmel } 1519296936Smmel 1520296936Smmel nranges = tegra_pci_get_ranges(node, &ranges); 1521296936Smmel if (nranges != 5) { 1522296936Smmel device_printf(sc->dev, "Unexpected number of ranges: %d\n", 1523296936Smmel nranges); 1524296936Smmel rv = ENXIO; 1525296936Smmel goto out; 1526296936Smmel } 1527296936Smmel 1528296936Smmel /* Allocate bus_space resources. */ 1529296936Smmel rid = 0; 1530296936Smmel sc->pads_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1531296936Smmel RF_ACTIVE); 1532296936Smmel if (sc->pads_mem_res == NULL) { 1533296936Smmel device_printf(dev, "Cannot allocate PADS register\n"); 1534296936Smmel rv = ENXIO; 1535296936Smmel goto out; 1536296936Smmel } 1537296936Smmel /* 1538296936Smmel * XXX - FIXME 1539296936Smmel * tag for config space is not filled when RF_ALLOCATED flag is used. 1540296936Smmel */ 1541296936Smmel sc->bus_tag = rman_get_bustag(sc->pads_mem_res); 1542296936Smmel 1543296936Smmel rid = 1; 1544296936Smmel sc->afi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1545296936Smmel RF_ACTIVE); 1546296936Smmel if (sc->afi_mem_res == NULL) { 1547296936Smmel device_printf(dev, "Cannot allocate AFI register\n"); 1548296936Smmel rv = ENXIO; 1549296936Smmel goto out; 1550296936Smmel } 1551296936Smmel 1552296936Smmel rid = 2; 1553296936Smmel sc->cfg_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1554296936Smmel RF_ALLOCATED); 1555296936Smmel if (sc->cfg_mem_res == NULL) { 1556296936Smmel device_printf(dev, "Cannot allocate config space memory\n"); 1557296936Smmel rv = ENXIO; 1558296936Smmel goto out; 1559296936Smmel } 1560296936Smmel sc->cfg_base_addr = rman_get_start(sc->cfg_mem_res); 1561296936Smmel 1562296936Smmel 1563296936Smmel /* Map RP slots */ 1564296936Smmel for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1565296936Smmel if (sc->ports[i] == NULL) 1566296936Smmel continue; 1567296936Smmel port = sc->ports[i]; 1568296936Smmel rv = bus_space_map(sc->bus_tag, port->rp_base_addr, 1569296936Smmel port->rp_size, 0, &port->cfg_handle); 1570296936Smmel if (rv != 0) { 1571296936Smmel device_printf(sc->dev, "Cannot allocate memory for " 1572296936Smmel "port: %d\n", i); 1573296936Smmel rv = ENXIO; 1574296936Smmel goto out; 1575296936Smmel } 1576296936Smmel } 1577296936Smmel 1578296936Smmel /* 1579296936Smmel * Get PCI interrupt info. 1580296936Smmel */ 1581296936Smmel ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(pcell_t)); 1582296936Smmel rid = 0; 1583296936Smmel sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1584296936Smmel RF_ACTIVE | RF_SHAREABLE); 1585296936Smmel if (sc->irq_res == NULL) { 1586296936Smmel device_printf(dev, "Cannot allocate IRQ resources\n"); 1587296936Smmel rv = ENXIO; 1588296936Smmel goto out; 1589296936Smmel } 1590296936Smmel 1591296936Smmel rid = 1; 1592296936Smmel sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1593296936Smmel RF_ACTIVE); 1594296936Smmel if (sc->irq_res == NULL) { 1595296936Smmel device_printf(dev, "Cannot allocate MSI IRQ resources\n"); 1596296936Smmel rv = ENXIO; 1597296936Smmel goto out; 1598296936Smmel } 1599296936Smmel 1600296936Smmel if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 1601296936Smmel tegra_pci_intr, NULL, sc, &sc->intr_cookie)) { 1602296936Smmel device_printf(dev, "cannot setup interrupt handler\n"); 1603296936Smmel rv = ENXIO; 1604296936Smmel goto out; 1605296936Smmel } 1606296936Smmel 1607296936Smmel /* Memory management. */ 1608296936Smmel rv = tegra_pcib_decode_ranges(sc, ranges, nranges); 1609296936Smmel if (rv != 0) 1610296936Smmel goto out; 1611296936Smmel 1612296936Smmel rv = tegra_pcib_rman_init(sc); 1613296936Smmel if (rv != 0) 1614296936Smmel goto out; 1615296936Smmel free(ranges, M_DEVBUF); 1616296936Smmel ranges = NULL; 1617296936Smmel 1618296936Smmel /* 1619296936Smmel * Enable PCIE device. 1620296936Smmel */ 1621296936Smmel rv = tegra_pcib_enable(sc, unit); 1622296936Smmel if (rv != 0) 1623296936Smmel goto out; 1624296936Smmel for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { 1625296936Smmel if (sc->ports[i] == NULL) 1626296936Smmel continue; 1627296936Smmel if (sc->ports[i]->enabled) 1628296936Smmel tegra_pcib_port_enable(sc, i); 1629296936Smmel else 1630296936Smmel tegra_pcib_port_disable(sc, i); 1631296936Smmel } 1632296936Smmel 1633296936Smmel device_add_child(dev, "pci", -1); 1634296936Smmel 1635296936Smmel return (bus_generic_attach(dev)); 1636296936Smmel 1637296936Smmelout: 1638296936Smmel if (ranges != NULL) 1639296936Smmel free(ranges, M_DEVBUF); 1640296936Smmel 1641296936Smmel return (rv); 1642296936Smmel} 1643296936Smmel 1644296936Smmel 1645296936Smmelstatic device_method_t tegra_pcib_methods[] = { 1646296936Smmel /* Device interface */ 1647296936Smmel DEVMETHOD(device_probe, tegra_pcib_probe), 1648296936Smmel DEVMETHOD(device_attach, tegra_pcib_attach), 1649296936Smmel 1650296936Smmel /* Bus interface */ 1651296936Smmel DEVMETHOD(bus_read_ivar, tegra_pcib_read_ivar), 1652296936Smmel DEVMETHOD(bus_write_ivar, tegra_pcib_write_ivar), 1653296936Smmel DEVMETHOD(bus_alloc_resource, tegra_pcib_alloc_resource), 1654296936Smmel DEVMETHOD(bus_adjust_resource, tegra_pcib_adjust_resource), 1655296936Smmel DEVMETHOD(bus_release_resource, tegra_pcib_release_resource), 1656296936Smmel DEVMETHOD(bus_activate_resource, tegra_pcib_pcie_activate_resource), 1657296936Smmel DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1658296936Smmel DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1659296936Smmel DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 1660296936Smmel 1661296936Smmel /* pcib interface */ 1662296936Smmel DEVMETHOD(pcib_maxslots, tegra_pcib_maxslots), 1663296936Smmel DEVMETHOD(pcib_read_config, tegra_pcib_read_config), 1664296936Smmel DEVMETHOD(pcib_write_config, tegra_pcib_write_config), 1665296936Smmel DEVMETHOD(pcib_route_interrupt, tegra_pcib_route_interrupt), 1666296936Smmel 1667296936Smmel#if defined(TEGRA_PCI_MSI) 1668296936Smmel DEVMETHOD(pcib_alloc_msi, tegra_pcib_alloc_msi), 1669296936Smmel DEVMETHOD(pcib_release_msi, tegra_pcib_release_msi), 1670296936Smmel DEVMETHOD(pcib_map_msi, tegra_pcib_map_msi), 1671296936Smmel#endif 1672296936Smmel 1673296936Smmel /* OFW bus interface */ 1674296936Smmel DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 1675296936Smmel DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 1676296936Smmel DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 1677296936Smmel DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 1678296936Smmel DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 1679296936Smmel 1680296936Smmel DEVMETHOD_END 1681296936Smmel}; 1682296936Smmel 1683296936Smmelstatic driver_t tegra_pcib_driver = { 1684296936Smmel "pcib", 1685296936Smmel tegra_pcib_methods, 1686296936Smmel sizeof(struct tegra_pcib_softc), 1687296936Smmel}; 1688296936Smmel 1689296936Smmeldevclass_t pcib_devclass; 1690296936Smmel 1691298627SbrDRIVER_MODULE(pcib, simplebus, tegra_pcib_driver, pcib_devclass, 0, 0); 1692