1eed8b80fSAndrew Turner /*- 2eed8b80fSAndrew Turner * SPDX-License-Identifier: ISC 3eed8b80fSAndrew Turner * 4eed8b80fSAndrew Turner * Copyright (c) 2020 Dr Robert Harvey Crowston <crowston@protonmail.com> 5eed8b80fSAndrew Turner * 6eed8b80fSAndrew Turner * Permission to use, copy, modify, and distribute this software for any 7eed8b80fSAndrew Turner * purpose with or without fee is hereby granted, provided that the above 8eed8b80fSAndrew Turner * copyright notice and this permission notice appear in all copies. 9eed8b80fSAndrew Turner * 10eed8b80fSAndrew Turner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11eed8b80fSAndrew Turner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12eed8b80fSAndrew Turner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13eed8b80fSAndrew Turner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14eed8b80fSAndrew Turner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15eed8b80fSAndrew Turner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16eed8b80fSAndrew Turner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17eed8b80fSAndrew Turner * 18eed8b80fSAndrew Turner * 19eed8b80fSAndrew Turner * $FreeBSD$ 20eed8b80fSAndrew Turner * 21eed8b80fSAndrew Turner */ 22eed8b80fSAndrew Turner 23eed8b80fSAndrew Turner /* 24eed8b80fSAndrew Turner * BCM2838-compatible PCI-express controller. 25eed8b80fSAndrew Turner * 26eed8b80fSAndrew Turner * Broadcom likes to give the same chip lots of different names. The name of 27eed8b80fSAndrew Turner * this driver is taken from the Raspberry Pi 4 Broadcom 2838 chip. 28eed8b80fSAndrew Turner */ 29eed8b80fSAndrew Turner 30eed8b80fSAndrew Turner #include <sys/cdefs.h> 31eed8b80fSAndrew Turner __FBSDID("$FreeBSD$"); 32eed8b80fSAndrew Turner 33eed8b80fSAndrew Turner #include <sys/param.h> 34eed8b80fSAndrew Turner #include <sys/systm.h> 35eed8b80fSAndrew Turner #include <sys/endian.h> 36eed8b80fSAndrew Turner #include <sys/kernel.h> 37eed8b80fSAndrew Turner #include <sys/module.h> 38eed8b80fSAndrew Turner #include <sys/bus.h> 39eed8b80fSAndrew Turner #include <sys/proc.h> 40eed8b80fSAndrew Turner #include <sys/rman.h> 41eed8b80fSAndrew Turner #include <sys/intr.h> 42eed8b80fSAndrew Turner #include <sys/mutex.h> 43eed8b80fSAndrew Turner 44eed8b80fSAndrew Turner #include <dev/ofw/openfirm.h> 45eed8b80fSAndrew Turner #include <dev/ofw/ofw_bus.h> 46eed8b80fSAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 47eed8b80fSAndrew Turner 48eed8b80fSAndrew Turner #include <dev/pci/pci_host_generic.h> 49eed8b80fSAndrew Turner #include <dev/pci/pci_host_generic_fdt.h> 50eed8b80fSAndrew Turner #include <dev/pci/pcivar.h> 51eed8b80fSAndrew Turner #include <dev/pci/pcireg.h> 52eed8b80fSAndrew Turner #include <dev/pci/pcib_private.h> 53eed8b80fSAndrew Turner 54eed8b80fSAndrew Turner #include <machine/bus.h> 55eed8b80fSAndrew Turner #include <machine/intr.h> 56eed8b80fSAndrew Turner 57eed8b80fSAndrew Turner #include "pcib_if.h" 58eed8b80fSAndrew Turner #include "msi_if.h" 59eed8b80fSAndrew Turner 60eed8b80fSAndrew Turner #define PCI_ID_VAL3 0x43c 61eed8b80fSAndrew Turner #define CLASS_SHIFT 0x10 62eed8b80fSAndrew Turner #define SUBCLASS_SHIFT 0x8 63eed8b80fSAndrew Turner 64eed8b80fSAndrew Turner #define REG_CONTROLLER_HW_REV 0x406c 65eed8b80fSAndrew Turner #define REG_BRIDGE_CTRL 0x9210 66eed8b80fSAndrew Turner #define BRIDGE_DISABLE_FLAG 0x1 67eed8b80fSAndrew Turner #define BRIDGE_RESET_FLAG 0x2 68eed8b80fSAndrew Turner #define REG_BRIDGE_SERDES_MODE 0x4204 69ac89220bSMike Karels #define REG_DMA_CONFIG 0x4008 70ac89220bSMike Karels #define REG_DMA_WINDOW_LOW 0x4034 71ac89220bSMike Karels #define REG_DMA_WINDOW_HIGH 0x4038 72ac89220bSMike Karels #define REG_DMA_WINDOW_1 0x403c 73eed8b80fSAndrew Turner #define REG_BRIDGE_GISB_WINDOW 0x402c 74eed8b80fSAndrew Turner #define REG_BRIDGE_STATE 0x4068 75eed8b80fSAndrew Turner #define REG_BRIDGE_LINK_STATE 0x00bc 76ac89220bSMike Karels #define REG_BUS_WINDOW_LOW 0x400c 77ac89220bSMike Karels #define REG_BUS_WINDOW_HIGH 0x4010 78ac89220bSMike Karels #define REG_CPU_WINDOW_LOW 0x4070 79ac89220bSMike Karels #define REG_CPU_WINDOW_START_HIGH 0x4080 80ac89220bSMike Karels #define REG_CPU_WINDOW_END_HIGH 0x4084 81eed8b80fSAndrew Turner 82eed8b80fSAndrew Turner #define REG_MSI_ADDR_LOW 0x4044 83eed8b80fSAndrew Turner #define REG_MSI_ADDR_HIGH 0x4048 84eed8b80fSAndrew Turner #define REG_MSI_CONFIG 0x404c 85eed8b80fSAndrew Turner #define REG_MSI_CLR 0x4508 86eed8b80fSAndrew Turner #define REG_MSI_MASK_CLR 0x4514 87eed8b80fSAndrew Turner #define REG_MSI_RAISED 0x4500 88eed8b80fSAndrew Turner #define REG_MSI_EOI 0x4060 89eed8b80fSAndrew Turner #define NUM_MSI 32 90eed8b80fSAndrew Turner 91eed8b80fSAndrew Turner #define REG_EP_CONFIG_CHOICE 0x9000 92eed8b80fSAndrew Turner #define REG_EP_CONFIG_DATA 0x8000 93eed8b80fSAndrew Turner 94eed8b80fSAndrew Turner /* 95ac89220bSMike Karels * The system memory controller can address up to 16 GiB of physical memory 96ac89220bSMike Karels * (although at time of writing the largest memory size available for purchase 97ac89220bSMike Karels * is 8 GiB). However, the system DMA controller is capable of accessing only a 98ac89220bSMike Karels * limited portion of the address space. Worse, the PCI-e controller has further 99ac89220bSMike Karels * constraints for DMA, and those limitations are not wholly clear to the 100ac89220bSMike Karels * author. NetBSD and Linux allow DMA on the lower 3 GiB of the physical memory, 101ac89220bSMike Karels * but experimentation shows DMA performed above 960 MiB results in data 102ac89220bSMike Karels * corruption with this driver. The limit of 960 MiB is taken from OpenBSD, but 103ac89220bSMike Karels * apparently that value was chosen for satisfying a constraint of an unrelated 104ac89220bSMike Karels * peripheral. 105ac89220bSMike Karels * 106ac89220bSMike Karels * Whatever the true maximum address, 960 MiB works. 107eed8b80fSAndrew Turner */ 108ac89220bSMike Karels #define DMA_HIGH_LIMIT 0x3c000000 109ac89220bSMike Karels #define MAX_MEMORY_LOG2 0x21 110ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_LOW (MAX_MEMORY_LOG2 - 0xf) 111ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_HIGH 0x0 112ac89220bSMike Karels #define DMA_WINDOW_ENABLE 0x3000 113ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_CONFIG \ 114ac89220bSMike Karels (((MAX_MEMORY_LOG2 - 0xf) << 0x1b) | DMA_WINDOW_ENABLE) 115ac89220bSMike Karels 116eed8b80fSAndrew Turner #define REG_VALUE_MSI_CONFIG 0xffe06540 117eed8b80fSAndrew Turner 118eed8b80fSAndrew Turner struct bcm_pcib_irqsrc { 119eed8b80fSAndrew Turner struct intr_irqsrc isrc; 120eed8b80fSAndrew Turner u_int irq; 121eed8b80fSAndrew Turner bool allocated; 122eed8b80fSAndrew Turner }; 123eed8b80fSAndrew Turner 124eed8b80fSAndrew Turner struct bcm_pcib_softc { 125eed8b80fSAndrew Turner struct generic_pcie_fdt_softc base; 126eed8b80fSAndrew Turner device_t dev; 127ac89220bSMike Karels bus_dma_tag_t dmat; 128eed8b80fSAndrew Turner struct mtx config_mtx; 129eed8b80fSAndrew Turner struct mtx msi_mtx; 130eed8b80fSAndrew Turner struct resource *msi_irq_res; 131eed8b80fSAndrew Turner void *msi_intr_cookie; 132eed8b80fSAndrew Turner struct bcm_pcib_irqsrc *msi_isrcs; 133eed8b80fSAndrew Turner pci_addr_t msi_addr; 134eed8b80fSAndrew Turner }; 135eed8b80fSAndrew Turner 136eed8b80fSAndrew Turner static struct ofw_compat_data compat_data[] = { 137eed8b80fSAndrew Turner {"brcm,bcm2711-pcie", 1}, 138eed8b80fSAndrew Turner {"brcm,bcm7211-pcie", 1}, 139eed8b80fSAndrew Turner {"brcm,bcm7445-pcie", 1}, 140eed8b80fSAndrew Turner {NULL, 0} 141eed8b80fSAndrew Turner }; 142eed8b80fSAndrew Turner 143eed8b80fSAndrew Turner static int 144eed8b80fSAndrew Turner bcm_pcib_probe(device_t dev) 145eed8b80fSAndrew Turner { 146eed8b80fSAndrew Turner 147eed8b80fSAndrew Turner if (!ofw_bus_status_okay(dev)) 148eed8b80fSAndrew Turner return (ENXIO); 149eed8b80fSAndrew Turner 150eed8b80fSAndrew Turner if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 151eed8b80fSAndrew Turner return (ENXIO); 152eed8b80fSAndrew Turner 153eed8b80fSAndrew Turner device_set_desc(dev, 154eed8b80fSAndrew Turner "BCM2838-compatible PCI-express controller"); 155eed8b80fSAndrew Turner return (BUS_PROBE_DEFAULT); 156eed8b80fSAndrew Turner } 157eed8b80fSAndrew Turner 158ac89220bSMike Karels static bus_dma_tag_t 159ac89220bSMike Karels bcm_pcib_get_dma_tag(device_t dev, device_t child) 160ac89220bSMike Karels { 161ac89220bSMike Karels struct bcm_pcib_softc *sc; 162ac89220bSMike Karels 163ac89220bSMike Karels sc = device_get_softc(dev); 164ac89220bSMike Karels return (sc->dmat); 165ac89220bSMike Karels } 166ac89220bSMike Karels 167eed8b80fSAndrew Turner static void 168eed8b80fSAndrew Turner bcm_pcib_set_reg(struct bcm_pcib_softc *sc, uint32_t reg, uint32_t val) 169eed8b80fSAndrew Turner { 170eed8b80fSAndrew Turner 171eed8b80fSAndrew Turner bus_space_write_4(sc->base.base.bst, sc->base.base.bsh, reg, 172eed8b80fSAndrew Turner htole32(val)); 173eed8b80fSAndrew Turner } 174eed8b80fSAndrew Turner 175eed8b80fSAndrew Turner static uint32_t 176eed8b80fSAndrew Turner bcm_pcib_read_reg(struct bcm_pcib_softc *sc, uint32_t reg) 177eed8b80fSAndrew Turner { 178eed8b80fSAndrew Turner 179eed8b80fSAndrew Turner return (le32toh(bus_space_read_4(sc->base.base.bst, sc->base.base.bsh, 180eed8b80fSAndrew Turner reg))); 181eed8b80fSAndrew Turner } 182eed8b80fSAndrew Turner 183eed8b80fSAndrew Turner static void 184eed8b80fSAndrew Turner bcm_pcib_reset_controller(struct bcm_pcib_softc *sc) 185eed8b80fSAndrew Turner { 186eed8b80fSAndrew Turner uint32_t val; 187eed8b80fSAndrew Turner 188eed8b80fSAndrew Turner val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL); 189eed8b80fSAndrew Turner val = val | BRIDGE_RESET_FLAG | BRIDGE_DISABLE_FLAG; 190eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val); 191eed8b80fSAndrew Turner 192eed8b80fSAndrew Turner DELAY(100); 193eed8b80fSAndrew Turner 194eed8b80fSAndrew Turner val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL); 195eed8b80fSAndrew Turner val = val & ~BRIDGE_RESET_FLAG; 196eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val); 197eed8b80fSAndrew Turner 198eed8b80fSAndrew Turner DELAY(100); 199eed8b80fSAndrew Turner 200eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_SERDES_MODE, 0); 201eed8b80fSAndrew Turner 202eed8b80fSAndrew Turner DELAY(100); 203eed8b80fSAndrew Turner } 204eed8b80fSAndrew Turner 205eed8b80fSAndrew Turner static void 206eed8b80fSAndrew Turner bcm_pcib_enable_controller(struct bcm_pcib_softc *sc) 207eed8b80fSAndrew Turner { 208eed8b80fSAndrew Turner uint32_t val; 209eed8b80fSAndrew Turner 210eed8b80fSAndrew Turner val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL); 211eed8b80fSAndrew Turner val = val & ~BRIDGE_DISABLE_FLAG; 212eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val); 213eed8b80fSAndrew Turner 214eed8b80fSAndrew Turner DELAY(100); 215eed8b80fSAndrew Turner } 216eed8b80fSAndrew Turner 217eed8b80fSAndrew Turner static int 218eed8b80fSAndrew Turner bcm_pcib_check_ranges(device_t dev) 219eed8b80fSAndrew Turner { 220eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 221eed8b80fSAndrew Turner struct pcie_range *ranges; 222eed8b80fSAndrew Turner int error = 0, i; 223eed8b80fSAndrew Turner 224eed8b80fSAndrew Turner sc = device_get_softc(dev); 225eed8b80fSAndrew Turner ranges = &sc->base.base.ranges[0]; 226eed8b80fSAndrew Turner 227eed8b80fSAndrew Turner /* The first range needs to be non-zero. */ 228eed8b80fSAndrew Turner if (ranges[0].size == 0) { 229eed8b80fSAndrew Turner device_printf(dev, "error: first outbound memory range " 230eed8b80fSAndrew Turner "(pci addr: 0x%jx, cpu addr: 0x%jx) has zero size.\n", 231eed8b80fSAndrew Turner ranges[0].pci_base, ranges[0].phys_base); 232eed8b80fSAndrew Turner error = ENXIO; 233eed8b80fSAndrew Turner } 234eed8b80fSAndrew Turner 235eed8b80fSAndrew Turner /* 236eed8b80fSAndrew Turner * The controller can actually handle three distinct ranges, but we 237eed8b80fSAndrew Turner * only implement support for one. 238eed8b80fSAndrew Turner */ 239eed8b80fSAndrew Turner for (i = 1; (bootverbose || error) && i < MAX_RANGES_TUPLES; ++i) { 240eed8b80fSAndrew Turner if (ranges[i].size > 0) 241eed8b80fSAndrew Turner device_printf(dev, 242eed8b80fSAndrew Turner "note: outbound memory range %d (pci addr: 0x%jx, " 243eed8b80fSAndrew Turner "cpu addr: 0x%jx, size: 0x%jx) will be ignored.\n", 244eed8b80fSAndrew Turner i, ranges[i].pci_base, ranges[i].phys_base, 245eed8b80fSAndrew Turner ranges[i].size); 246eed8b80fSAndrew Turner } 247eed8b80fSAndrew Turner 248eed8b80fSAndrew Turner return (error); 249eed8b80fSAndrew Turner } 250eed8b80fSAndrew Turner 251eed8b80fSAndrew Turner static const char * 252eed8b80fSAndrew Turner bcm_pcib_link_state_string(uint32_t mode) 253eed8b80fSAndrew Turner { 254eed8b80fSAndrew Turner 255eed8b80fSAndrew Turner switch(mode & PCIEM_LINK_STA_SPEED) { 256eed8b80fSAndrew Turner case 0: 257eed8b80fSAndrew Turner return ("not up"); 258eed8b80fSAndrew Turner case 1: 259eed8b80fSAndrew Turner return ("2.5 GT/s"); 260eed8b80fSAndrew Turner case 2: 261eed8b80fSAndrew Turner return ("5.0 GT/s"); 262eed8b80fSAndrew Turner case 4: 263eed8b80fSAndrew Turner return ("8.0 GT/s"); 264eed8b80fSAndrew Turner default: 265eed8b80fSAndrew Turner return ("unknown"); 266eed8b80fSAndrew Turner } 267eed8b80fSAndrew Turner } 268eed8b80fSAndrew Turner 269eed8b80fSAndrew Turner static bus_addr_t 270eed8b80fSAndrew Turner bcm_get_offset_and_prepare_config(struct bcm_pcib_softc *sc, u_int bus, 271eed8b80fSAndrew Turner u_int slot, u_int func, u_int reg) 272eed8b80fSAndrew Turner { 273eed8b80fSAndrew Turner /* 274eed8b80fSAndrew Turner * Config for an end point is only available through a narrow window for 275eed8b80fSAndrew Turner * one end point at a time. We first tell the controller which end point 276eed8b80fSAndrew Turner * we want, then access it through the window. 277eed8b80fSAndrew Turner */ 278eed8b80fSAndrew Turner uint32_t func_index; 279eed8b80fSAndrew Turner 280eed8b80fSAndrew Turner if (bus == 0 && slot == 0 && func == 0) 281eed8b80fSAndrew Turner /* 282eed8b80fSAndrew Turner * Special case for root device; its config is always available 283eed8b80fSAndrew Turner * through the zero-offset. 284eed8b80fSAndrew Turner */ 285eed8b80fSAndrew Turner return (reg); 286eed8b80fSAndrew Turner 287eed8b80fSAndrew Turner /* Tell the controller to show us the config in question. */ 288eed8b80fSAndrew Turner func_index = PCIE_ADDR_OFFSET(bus, slot, func, 0); 289eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_EP_CONFIG_CHOICE, func_index); 290eed8b80fSAndrew Turner 291eed8b80fSAndrew Turner return (REG_EP_CONFIG_DATA + reg); 292eed8b80fSAndrew Turner } 293eed8b80fSAndrew Turner 294eed8b80fSAndrew Turner static bool 295eed8b80fSAndrew Turner bcm_pcib_is_valid_quad(struct bcm_pcib_softc *sc, u_int bus, u_int slot, 296eed8b80fSAndrew Turner u_int func, u_int reg) 297eed8b80fSAndrew Turner { 298eed8b80fSAndrew Turner 299eed8b80fSAndrew Turner if ((bus < sc->base.base.bus_start) || (bus > sc->base.base.bus_end)) 300eed8b80fSAndrew Turner return (false); 301eed8b80fSAndrew Turner if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) 302eed8b80fSAndrew Turner return (false); 303eed8b80fSAndrew Turner 304eed8b80fSAndrew Turner if (bus == 0 && slot == 0 && func == 0) 305eed8b80fSAndrew Turner return (true); 306eed8b80fSAndrew Turner if (bus == 0) 307eed8b80fSAndrew Turner /* 308eed8b80fSAndrew Turner * Probing other slots and funcs on bus 0 will lock up the 309eed8b80fSAndrew Turner * memory controller. 310eed8b80fSAndrew Turner */ 311eed8b80fSAndrew Turner return (false); 312eed8b80fSAndrew Turner 313eed8b80fSAndrew Turner return (true); 314eed8b80fSAndrew Turner } 315eed8b80fSAndrew Turner 316eed8b80fSAndrew Turner static uint32_t 317eed8b80fSAndrew Turner bcm_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 318eed8b80fSAndrew Turner int bytes) 319eed8b80fSAndrew Turner { 320eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 321eed8b80fSAndrew Turner bus_space_handle_t h; 322eed8b80fSAndrew Turner bus_space_tag_t t; 323eed8b80fSAndrew Turner bus_addr_t offset; 324eed8b80fSAndrew Turner uint32_t data; 325eed8b80fSAndrew Turner 326eed8b80fSAndrew Turner sc = device_get_softc(dev); 327eed8b80fSAndrew Turner if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg)) 328eed8b80fSAndrew Turner return (~0U); 329eed8b80fSAndrew Turner 330eed8b80fSAndrew Turner mtx_lock(&sc->config_mtx); 331eed8b80fSAndrew Turner offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg); 332eed8b80fSAndrew Turner 333eed8b80fSAndrew Turner t = sc->base.base.bst; 334eed8b80fSAndrew Turner h = sc->base.base.bsh; 335eed8b80fSAndrew Turner 336eed8b80fSAndrew Turner switch (bytes) { 337eed8b80fSAndrew Turner case 1: 338eed8b80fSAndrew Turner data = bus_space_read_1(t, h, offset); 339eed8b80fSAndrew Turner break; 340eed8b80fSAndrew Turner case 2: 341eed8b80fSAndrew Turner data = le16toh(bus_space_read_2(t, h, offset)); 342eed8b80fSAndrew Turner break; 343eed8b80fSAndrew Turner case 4: 344eed8b80fSAndrew Turner data = le32toh(bus_space_read_4(t, h, offset)); 345eed8b80fSAndrew Turner break; 346eed8b80fSAndrew Turner default: 347eed8b80fSAndrew Turner data = ~0U; 348eed8b80fSAndrew Turner break; 349eed8b80fSAndrew Turner } 350eed8b80fSAndrew Turner 351eed8b80fSAndrew Turner mtx_unlock(&sc->config_mtx); 352eed8b80fSAndrew Turner return (data); 353eed8b80fSAndrew Turner } 354eed8b80fSAndrew Turner 355eed8b80fSAndrew Turner static void 356eed8b80fSAndrew Turner bcm_pcib_write_config(device_t dev, u_int bus, u_int slot, 357eed8b80fSAndrew Turner u_int func, u_int reg, uint32_t val, int bytes) 358eed8b80fSAndrew Turner { 359eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 360eed8b80fSAndrew Turner bus_space_handle_t h; 361eed8b80fSAndrew Turner bus_space_tag_t t; 362eed8b80fSAndrew Turner uint32_t offset; 363eed8b80fSAndrew Turner 364eed8b80fSAndrew Turner sc = device_get_softc(dev); 365eed8b80fSAndrew Turner if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg)) 366eed8b80fSAndrew Turner return; 367eed8b80fSAndrew Turner 368eed8b80fSAndrew Turner mtx_lock(&sc->config_mtx); 369eed8b80fSAndrew Turner offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg); 370eed8b80fSAndrew Turner 371eed8b80fSAndrew Turner t = sc->base.base.bst; 372eed8b80fSAndrew Turner h = sc->base.base.bsh; 373eed8b80fSAndrew Turner 374eed8b80fSAndrew Turner switch (bytes) { 375eed8b80fSAndrew Turner case 1: 376eed8b80fSAndrew Turner bus_space_write_1(t, h, offset, val); 377eed8b80fSAndrew Turner break; 378eed8b80fSAndrew Turner case 2: 379eed8b80fSAndrew Turner bus_space_write_2(t, h, offset, htole16(val)); 380eed8b80fSAndrew Turner break; 381eed8b80fSAndrew Turner case 4: 382eed8b80fSAndrew Turner bus_space_write_4(t, h, offset, htole32(val)); 383eed8b80fSAndrew Turner break; 384eed8b80fSAndrew Turner default: 385eed8b80fSAndrew Turner break; 386eed8b80fSAndrew Turner } 387eed8b80fSAndrew Turner 388eed8b80fSAndrew Turner mtx_unlock(&sc->config_mtx); 389eed8b80fSAndrew Turner } 390eed8b80fSAndrew Turner 391eed8b80fSAndrew Turner static void 392eed8b80fSAndrew Turner bcm_pcib_msi_intr_process(struct bcm_pcib_softc *sc, uint32_t interrupt_bitmap, 393eed8b80fSAndrew Turner struct trapframe *tf) 394eed8b80fSAndrew Turner { 395eed8b80fSAndrew Turner struct bcm_pcib_irqsrc *irqsrc; 396eed8b80fSAndrew Turner uint32_t bit, irq; 397eed8b80fSAndrew Turner 398eed8b80fSAndrew Turner while ((bit = ffs(interrupt_bitmap))) { 399eed8b80fSAndrew Turner irq = bit - 1; 400eed8b80fSAndrew Turner 401eed8b80fSAndrew Turner /* Acknowledge interrupt. */ 402eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_CLR, 1 << irq); 403eed8b80fSAndrew Turner 404eed8b80fSAndrew Turner /* Send EOI. */ 405eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_EOI, 1); 406eed8b80fSAndrew Turner 407eed8b80fSAndrew Turner /* Despatch to handler. */ 408eed8b80fSAndrew Turner irqsrc = &sc->msi_isrcs[irq]; 409eed8b80fSAndrew Turner if (intr_isrc_dispatch(&irqsrc->isrc, tf)) 410eed8b80fSAndrew Turner device_printf(sc->dev, 411eed8b80fSAndrew Turner "note: unexpected interrupt (%d) triggered.\n", 412eed8b80fSAndrew Turner irq); 413eed8b80fSAndrew Turner 414eed8b80fSAndrew Turner /* Done with this interrupt. */ 415eed8b80fSAndrew Turner interrupt_bitmap = interrupt_bitmap & ~(1 << irq); 416eed8b80fSAndrew Turner } 417eed8b80fSAndrew Turner } 418eed8b80fSAndrew Turner 419eed8b80fSAndrew Turner static int 420eed8b80fSAndrew Turner bcm_pcib_msi_intr(void *arg) 421eed8b80fSAndrew Turner { 422eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 423eed8b80fSAndrew Turner struct trapframe *tf; 424eed8b80fSAndrew Turner uint32_t interrupt_bitmap; 425eed8b80fSAndrew Turner 426eed8b80fSAndrew Turner sc = (struct bcm_pcib_softc *) arg; 427eed8b80fSAndrew Turner tf = curthread->td_intr_frame; 428eed8b80fSAndrew Turner 429eed8b80fSAndrew Turner while ((interrupt_bitmap = bcm_pcib_read_reg(sc, REG_MSI_RAISED))) 430eed8b80fSAndrew Turner bcm_pcib_msi_intr_process(sc, interrupt_bitmap, tf); 431eed8b80fSAndrew Turner 432eed8b80fSAndrew Turner return (FILTER_HANDLED); 433eed8b80fSAndrew Turner } 434eed8b80fSAndrew Turner 435eed8b80fSAndrew Turner static int 436eed8b80fSAndrew Turner bcm_pcib_alloc_msi(device_t dev, device_t child, int count, int maxcount, 437eed8b80fSAndrew Turner device_t *pic, struct intr_irqsrc **srcs) 438eed8b80fSAndrew Turner { 439eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 440eed8b80fSAndrew Turner int first_int, i; 441eed8b80fSAndrew Turner 442eed8b80fSAndrew Turner sc = device_get_softc(dev); 443eed8b80fSAndrew Turner mtx_lock(&sc->msi_mtx); 444eed8b80fSAndrew Turner 445eed8b80fSAndrew Turner /* Find a continguous region of free message-signalled interrupts. */ 446eed8b80fSAndrew Turner for (first_int = 0; first_int + count < NUM_MSI; ) { 447eed8b80fSAndrew Turner for (i = first_int; i < first_int + count; ++i) { 448eed8b80fSAndrew Turner if (sc->msi_isrcs[i].allocated) 449eed8b80fSAndrew Turner goto next; 450eed8b80fSAndrew Turner } 451eed8b80fSAndrew Turner goto found; 452eed8b80fSAndrew Turner next: 453eed8b80fSAndrew Turner first_int = i + 1; 454eed8b80fSAndrew Turner } 455eed8b80fSAndrew Turner 456eed8b80fSAndrew Turner /* No appropriate region available. */ 457eed8b80fSAndrew Turner mtx_unlock(&sc->msi_mtx); 458eed8b80fSAndrew Turner device_printf(dev, "warning: failed to allocate %d MSI messages.\n", 459eed8b80fSAndrew Turner count); 460eed8b80fSAndrew Turner return (ENXIO); 461eed8b80fSAndrew Turner 462eed8b80fSAndrew Turner found: 463eed8b80fSAndrew Turner /* Mark the messages as in use. */ 464eed8b80fSAndrew Turner for (i = 0; i < count; ++i) { 465eed8b80fSAndrew Turner sc->msi_isrcs[i + first_int].allocated = true; 466eed8b80fSAndrew Turner srcs[i] = &(sc->msi_isrcs[i + first_int].isrc); 467eed8b80fSAndrew Turner } 468eed8b80fSAndrew Turner 469eed8b80fSAndrew Turner mtx_unlock(&sc->msi_mtx); 470eed8b80fSAndrew Turner *pic = device_get_parent(dev); 471eed8b80fSAndrew Turner 472eed8b80fSAndrew Turner return (0); 473eed8b80fSAndrew Turner } 474eed8b80fSAndrew Turner 475eed8b80fSAndrew Turner static int 476eed8b80fSAndrew Turner bcm_pcib_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 477eed8b80fSAndrew Turner uint64_t *addr, uint32_t *data) 478eed8b80fSAndrew Turner { 479eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 480eed8b80fSAndrew Turner struct bcm_pcib_irqsrc *msi_msg; 481eed8b80fSAndrew Turner 482eed8b80fSAndrew Turner sc = device_get_softc(dev); 483eed8b80fSAndrew Turner msi_msg = (struct bcm_pcib_irqsrc *) isrc; 484eed8b80fSAndrew Turner 485eed8b80fSAndrew Turner *addr = sc->msi_addr; 486eed8b80fSAndrew Turner *data = (REG_VALUE_MSI_CONFIG & 0xffff) | msi_msg->irq; 487eed8b80fSAndrew Turner return (0); 488eed8b80fSAndrew Turner } 489eed8b80fSAndrew Turner 490eed8b80fSAndrew Turner static int 491eed8b80fSAndrew Turner bcm_pcib_release_msi(device_t dev, device_t child, int count, 492eed8b80fSAndrew Turner struct intr_irqsrc **isrc) 493eed8b80fSAndrew Turner { 494eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 495eed8b80fSAndrew Turner struct bcm_pcib_irqsrc *msi_isrc; 496eed8b80fSAndrew Turner int i; 497eed8b80fSAndrew Turner 498eed8b80fSAndrew Turner sc = device_get_softc(dev); 499eed8b80fSAndrew Turner mtx_lock(&sc->msi_mtx); 500eed8b80fSAndrew Turner 501eed8b80fSAndrew Turner for (i = 0; i < count; i++) { 502eed8b80fSAndrew Turner msi_isrc = (struct bcm_pcib_irqsrc *) isrc[i]; 503eed8b80fSAndrew Turner msi_isrc->allocated = false; 504eed8b80fSAndrew Turner } 505eed8b80fSAndrew Turner 506eed8b80fSAndrew Turner mtx_unlock(&sc->msi_mtx); 507eed8b80fSAndrew Turner return (0); 508eed8b80fSAndrew Turner } 509eed8b80fSAndrew Turner 510eed8b80fSAndrew Turner static int 511eed8b80fSAndrew Turner bcm_pcib_msi_attach(device_t dev) 512eed8b80fSAndrew Turner { 513eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 514eed8b80fSAndrew Turner phandle_t node, xref; 515eed8b80fSAndrew Turner char const *bcm_name; 516eed8b80fSAndrew Turner int i, rid; 517eed8b80fSAndrew Turner 518eed8b80fSAndrew Turner sc = device_get_softc(dev); 519eed8b80fSAndrew Turner sc->msi_addr = 0xffffffffc; 520eed8b80fSAndrew Turner 521eed8b80fSAndrew Turner /* Clear any pending interrupts. */ 522eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_CLR, 0xffffffff); 523eed8b80fSAndrew Turner 524eed8b80fSAndrew Turner rid = 1; 525eed8b80fSAndrew Turner sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 526eed8b80fSAndrew Turner RF_ACTIVE); 527eed8b80fSAndrew Turner if (sc->msi_irq_res == NULL) { 528eed8b80fSAndrew Turner device_printf(dev, "could not allocate MSI irq resource.\n"); 529eed8b80fSAndrew Turner return (ENXIO); 530eed8b80fSAndrew Turner } 531eed8b80fSAndrew Turner 532eed8b80fSAndrew Turner sc->msi_isrcs = malloc(sizeof(*sc->msi_isrcs) * NUM_MSI, M_DEVBUF, 533eed8b80fSAndrew Turner M_WAITOK | M_ZERO); 534eed8b80fSAndrew Turner 535eed8b80fSAndrew Turner int error = bus_setup_intr(dev, sc->msi_irq_res, INTR_TYPE_BIO | 536eed8b80fSAndrew Turner INTR_MPSAFE, bcm_pcib_msi_intr, NULL, sc, &sc->msi_intr_cookie); 537eed8b80fSAndrew Turner if (error) { 538eed8b80fSAndrew Turner device_printf(dev, "error: failed to setup MSI handler.\n"); 539eed8b80fSAndrew Turner return (ENXIO); 540eed8b80fSAndrew Turner } 541eed8b80fSAndrew Turner 542eed8b80fSAndrew Turner bcm_name = device_get_nameunit(dev); 543eed8b80fSAndrew Turner for (i = 0; i < NUM_MSI; i++) { 544eed8b80fSAndrew Turner sc->msi_isrcs[i].irq = i; 545eed8b80fSAndrew Turner error = intr_isrc_register(&sc->msi_isrcs[i].isrc, dev, 0, 546eed8b80fSAndrew Turner "%s,%u", bcm_name, i); 547eed8b80fSAndrew Turner if (error) { 548eed8b80fSAndrew Turner device_printf(dev, 549eed8b80fSAndrew Turner "error: failed to register interrupt %d.\n", i); 550eed8b80fSAndrew Turner return (ENXIO); 551eed8b80fSAndrew Turner } 552eed8b80fSAndrew Turner } 553eed8b80fSAndrew Turner 554eed8b80fSAndrew Turner node = ofw_bus_get_node(dev); 555eed8b80fSAndrew Turner xref = OF_xref_from_node(node); 556eed8b80fSAndrew Turner OF_device_register_xref(xref, dev); 557eed8b80fSAndrew Turner 558eed8b80fSAndrew Turner error = intr_msi_register(dev, xref); 559eed8b80fSAndrew Turner if (error) 560eed8b80fSAndrew Turner return (ENXIO); 561eed8b80fSAndrew Turner 562eed8b80fSAndrew Turner mtx_init(&sc->msi_mtx, "bcm_pcib: msi_mtx", NULL, MTX_DEF); 563eed8b80fSAndrew Turner 564eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_MASK_CLR, 0xffffffff); 565eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_ADDR_LOW, (sc->msi_addr & 0xffffffff) | 1); 566eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_ADDR_HIGH, (sc->msi_addr >> 32)); 567eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_MSI_CONFIG, REG_VALUE_MSI_CONFIG); 568eed8b80fSAndrew Turner 569eed8b80fSAndrew Turner return (0); 570eed8b80fSAndrew Turner } 571eed8b80fSAndrew Turner 572eed8b80fSAndrew Turner static void 573eed8b80fSAndrew Turner bcm_pcib_relocate_bridge_window(device_t dev) 574eed8b80fSAndrew Turner { 575eed8b80fSAndrew Turner /* 576eed8b80fSAndrew Turner * In principle an out-of-bounds bridge window could be automatically 577eed8b80fSAndrew Turner * adjusted at resource-activation time to lie within the bus address 578eed8b80fSAndrew Turner * space by pcib_grow_window(), but that is not possible because the 579eed8b80fSAndrew Turner * out-of-bounds resource allocation fails at allocation time. Instead, 580eed8b80fSAndrew Turner * we will just fix up the window on the controller here, before it is 581eed8b80fSAndrew Turner * re-discovered by pcib_probe_windows(). 582eed8b80fSAndrew Turner */ 583eed8b80fSAndrew Turner 584eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 585eed8b80fSAndrew Turner pci_addr_t base, size, new_base, new_limit; 586eed8b80fSAndrew Turner uint16_t val; 587eed8b80fSAndrew Turner 588eed8b80fSAndrew Turner sc = device_get_softc(dev); 589eed8b80fSAndrew Turner 590eed8b80fSAndrew Turner val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMBASE_1, 2); 591eed8b80fSAndrew Turner base = PCI_PPBMEMBASE(0, val); 592eed8b80fSAndrew Turner 593eed8b80fSAndrew Turner val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, 2); 594eed8b80fSAndrew Turner size = PCI_PPBMEMLIMIT(0, val) - base; 595eed8b80fSAndrew Turner 596eed8b80fSAndrew Turner new_base = sc->base.base.ranges[0].pci_base; 597eed8b80fSAndrew Turner val = (uint16_t) (new_base >> 16); 598eed8b80fSAndrew Turner bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMBASE_1, val, 2); 599eed8b80fSAndrew Turner 600eed8b80fSAndrew Turner new_limit = new_base + size; 601eed8b80fSAndrew Turner val = (uint16_t) (new_limit >> 16); 602eed8b80fSAndrew Turner bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, val, 2); 603eed8b80fSAndrew Turner } 604eed8b80fSAndrew Turner 605eed8b80fSAndrew Turner static uint32_t 606eed8b80fSAndrew Turner encode_cpu_window_low(pci_addr_t phys_base, bus_size_t size) 607eed8b80fSAndrew Turner { 608eed8b80fSAndrew Turner 609eed8b80fSAndrew Turner return (((phys_base >> 0x10) & 0xfff0) | 610eed8b80fSAndrew Turner ((phys_base + size - 1) & 0xfff00000)); 611eed8b80fSAndrew Turner } 612eed8b80fSAndrew Turner 613eed8b80fSAndrew Turner static uint32_t 614eed8b80fSAndrew Turner encode_cpu_window_start_high(pci_addr_t phys_base) 615eed8b80fSAndrew Turner { 616eed8b80fSAndrew Turner 617eed8b80fSAndrew Turner return ((phys_base >> 0x20) & 0xff); 618eed8b80fSAndrew Turner } 619eed8b80fSAndrew Turner 620eed8b80fSAndrew Turner static uint32_t 621eed8b80fSAndrew Turner encode_cpu_window_end_high(pci_addr_t phys_base, bus_size_t size) 622eed8b80fSAndrew Turner { 623eed8b80fSAndrew Turner 624eed8b80fSAndrew Turner return (((phys_base + size - 1) >> 0x20) & 0xff); 625eed8b80fSAndrew Turner } 626eed8b80fSAndrew Turner 627eed8b80fSAndrew Turner static int 628eed8b80fSAndrew Turner bcm_pcib_attach(device_t dev) 629eed8b80fSAndrew Turner { 630eed8b80fSAndrew Turner struct bcm_pcib_softc *sc; 631eed8b80fSAndrew Turner pci_addr_t phys_base, pci_base; 632eed8b80fSAndrew Turner bus_size_t size; 633eed8b80fSAndrew Turner uint32_t hardware_rev, bridge_state, link_state; 634eed8b80fSAndrew Turner int error, tries; 635eed8b80fSAndrew Turner 636eed8b80fSAndrew Turner sc = device_get_softc(dev); 637eed8b80fSAndrew Turner sc->dev = dev; 638eed8b80fSAndrew Turner 639ac89220bSMike Karels /* 640ac89220bSMike Karels * This tag will be used in preference to the one created in 641ac89220bSMike Karels * pci_host_generic.c. 642ac89220bSMike Karels */ 643ac89220bSMike Karels error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 644ac89220bSMike Karels 1, 0, /* alignment, bounds */ 645ac89220bSMike Karels DMA_HIGH_LIMIT, /* lowaddr */ 646ac89220bSMike Karels BUS_SPACE_MAXADDR, /* highaddr */ 647ac89220bSMike Karels NULL, NULL, /* filter, filterarg */ 648ac89220bSMike Karels DMA_HIGH_LIMIT, /* maxsize */ 649ac89220bSMike Karels BUS_SPACE_UNRESTRICTED, /* nsegments */ 650ac89220bSMike Karels DMA_HIGH_LIMIT, /* maxsegsize */ 651ac89220bSMike Karels 0, /* flags */ 652ac89220bSMike Karels NULL, NULL, /* lockfunc, lockarg */ 653ac89220bSMike Karels &sc->dmat); 654ac89220bSMike Karels if (error) 655ac89220bSMike Karels return (error); 656ac89220bSMike Karels 657eed8b80fSAndrew Turner error = pci_host_generic_setup_fdt(dev); 658eed8b80fSAndrew Turner if (error) 659eed8b80fSAndrew Turner return (error); 660eed8b80fSAndrew Turner 661eed8b80fSAndrew Turner error = bcm_pcib_check_ranges(dev); 662eed8b80fSAndrew Turner if (error) 663eed8b80fSAndrew Turner return (error); 664eed8b80fSAndrew Turner 665eed8b80fSAndrew Turner mtx_init(&sc->config_mtx, "bcm_pcib: config_mtx", NULL, MTX_DEF); 666eed8b80fSAndrew Turner 667eed8b80fSAndrew Turner bcm_pcib_reset_controller(sc); 668eed8b80fSAndrew Turner 669eed8b80fSAndrew Turner hardware_rev = bcm_pcib_read_reg(sc, REG_CONTROLLER_HW_REV) & 0xffff; 670eed8b80fSAndrew Turner device_printf(dev, "hardware identifies as revision 0x%x.\n", 671eed8b80fSAndrew Turner hardware_rev); 672eed8b80fSAndrew Turner 673eed8b80fSAndrew Turner /* 674eed8b80fSAndrew Turner * Set PCI->CPU memory window. This encodes the inbound window showing 675ac89220bSMike Karels * the system memory to the controller. 676eed8b80fSAndrew Turner */ 677ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_DMA_WINDOW_LOW, REG_VALUE_DMA_WINDOW_LOW); 678ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_DMA_WINDOW_HIGH, REG_VALUE_DMA_WINDOW_HIGH); 679ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_DMA_CONFIG, REG_VALUE_DMA_WINDOW_CONFIG); 680ac89220bSMike Karels 681eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_GISB_WINDOW, 0); 682ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_DMA_WINDOW_1, 0); 683eed8b80fSAndrew Turner 684eed8b80fSAndrew Turner bcm_pcib_enable_controller(sc); 685eed8b80fSAndrew Turner 686eed8b80fSAndrew Turner /* Wait for controller to start. */ 687eed8b80fSAndrew Turner for(tries = 0; ; ++tries) { 688eed8b80fSAndrew Turner bridge_state = bcm_pcib_read_reg(sc, REG_BRIDGE_STATE); 689eed8b80fSAndrew Turner 690eed8b80fSAndrew Turner if ((bridge_state & 0x30) == 0x30) 691eed8b80fSAndrew Turner /* Controller ready. */ 692eed8b80fSAndrew Turner break; 693eed8b80fSAndrew Turner 694eed8b80fSAndrew Turner if (tries > 100) { 695eed8b80fSAndrew Turner device_printf(dev, 696eed8b80fSAndrew Turner "error: controller failed to start.\n"); 697eed8b80fSAndrew Turner return (ENXIO); 698eed8b80fSAndrew Turner } 699eed8b80fSAndrew Turner 700eed8b80fSAndrew Turner DELAY(1000); 701eed8b80fSAndrew Turner } 702eed8b80fSAndrew Turner 703eed8b80fSAndrew Turner link_state = bcm_pcib_read_reg(sc, REG_BRIDGE_LINK_STATE) >> 0x10; 704eed8b80fSAndrew Turner if (!link_state) { 705eed8b80fSAndrew Turner device_printf(dev, "error: controller started but link is not " 706eed8b80fSAndrew Turner "up.\n"); 707eed8b80fSAndrew Turner return (ENXIO); 708eed8b80fSAndrew Turner } 709eed8b80fSAndrew Turner if (bootverbose) 710eed8b80fSAndrew Turner device_printf(dev, "note: reported link speed is %s.\n", 711eed8b80fSAndrew Turner bcm_pcib_link_state_string(link_state)); 712eed8b80fSAndrew Turner 713eed8b80fSAndrew Turner /* 714eed8b80fSAndrew Turner * Set the CPU->PCI memory window. The map in this direction is not 1:1. 715eed8b80fSAndrew Turner * Addresses seen by the CPU need to be adjusted to make sense to the 716eed8b80fSAndrew Turner * controller as they pass through the window. 717eed8b80fSAndrew Turner */ 718eed8b80fSAndrew Turner pci_base = sc->base.base.ranges[0].pci_base; 719eed8b80fSAndrew Turner phys_base = sc->base.base.ranges[0].phys_base; 720eed8b80fSAndrew Turner size = sc->base.base.ranges[0].size; 721eed8b80fSAndrew Turner 722ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_BUS_WINDOW_LOW, pci_base & 0xffffffff); 723ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_BUS_WINDOW_HIGH, pci_base >> 32); 724eed8b80fSAndrew Turner 725ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_CPU_WINDOW_LOW, 726eed8b80fSAndrew Turner encode_cpu_window_low(phys_base, size)); 727ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_CPU_WINDOW_START_HIGH, 728eed8b80fSAndrew Turner encode_cpu_window_start_high(phys_base)); 729ac89220bSMike Karels bcm_pcib_set_reg(sc, REG_CPU_WINDOW_END_HIGH, 730eed8b80fSAndrew Turner encode_cpu_window_end_high(phys_base, size)); 731eed8b80fSAndrew Turner 732eed8b80fSAndrew Turner /* 733eed8b80fSAndrew Turner * The controller starts up declaring itself an endpoint; readvertise it 734eed8b80fSAndrew Turner * as a bridge. 735eed8b80fSAndrew Turner */ 736eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, PCI_ID_VAL3, 737eed8b80fSAndrew Turner PCIC_BRIDGE << CLASS_SHIFT | PCIS_BRIDGE_PCI << SUBCLASS_SHIFT); 738eed8b80fSAndrew Turner 739eed8b80fSAndrew Turner bcm_pcib_set_reg(sc, REG_BRIDGE_SERDES_MODE, 0x2); 740eed8b80fSAndrew Turner DELAY(100); 741eed8b80fSAndrew Turner 742eed8b80fSAndrew Turner bcm_pcib_relocate_bridge_window(dev); 743eed8b80fSAndrew Turner 744eed8b80fSAndrew Turner /* Configure interrupts. */ 745eed8b80fSAndrew Turner error = bcm_pcib_msi_attach(dev); 746eed8b80fSAndrew Turner if (error) 747eed8b80fSAndrew Turner return (error); 748eed8b80fSAndrew Turner 749eed8b80fSAndrew Turner /* Done. */ 750eed8b80fSAndrew Turner device_add_child(dev, "pci", -1); 751eed8b80fSAndrew Turner return (bus_generic_attach(dev)); 752eed8b80fSAndrew Turner } 753eed8b80fSAndrew Turner 754eed8b80fSAndrew Turner /* 755eed8b80fSAndrew Turner * Device method table. 756eed8b80fSAndrew Turner */ 757eed8b80fSAndrew Turner static device_method_t bcm_pcib_methods[] = { 758ac89220bSMike Karels /* Bus interface. */ 759ac89220bSMike Karels DEVMETHOD(bus_get_dma_tag, bcm_pcib_get_dma_tag), 760ac89220bSMike Karels 761eed8b80fSAndrew Turner /* Device interface. */ 762eed8b80fSAndrew Turner DEVMETHOD(device_probe, bcm_pcib_probe), 763eed8b80fSAndrew Turner DEVMETHOD(device_attach, bcm_pcib_attach), 764eed8b80fSAndrew Turner 765eed8b80fSAndrew Turner /* PCIB interface. */ 766eed8b80fSAndrew Turner DEVMETHOD(pcib_read_config, bcm_pcib_read_config), 767eed8b80fSAndrew Turner DEVMETHOD(pcib_write_config, bcm_pcib_write_config), 768eed8b80fSAndrew Turner 769eed8b80fSAndrew Turner /* MSI interface. */ 770eed8b80fSAndrew Turner DEVMETHOD(msi_alloc_msi, bcm_pcib_alloc_msi), 771eed8b80fSAndrew Turner DEVMETHOD(msi_release_msi, bcm_pcib_release_msi), 772eed8b80fSAndrew Turner DEVMETHOD(msi_map_msi, bcm_pcib_map_msi), 773eed8b80fSAndrew Turner 774eed8b80fSAndrew Turner DEVMETHOD_END 775eed8b80fSAndrew Turner }; 776eed8b80fSAndrew Turner 777eed8b80fSAndrew Turner DEFINE_CLASS_1(pcib, bcm_pcib_driver, bcm_pcib_methods, 778eed8b80fSAndrew Turner sizeof(struct bcm_pcib_softc), generic_pcie_fdt_driver); 779eed8b80fSAndrew Turner 780*82d4dc06SJohn Baldwin DRIVER_MODULE(bcm_pcib, simplebus, bcm_pcib_driver, 0, 0); 781ac89220bSMike Karels 782