1896e217aSJessica Clarke /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3896e217aSJessica Clarke * 4896e217aSJessica Clarke * Copyright 2021 Jessica Clarke <jrtc27@FreeBSD.org> 5896e217aSJessica Clarke * 6896e217aSJessica Clarke * Redistribution and use in source and binary forms, with or without 7896e217aSJessica Clarke * modification, are permitted provided that the following conditions 8896e217aSJessica Clarke * are met: 9896e217aSJessica Clarke * 1. Redistributions of source code must retain the above copyright 10896e217aSJessica Clarke * notice, this list of conditions and the following disclaimer. 11896e217aSJessica Clarke * 2. Redistributions in binary form must reproduce the above copyright 12896e217aSJessica Clarke * notice, this list of conditions and the following disclaimer in the 13896e217aSJessica Clarke * documentation and/or other materials provided with the distribution. 14896e217aSJessica Clarke * 15896e217aSJessica Clarke * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16896e217aSJessica Clarke * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17896e217aSJessica Clarke * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18896e217aSJessica Clarke * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19896e217aSJessica Clarke * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20896e217aSJessica Clarke * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21896e217aSJessica Clarke * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22896e217aSJessica Clarke * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23896e217aSJessica Clarke * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24896e217aSJessica Clarke * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25896e217aSJessica Clarke * SUCH DAMAGE. 26896e217aSJessica Clarke * 27896e217aSJessica Clarke */ 28896e217aSJessica Clarke 29896e217aSJessica Clarke /* SiFive FU740 DesignWare PCIe driver */ 30896e217aSJessica Clarke 31896e217aSJessica Clarke #include <sys/cdefs.h> 32896e217aSJessica Clarke __FBSDID("$FreeBSD$"); 33896e217aSJessica Clarke 34896e217aSJessica Clarke #include <sys/param.h> 35896e217aSJessica Clarke #include <sys/systm.h> 36896e217aSJessica Clarke #include <sys/bus.h> 37896e217aSJessica Clarke #include <sys/gpio.h> 38896e217aSJessica Clarke #include <sys/kernel.h> 39896e217aSJessica Clarke #include <sys/module.h> 40896e217aSJessica Clarke #include <sys/rman.h> 41896e217aSJessica Clarke 42896e217aSJessica Clarke #include <machine/bus.h> 43896e217aSJessica Clarke #include <machine/intr.h> 44896e217aSJessica Clarke #include <machine/resource.h> 45896e217aSJessica Clarke 46896e217aSJessica Clarke #include <dev/extres/clk/clk.h> 47896e217aSJessica Clarke #include <dev/extres/hwreset/hwreset.h> 48896e217aSJessica Clarke #include <dev/gpio/gpiobusvar.h> 49896e217aSJessica Clarke #include <dev/ofw/ofw_bus.h> 50896e217aSJessica Clarke #include <dev/ofw/ofw_bus_subr.h> 51896e217aSJessica Clarke #include <dev/ofw/ofw_pci.h> 52896e217aSJessica Clarke #include <dev/ofw/ofwpci.h> 53896e217aSJessica Clarke #include <dev/pci/pcivar.h> 54896e217aSJessica Clarke #include <dev/pci/pcireg.h> 55896e217aSJessica Clarke #include <dev/pci/pcib_private.h> 56896e217aSJessica Clarke #include <dev/pci/pci_dw.h> 57896e217aSJessica Clarke 58896e217aSJessica Clarke #include "pcib_if.h" 59896e217aSJessica Clarke #include "pci_dw_if.h" 60896e217aSJessica Clarke 61896e217aSJessica Clarke #define FUDW_PHYS 2 62896e217aSJessica Clarke #define FUDW_LANES_PER_PHY 4 63896e217aSJessica Clarke 64896e217aSJessica Clarke #define FUDW_MGMT_PERST_N 0x0 65896e217aSJessica Clarke #define FUDW_MGMT_LTSSM_EN 0x10 66896e217aSJessica Clarke #define FUDW_MGMT_HOLD_PHY_RST 0x18 67896e217aSJessica Clarke #define FUDW_MGMT_DEVICE_TYPE 0x708 68896e217aSJessica Clarke #define FUDW_MGMT_DEVICE_TYPE_RC 0x4 69896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_REG(_n, _r) \ 70896e217aSJessica Clarke (0x860 + (_n) * 0x40 + FUDW_MGMT_PHY_CR_PARA_##_r) 71896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_ADDR 0x0 72896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_READ_EN 0x10 73896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_READ_DATA 0x18 74896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_SEL 0x20 75896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_WRITE_DATA 0x28 76896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_WRITE_EN 0x30 77896e217aSJessica Clarke #define FUDW_MGMT_PHY_CR_PARA_ACK 0x38 78896e217aSJessica Clarke 79896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE(_n) (0x1008 + (_n) * 0x100) 80896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_CDR_TRACK_EN (1 << 0) 81896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_LOS_THRESH (1 << 5) 82896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_TERM_EN (1 << 9) 83896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_TERM_ACDC (1 << 10) 84896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_EN (1 << 11) 85896e217aSJessica Clarke #define FUDW_MGMT_PHY_LANE_INIT \ 86896e217aSJessica Clarke (FUDW_MGMT_PHY_LANE_CDR_TRACK_EN | FUDW_MGMT_PHY_LANE_LOS_THRESH | \ 87896e217aSJessica Clarke FUDW_MGMT_PHY_LANE_TERM_EN | FUDW_MGMT_PHY_LANE_TERM_ACDC | \ 88896e217aSJessica Clarke FUDW_MGMT_PHY_LANE_EN) 89896e217aSJessica Clarke 90896e217aSJessica Clarke #define FUDW_DBI_PORT_DBG1 0x72c 91896e217aSJessica Clarke #define FUDW_DBI_PORT_DBG1_LINK_UP (1 << 4) 92896e217aSJessica Clarke #define FUDW_DBI_PORT_DBG1_LINK_IN_TRAINING (1 << 29) 93896e217aSJessica Clarke 94896e217aSJessica Clarke struct fupci_softc { 95896e217aSJessica Clarke struct pci_dw_softc dw_sc; 96896e217aSJessica Clarke device_t dev; 97896e217aSJessica Clarke struct resource *mgmt_res; 98896e217aSJessica Clarke gpio_pin_t porst_pin; 99896e217aSJessica Clarke gpio_pin_t pwren_pin; 100896e217aSJessica Clarke clk_t pcie_aux_clk; 101896e217aSJessica Clarke hwreset_t pcie_aux_rst; 102896e217aSJessica Clarke }; 103896e217aSJessica Clarke 104896e217aSJessica Clarke #define FUDW_MGMT_READ(_sc, _o) bus_read_4((_sc)->mgmt_res, (_o)) 105896e217aSJessica Clarke #define FUDW_MGMT_WRITE(_sc, _o, _v) bus_write_4((_sc)->mgmt_res, (_o), (_v)) 106896e217aSJessica Clarke 107896e217aSJessica Clarke static struct ofw_compat_data compat_data[] = { 108896e217aSJessica Clarke { "sifive,fu740-pcie", 1 }, 109896e217aSJessica Clarke { NULL, 0 }, 110896e217aSJessica Clarke }; 111896e217aSJessica Clarke 112896e217aSJessica Clarke /* Currently unused; included for completeness */ 113896e217aSJessica Clarke static int __unused 114896e217aSJessica Clarke fupci_phy_read(struct fupci_softc *sc, int phy, uint32_t reg, uint32_t *val) 115896e217aSJessica Clarke { 116896e217aSJessica Clarke unsigned timeout; 117896e217aSJessica Clarke uint32_t ack; 118896e217aSJessica Clarke 119896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ADDR), reg); 120896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_EN), 1); 121896e217aSJessica Clarke 122896e217aSJessica Clarke timeout = 10; 123896e217aSJessica Clarke do { 124896e217aSJessica Clarke ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 125896e217aSJessica Clarke if (ack != 0) 126896e217aSJessica Clarke break; 127896e217aSJessica Clarke DELAY(10); 128896e217aSJessica Clarke } while (--timeout > 0); 129896e217aSJessica Clarke 130896e217aSJessica Clarke if (timeout == 0) { 131896e217aSJessica Clarke device_printf(sc->dev, "Timeout waiting for read ACK\n"); 132896e217aSJessica Clarke return (ETIMEDOUT); 133896e217aSJessica Clarke } 134896e217aSJessica Clarke 135896e217aSJessica Clarke *val = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_DATA)); 136896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_EN), 0); 137896e217aSJessica Clarke 138896e217aSJessica Clarke timeout = 10; 139896e217aSJessica Clarke do { 140896e217aSJessica Clarke ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 141896e217aSJessica Clarke if (ack == 0) 142896e217aSJessica Clarke break; 143896e217aSJessica Clarke DELAY(10); 144896e217aSJessica Clarke } while (--timeout > 0); 145896e217aSJessica Clarke 146896e217aSJessica Clarke if (timeout == 0) { 147896e217aSJessica Clarke device_printf(sc->dev, "Timeout waiting for read un-ACK\n"); 148896e217aSJessica Clarke return (ETIMEDOUT); 149896e217aSJessica Clarke } 150896e217aSJessica Clarke 151896e217aSJessica Clarke return (0); 152896e217aSJessica Clarke } 153896e217aSJessica Clarke 154896e217aSJessica Clarke static int 155896e217aSJessica Clarke fupci_phy_write(struct fupci_softc *sc, int phy, uint32_t reg, uint32_t val) 156896e217aSJessica Clarke { 157896e217aSJessica Clarke unsigned timeout; 158896e217aSJessica Clarke uint32_t ack; 159896e217aSJessica Clarke 160896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ADDR), reg); 161896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_DATA), val); 162896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_EN), 1); 163896e217aSJessica Clarke 164896e217aSJessica Clarke timeout = 10; 165896e217aSJessica Clarke do { 166896e217aSJessica Clarke ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 167896e217aSJessica Clarke if (ack != 0) 168896e217aSJessica Clarke break; 169896e217aSJessica Clarke DELAY(10); 170896e217aSJessica Clarke } while (--timeout > 0); 171896e217aSJessica Clarke 172896e217aSJessica Clarke if (timeout == 0) { 173896e217aSJessica Clarke device_printf(sc->dev, "Timeout waiting for write ACK\n"); 174896e217aSJessica Clarke return (ETIMEDOUT); 175896e217aSJessica Clarke } 176896e217aSJessica Clarke 177896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_EN), 0); 178896e217aSJessica Clarke 179896e217aSJessica Clarke timeout = 10; 180896e217aSJessica Clarke do { 181896e217aSJessica Clarke ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 182896e217aSJessica Clarke if (ack == 0) 183896e217aSJessica Clarke break; 184896e217aSJessica Clarke DELAY(10); 185896e217aSJessica Clarke } while (--timeout > 0); 186896e217aSJessica Clarke 187896e217aSJessica Clarke if (timeout == 0) { 188896e217aSJessica Clarke device_printf(sc->dev, "Timeout waiting for write un-ACK\n"); 189896e217aSJessica Clarke return (ETIMEDOUT); 190896e217aSJessica Clarke } 191896e217aSJessica Clarke 192896e217aSJessica Clarke return (0); 193896e217aSJessica Clarke } 194896e217aSJessica Clarke 195896e217aSJessica Clarke static int 196896e217aSJessica Clarke fupci_phy_init(struct fupci_softc *sc) 197896e217aSJessica Clarke { 198896e217aSJessica Clarke device_t dev; 199896e217aSJessica Clarke int error, phy, lane; 200896e217aSJessica Clarke 201896e217aSJessica Clarke dev = sc->dev; 202896e217aSJessica Clarke 203896e217aSJessica Clarke /* Assert core power-on reset (active low) */ 204896e217aSJessica Clarke error = gpio_pin_set_active(sc->porst_pin, false); 205896e217aSJessica Clarke if (error != 0) { 206896e217aSJessica Clarke device_printf(dev, "Cannot assert power-on reset: %d\n", 207896e217aSJessica Clarke error); 208896e217aSJessica Clarke return (error); 209896e217aSJessica Clarke } 210896e217aSJessica Clarke 211896e217aSJessica Clarke /* Assert PERST_N */ 212896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PERST_N, 0); 213896e217aSJessica Clarke 214896e217aSJessica Clarke /* Enable power */ 215896e217aSJessica Clarke error = gpio_pin_set_active(sc->pwren_pin, true); 216896e217aSJessica Clarke if (error != 0) { 217896e217aSJessica Clarke device_printf(dev, "Cannot enable power: %d\n", error); 218896e217aSJessica Clarke return (error); 219896e217aSJessica Clarke } 220896e217aSJessica Clarke 221896e217aSJessica Clarke /* Hold PERST for 100ms as per the PCIe spec */ 222896e217aSJessica Clarke DELAY(100); 223896e217aSJessica Clarke 224896e217aSJessica Clarke /* Deassert PERST_N */ 225896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PERST_N, 1); 226896e217aSJessica Clarke 227896e217aSJessica Clarke /* Deassert core power-on reset (active low) */ 228896e217aSJessica Clarke error = gpio_pin_set_active(sc->porst_pin, true); 229896e217aSJessica Clarke if (error != 0) { 230896e217aSJessica Clarke device_printf(dev, "Cannot deassert power-on reset: %d\n", 231896e217aSJessica Clarke error); 232896e217aSJessica Clarke return (error); 233896e217aSJessica Clarke } 234896e217aSJessica Clarke 235896e217aSJessica Clarke /* Enable the aux clock */ 236896e217aSJessica Clarke error = clk_enable(sc->pcie_aux_clk); 237896e217aSJessica Clarke if (error != 0) { 238896e217aSJessica Clarke device_printf(dev, "Cannot enable aux clock: %d\n", error); 239896e217aSJessica Clarke return (error); 240896e217aSJessica Clarke } 241896e217aSJessica Clarke 242896e217aSJessica Clarke /* Hold LTSSM in reset whilst initialising the PHYs */ 243896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_HOLD_PHY_RST, 1); 244896e217aSJessica Clarke 245896e217aSJessica Clarke /* Deassert the aux reset */ 246896e217aSJessica Clarke error = hwreset_deassert(sc->pcie_aux_rst); 247896e217aSJessica Clarke if (error != 0) { 248896e217aSJessica Clarke device_printf(dev, "Cannot deassert aux reset: %d\n", error); 249896e217aSJessica Clarke return (error); 250896e217aSJessica Clarke } 251896e217aSJessica Clarke 252896e217aSJessica Clarke /* Enable control register interface */ 253896e217aSJessica Clarke for (phy = 0; phy < FUDW_PHYS; ++phy) 254896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, SEL), 1); 255896e217aSJessica Clarke 256896e217aSJessica Clarke /* Wait for enable to take effect */ 257896e217aSJessica Clarke DELAY(1); 258896e217aSJessica Clarke 259896e217aSJessica Clarke /* Initialise lane configuration */ 260896e217aSJessica Clarke for (phy = 0; phy < FUDW_PHYS; ++phy) { 261896e217aSJessica Clarke for (lane = 0; lane < FUDW_LANES_PER_PHY; ++lane) 262896e217aSJessica Clarke fupci_phy_write(sc, phy, FUDW_MGMT_PHY_LANE(lane), 263896e217aSJessica Clarke FUDW_MGMT_PHY_LANE_INIT); 264896e217aSJessica Clarke } 265896e217aSJessica Clarke 266896e217aSJessica Clarke /* Disable the aux clock whilst taking the LTSSM out of reset */ 267896e217aSJessica Clarke error = clk_disable(sc->pcie_aux_clk); 268896e217aSJessica Clarke if (error != 0) { 269896e217aSJessica Clarke device_printf(dev, "Cannot disable aux clock: %d\n", error); 270896e217aSJessica Clarke return (error); 271896e217aSJessica Clarke } 272896e217aSJessica Clarke 273896e217aSJessica Clarke /* Take LTSSM out of reset */ 274896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_HOLD_PHY_RST, 0); 275896e217aSJessica Clarke 276896e217aSJessica Clarke /* Enable the aux clock again */ 277896e217aSJessica Clarke error = clk_enable(sc->pcie_aux_clk); 278896e217aSJessica Clarke if (error != 0) { 279896e217aSJessica Clarke device_printf(dev, "Cannot re-enable aux clock: %d\n", error); 280896e217aSJessica Clarke return (error); 281896e217aSJessica Clarke } 282896e217aSJessica Clarke 283896e217aSJessica Clarke /* Put the controller in Root Complex mode */ 284896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_DEVICE_TYPE, FUDW_MGMT_DEVICE_TYPE_RC); 285896e217aSJessica Clarke 286896e217aSJessica Clarke return (0); 287896e217aSJessica Clarke } 288896e217aSJessica Clarke 289896e217aSJessica Clarke static void 290896e217aSJessica Clarke fupci_dbi_protect(struct fupci_softc *sc, bool protect) 291896e217aSJessica Clarke { 292896e217aSJessica Clarke uint32_t reg; 293896e217aSJessica Clarke 294896e217aSJessica Clarke reg = pci_dw_dbi_rd4(sc->dev, DW_MISC_CONTROL_1); 295896e217aSJessica Clarke if (protect) 296896e217aSJessica Clarke reg &= ~DBI_RO_WR_EN; 297896e217aSJessica Clarke else 298896e217aSJessica Clarke reg |= DBI_RO_WR_EN; 299896e217aSJessica Clarke pci_dw_dbi_wr4(sc->dev, DW_MISC_CONTROL_1, reg); 300896e217aSJessica Clarke } 301896e217aSJessica Clarke 302896e217aSJessica Clarke static int 303896e217aSJessica Clarke fupci_init(struct fupci_softc *sc) 304896e217aSJessica Clarke { 305896e217aSJessica Clarke /* Enable 32-bit I/O window */ 306896e217aSJessica Clarke fupci_dbi_protect(sc, false); 307896e217aSJessica Clarke pci_dw_dbi_wr2(sc->dev, PCIR_IOBASEL_1, 308896e217aSJessica Clarke (PCIM_BRIO_32 << 8) | PCIM_BRIO_32); 309896e217aSJessica Clarke fupci_dbi_protect(sc, true); 310896e217aSJessica Clarke 311896e217aSJessica Clarke /* Enable LTSSM */ 312896e217aSJessica Clarke FUDW_MGMT_WRITE(sc, FUDW_MGMT_LTSSM_EN, 1); 313896e217aSJessica Clarke 314896e217aSJessica Clarke return (0); 315896e217aSJessica Clarke } 316896e217aSJessica Clarke 317896e217aSJessica Clarke static int 318896e217aSJessica Clarke fupci_probe(device_t dev) 319896e217aSJessica Clarke { 320896e217aSJessica Clarke if (!ofw_bus_status_okay(dev)) 321896e217aSJessica Clarke return (ENXIO); 322896e217aSJessica Clarke 323896e217aSJessica Clarke if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 324896e217aSJessica Clarke return (ENXIO); 325896e217aSJessica Clarke 326896e217aSJessica Clarke device_set_desc(dev, "SiFive FU740 PCIe Controller"); 327896e217aSJessica Clarke 328896e217aSJessica Clarke return (BUS_PROBE_DEFAULT); 329896e217aSJessica Clarke } 330896e217aSJessica Clarke 331896e217aSJessica Clarke static int 332896e217aSJessica Clarke fupci_attach(device_t dev) 333896e217aSJessica Clarke { 334896e217aSJessica Clarke struct fupci_softc *sc; 335896e217aSJessica Clarke phandle_t node; 336896e217aSJessica Clarke int error, rid; 337896e217aSJessica Clarke 338896e217aSJessica Clarke sc = device_get_softc(dev); 339896e217aSJessica Clarke node = ofw_bus_get_node(dev); 340896e217aSJessica Clarke sc->dev = dev; 341896e217aSJessica Clarke 342896e217aSJessica Clarke rid = 0; 343896e217aSJessica Clarke error = ofw_bus_find_string_index(node, "reg-names", "dbi", &rid); 344896e217aSJessica Clarke if (error != 0) { 345896e217aSJessica Clarke device_printf(dev, "Cannot get DBI memory: %d\n", error); 346896e217aSJessica Clarke goto fail; 347896e217aSJessica Clarke } 348896e217aSJessica Clarke sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 349896e217aSJessica Clarke RF_ACTIVE); 350896e217aSJessica Clarke if (sc->dw_sc.dbi_res == NULL) { 351896e217aSJessica Clarke device_printf(dev, "Cannot allocate DBI memory\n"); 352896e217aSJessica Clarke error = ENXIO; 353896e217aSJessica Clarke goto fail; 354896e217aSJessica Clarke } 355896e217aSJessica Clarke 356896e217aSJessica Clarke rid = 0; 357896e217aSJessica Clarke error = ofw_bus_find_string_index(node, "reg-names", "mgmt", &rid); 358896e217aSJessica Clarke if (error != 0) { 359896e217aSJessica Clarke device_printf(dev, "Cannot get management space memory: %d\n", 360896e217aSJessica Clarke error); 361896e217aSJessica Clarke goto fail; 362896e217aSJessica Clarke } 363896e217aSJessica Clarke sc->mgmt_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 364896e217aSJessica Clarke RF_ACTIVE); 365896e217aSJessica Clarke if (sc->mgmt_res == NULL) { 366896e217aSJessica Clarke device_printf(dev, "Cannot allocate management space memory\n"); 367896e217aSJessica Clarke error = ENXIO; 368896e217aSJessica Clarke goto fail; 369896e217aSJessica Clarke } 370896e217aSJessica Clarke 371896e217aSJessica Clarke error = gpio_pin_get_by_ofw_property(dev, node, "reset-gpios", 372896e217aSJessica Clarke &sc->porst_pin); 373896e217aSJessica Clarke /* Old U-Boot device tree uses perstn-gpios */ 374896e217aSJessica Clarke if (error == ENOENT) 375896e217aSJessica Clarke error = gpio_pin_get_by_ofw_property(dev, node, "perstn-gpios", 376896e217aSJessica Clarke &sc->porst_pin); 377896e217aSJessica Clarke if (error != 0) { 378896e217aSJessica Clarke device_printf(dev, "Cannot get power-on reset GPIO: %d\n", 379896e217aSJessica Clarke error); 380896e217aSJessica Clarke goto fail; 381896e217aSJessica Clarke } 382896e217aSJessica Clarke error = gpio_pin_setflags(sc->porst_pin, GPIO_PIN_OUTPUT); 383896e217aSJessica Clarke if (error != 0) { 384896e217aSJessica Clarke device_printf(dev, "Cannot configure power-on reset GPIO: %d\n", 385896e217aSJessica Clarke error); 386896e217aSJessica Clarke goto fail; 387896e217aSJessica Clarke } 388896e217aSJessica Clarke 389896e217aSJessica Clarke error = gpio_pin_get_by_ofw_property(dev, node, "pwren-gpios", 390896e217aSJessica Clarke &sc->pwren_pin); 391896e217aSJessica Clarke if (error != 0) { 392896e217aSJessica Clarke device_printf(dev, "Cannot get power enable GPIO: %d\n", 393896e217aSJessica Clarke error); 394896e217aSJessica Clarke goto fail; 395896e217aSJessica Clarke } 396896e217aSJessica Clarke error = gpio_pin_setflags(sc->pwren_pin, GPIO_PIN_OUTPUT); 397896e217aSJessica Clarke if (error != 0) { 398896e217aSJessica Clarke device_printf(dev, "Cannot configure power enable GPIO: %d\n", 399896e217aSJessica Clarke error); 400896e217aSJessica Clarke goto fail; 401896e217aSJessica Clarke } 402896e217aSJessica Clarke 403896e217aSJessica Clarke error = clk_get_by_ofw_name(dev, node, "pcie_aux", &sc->pcie_aux_clk); 404896e217aSJessica Clarke /* Old U-Boot device tree uses pcieaux */ 405896e217aSJessica Clarke if (error == ENOENT) 406896e217aSJessica Clarke error = clk_get_by_ofw_name(dev, node, "pcieaux", 407896e217aSJessica Clarke &sc->pcie_aux_clk); 408896e217aSJessica Clarke if (error != 0) { 409896e217aSJessica Clarke device_printf(dev, "Cannot get aux clock: %d\n", error); 410896e217aSJessica Clarke goto fail; 411896e217aSJessica Clarke } 412896e217aSJessica Clarke 413896e217aSJessica Clarke error = hwreset_get_by_ofw_idx(dev, node, 0, &sc->pcie_aux_rst); 414896e217aSJessica Clarke if (error != 0) { 415896e217aSJessica Clarke device_printf(dev, "Cannot get aux reset: %d\n", error); 416896e217aSJessica Clarke goto fail; 417896e217aSJessica Clarke } 418896e217aSJessica Clarke 419896e217aSJessica Clarke error = fupci_phy_init(sc); 420896e217aSJessica Clarke if (error != 0) 421896e217aSJessica Clarke goto fail; 422896e217aSJessica Clarke 423896e217aSJessica Clarke error = pci_dw_init(dev); 424896e217aSJessica Clarke if (error != 0) 425896e217aSJessica Clarke goto fail; 426896e217aSJessica Clarke 427896e217aSJessica Clarke error = fupci_init(sc); 428896e217aSJessica Clarke if (error != 0) 429896e217aSJessica Clarke goto fail; 430896e217aSJessica Clarke 431896e217aSJessica Clarke return (bus_generic_attach(dev)); 432896e217aSJessica Clarke 433896e217aSJessica Clarke fail: 434896e217aSJessica Clarke /* XXX Cleanup */ 435896e217aSJessica Clarke return (error); 436896e217aSJessica Clarke } 437896e217aSJessica Clarke 438896e217aSJessica Clarke static int 439896e217aSJessica Clarke fupci_get_link(device_t dev, bool *status) 440896e217aSJessica Clarke { 441896e217aSJessica Clarke uint32_t reg; 442896e217aSJessica Clarke 443896e217aSJessica Clarke reg = pci_dw_dbi_rd4(dev, FUDW_DBI_PORT_DBG1); 444896e217aSJessica Clarke *status = (reg & FUDW_DBI_PORT_DBG1_LINK_UP) != 0 && 445896e217aSJessica Clarke (reg & FUDW_DBI_PORT_DBG1_LINK_IN_TRAINING) == 0; 446896e217aSJessica Clarke 447896e217aSJessica Clarke return (0); 448896e217aSJessica Clarke } 449896e217aSJessica Clarke 450896e217aSJessica Clarke static device_method_t fupci_methods[] = { 451896e217aSJessica Clarke /* Device interface */ 452896e217aSJessica Clarke DEVMETHOD(device_probe, fupci_probe), 453896e217aSJessica Clarke DEVMETHOD(device_attach, fupci_attach), 454896e217aSJessica Clarke 455896e217aSJessica Clarke /* PCI DW interface */ 456896e217aSJessica Clarke DEVMETHOD(pci_dw_get_link, fupci_get_link), 457896e217aSJessica Clarke 458896e217aSJessica Clarke DEVMETHOD_END 459896e217aSJessica Clarke }; 460896e217aSJessica Clarke 461896e217aSJessica Clarke DEFINE_CLASS_1(pcib, fupci_driver, fupci_methods, 462896e217aSJessica Clarke sizeof(struct fupci_softc), pci_dw_driver); 463bb32809bSJohn Baldwin DRIVER_MODULE(fu740_pci_dw, simplebus, fupci_driver, NULL, NULL); 464