1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2021 Jessica Clarke <jrtc27@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 /* SiFive FU740 DesignWare PCIe driver */ 30 31 #include <sys/cdefs.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/gpio.h> 36 #include <sys/kernel.h> 37 #include <sys/module.h> 38 #include <sys/rman.h> 39 40 #include <machine/bus.h> 41 #include <machine/intr.h> 42 #include <machine/resource.h> 43 44 #include <dev/extres/clk/clk.h> 45 #include <dev/extres/hwreset/hwreset.h> 46 #include <dev/gpio/gpiobusvar.h> 47 #include <dev/ofw/ofw_bus.h> 48 #include <dev/ofw/ofw_bus_subr.h> 49 #include <dev/ofw/ofw_pci.h> 50 #include <dev/ofw/ofwpci.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pcireg.h> 53 #include <dev/pci/pcib_private.h> 54 #include <dev/pci/pci_dw.h> 55 56 #include "pcib_if.h" 57 #include "pci_dw_if.h" 58 59 #define FUDW_PHYS 2 60 #define FUDW_LANES_PER_PHY 4 61 62 #define FUDW_MGMT_PERST_N 0x0 63 #define FUDW_MGMT_LTSSM_EN 0x10 64 #define FUDW_MGMT_HOLD_PHY_RST 0x18 65 #define FUDW_MGMT_DEVICE_TYPE 0x708 66 #define FUDW_MGMT_DEVICE_TYPE_RC 0x4 67 #define FUDW_MGMT_PHY_CR_PARA_REG(_n, _r) \ 68 (0x860 + (_n) * 0x40 + FUDW_MGMT_PHY_CR_PARA_##_r) 69 #define FUDW_MGMT_PHY_CR_PARA_ADDR 0x0 70 #define FUDW_MGMT_PHY_CR_PARA_READ_EN 0x10 71 #define FUDW_MGMT_PHY_CR_PARA_READ_DATA 0x18 72 #define FUDW_MGMT_PHY_CR_PARA_SEL 0x20 73 #define FUDW_MGMT_PHY_CR_PARA_WRITE_DATA 0x28 74 #define FUDW_MGMT_PHY_CR_PARA_WRITE_EN 0x30 75 #define FUDW_MGMT_PHY_CR_PARA_ACK 0x38 76 77 #define FUDW_MGMT_PHY_LANE(_n) (0x1008 + (_n) * 0x100) 78 #define FUDW_MGMT_PHY_LANE_CDR_TRACK_EN (1 << 0) 79 #define FUDW_MGMT_PHY_LANE_LOS_THRESH (1 << 5) 80 #define FUDW_MGMT_PHY_LANE_TERM_EN (1 << 9) 81 #define FUDW_MGMT_PHY_LANE_TERM_ACDC (1 << 10) 82 #define FUDW_MGMT_PHY_LANE_EN (1 << 11) 83 #define FUDW_MGMT_PHY_LANE_INIT \ 84 (FUDW_MGMT_PHY_LANE_CDR_TRACK_EN | FUDW_MGMT_PHY_LANE_LOS_THRESH | \ 85 FUDW_MGMT_PHY_LANE_TERM_EN | FUDW_MGMT_PHY_LANE_TERM_ACDC | \ 86 FUDW_MGMT_PHY_LANE_EN) 87 88 #define FUDW_DBI_PORT_DBG1 0x72c 89 #define FUDW_DBI_PORT_DBG1_LINK_UP (1 << 4) 90 #define FUDW_DBI_PORT_DBG1_LINK_IN_TRAINING (1 << 29) 91 92 struct fupci_softc { 93 struct pci_dw_softc dw_sc; 94 device_t dev; 95 struct resource *mgmt_res; 96 gpio_pin_t porst_pin; 97 gpio_pin_t pwren_pin; 98 clk_t pcie_aux_clk; 99 hwreset_t pcie_aux_rst; 100 }; 101 102 #define FUDW_MGMT_READ(_sc, _o) bus_read_4((_sc)->mgmt_res, (_o)) 103 #define FUDW_MGMT_WRITE(_sc, _o, _v) bus_write_4((_sc)->mgmt_res, (_o), (_v)) 104 105 static struct ofw_compat_data compat_data[] = { 106 { "sifive,fu740-pcie", 1 }, 107 { NULL, 0 }, 108 }; 109 110 /* Currently unused; included for completeness */ 111 static int __unused 112 fupci_phy_read(struct fupci_softc *sc, int phy, uint32_t reg, uint32_t *val) 113 { 114 unsigned timeout; 115 uint32_t ack; 116 117 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ADDR), reg); 118 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_EN), 1); 119 120 timeout = 10; 121 do { 122 ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 123 if (ack != 0) 124 break; 125 DELAY(10); 126 } while (--timeout > 0); 127 128 if (timeout == 0) { 129 device_printf(sc->dev, "Timeout waiting for read ACK\n"); 130 return (ETIMEDOUT); 131 } 132 133 *val = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_DATA)); 134 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, READ_EN), 0); 135 136 timeout = 10; 137 do { 138 ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 139 if (ack == 0) 140 break; 141 DELAY(10); 142 } while (--timeout > 0); 143 144 if (timeout == 0) { 145 device_printf(sc->dev, "Timeout waiting for read un-ACK\n"); 146 return (ETIMEDOUT); 147 } 148 149 return (0); 150 } 151 152 static int 153 fupci_phy_write(struct fupci_softc *sc, int phy, uint32_t reg, uint32_t val) 154 { 155 unsigned timeout; 156 uint32_t ack; 157 158 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ADDR), reg); 159 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_DATA), val); 160 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_EN), 1); 161 162 timeout = 10; 163 do { 164 ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 165 if (ack != 0) 166 break; 167 DELAY(10); 168 } while (--timeout > 0); 169 170 if (timeout == 0) { 171 device_printf(sc->dev, "Timeout waiting for write ACK\n"); 172 return (ETIMEDOUT); 173 } 174 175 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, WRITE_EN), 0); 176 177 timeout = 10; 178 do { 179 ack = FUDW_MGMT_READ(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, ACK)); 180 if (ack == 0) 181 break; 182 DELAY(10); 183 } while (--timeout > 0); 184 185 if (timeout == 0) { 186 device_printf(sc->dev, "Timeout waiting for write un-ACK\n"); 187 return (ETIMEDOUT); 188 } 189 190 return (0); 191 } 192 193 static int 194 fupci_phy_init(struct fupci_softc *sc) 195 { 196 device_t dev; 197 int error, phy, lane; 198 199 dev = sc->dev; 200 201 /* Assert core power-on reset (active low) */ 202 error = gpio_pin_set_active(sc->porst_pin, false); 203 if (error != 0) { 204 device_printf(dev, "Cannot assert power-on reset: %d\n", 205 error); 206 return (error); 207 } 208 209 /* Assert PERST_N */ 210 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PERST_N, 0); 211 212 /* Enable power */ 213 error = gpio_pin_set_active(sc->pwren_pin, true); 214 if (error != 0) { 215 device_printf(dev, "Cannot enable power: %d\n", error); 216 return (error); 217 } 218 219 /* Hold PERST for 100ms as per the PCIe spec */ 220 DELAY(100); 221 222 /* Deassert PERST_N */ 223 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PERST_N, 1); 224 225 /* Deassert core power-on reset (active low) */ 226 error = gpio_pin_set_active(sc->porst_pin, true); 227 if (error != 0) { 228 device_printf(dev, "Cannot deassert power-on reset: %d\n", 229 error); 230 return (error); 231 } 232 233 /* Enable the aux clock */ 234 error = clk_enable(sc->pcie_aux_clk); 235 if (error != 0) { 236 device_printf(dev, "Cannot enable aux clock: %d\n", error); 237 return (error); 238 } 239 240 /* Hold LTSSM in reset whilst initialising the PHYs */ 241 FUDW_MGMT_WRITE(sc, FUDW_MGMT_HOLD_PHY_RST, 1); 242 243 /* Deassert the aux reset */ 244 error = hwreset_deassert(sc->pcie_aux_rst); 245 if (error != 0) { 246 device_printf(dev, "Cannot deassert aux reset: %d\n", error); 247 return (error); 248 } 249 250 /* Enable control register interface */ 251 for (phy = 0; phy < FUDW_PHYS; ++phy) 252 FUDW_MGMT_WRITE(sc, FUDW_MGMT_PHY_CR_PARA_REG(phy, SEL), 1); 253 254 /* Wait for enable to take effect */ 255 DELAY(1); 256 257 /* Initialise lane configuration */ 258 for (phy = 0; phy < FUDW_PHYS; ++phy) { 259 for (lane = 0; lane < FUDW_LANES_PER_PHY; ++lane) 260 fupci_phy_write(sc, phy, FUDW_MGMT_PHY_LANE(lane), 261 FUDW_MGMT_PHY_LANE_INIT); 262 } 263 264 /* Disable the aux clock whilst taking the LTSSM out of reset */ 265 error = clk_disable(sc->pcie_aux_clk); 266 if (error != 0) { 267 device_printf(dev, "Cannot disable aux clock: %d\n", error); 268 return (error); 269 } 270 271 /* Take LTSSM out of reset */ 272 FUDW_MGMT_WRITE(sc, FUDW_MGMT_HOLD_PHY_RST, 0); 273 274 /* Enable the aux clock again */ 275 error = clk_enable(sc->pcie_aux_clk); 276 if (error != 0) { 277 device_printf(dev, "Cannot re-enable aux clock: %d\n", error); 278 return (error); 279 } 280 281 /* Put the controller in Root Complex mode */ 282 FUDW_MGMT_WRITE(sc, FUDW_MGMT_DEVICE_TYPE, FUDW_MGMT_DEVICE_TYPE_RC); 283 284 return (0); 285 } 286 287 static void 288 fupci_dbi_protect(struct fupci_softc *sc, bool protect) 289 { 290 uint32_t reg; 291 292 reg = pci_dw_dbi_rd4(sc->dev, DW_MISC_CONTROL_1); 293 if (protect) 294 reg &= ~DBI_RO_WR_EN; 295 else 296 reg |= DBI_RO_WR_EN; 297 pci_dw_dbi_wr4(sc->dev, DW_MISC_CONTROL_1, reg); 298 } 299 300 static int 301 fupci_init(struct fupci_softc *sc) 302 { 303 /* Enable 32-bit I/O window */ 304 fupci_dbi_protect(sc, false); 305 pci_dw_dbi_wr2(sc->dev, PCIR_IOBASEL_1, 306 (PCIM_BRIO_32 << 8) | PCIM_BRIO_32); 307 fupci_dbi_protect(sc, true); 308 309 /* Enable LTSSM */ 310 FUDW_MGMT_WRITE(sc, FUDW_MGMT_LTSSM_EN, 1); 311 312 return (0); 313 } 314 315 static int 316 fupci_probe(device_t dev) 317 { 318 if (!ofw_bus_status_okay(dev)) 319 return (ENXIO); 320 321 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 322 return (ENXIO); 323 324 device_set_desc(dev, "SiFive FU740 PCIe Controller"); 325 326 return (BUS_PROBE_DEFAULT); 327 } 328 329 static int 330 fupci_attach(device_t dev) 331 { 332 struct fupci_softc *sc; 333 phandle_t node; 334 int error, rid; 335 336 sc = device_get_softc(dev); 337 node = ofw_bus_get_node(dev); 338 sc->dev = dev; 339 340 rid = 0; 341 error = ofw_bus_find_string_index(node, "reg-names", "dbi", &rid); 342 if (error != 0) { 343 device_printf(dev, "Cannot get DBI memory: %d\n", error); 344 goto fail; 345 } 346 sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 347 RF_ACTIVE); 348 if (sc->dw_sc.dbi_res == NULL) { 349 device_printf(dev, "Cannot allocate DBI memory\n"); 350 error = ENXIO; 351 goto fail; 352 } 353 354 rid = 0; 355 error = ofw_bus_find_string_index(node, "reg-names", "mgmt", &rid); 356 if (error != 0) { 357 device_printf(dev, "Cannot get management space memory: %d\n", 358 error); 359 goto fail; 360 } 361 sc->mgmt_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 362 RF_ACTIVE); 363 if (sc->mgmt_res == NULL) { 364 device_printf(dev, "Cannot allocate management space memory\n"); 365 error = ENXIO; 366 goto fail; 367 } 368 369 error = gpio_pin_get_by_ofw_property(dev, node, "reset-gpios", 370 &sc->porst_pin); 371 /* Old U-Boot device tree uses perstn-gpios */ 372 if (error == ENOENT) 373 error = gpio_pin_get_by_ofw_property(dev, node, "perstn-gpios", 374 &sc->porst_pin); 375 if (error != 0) { 376 device_printf(dev, "Cannot get power-on reset GPIO: %d\n", 377 error); 378 goto fail; 379 } 380 error = gpio_pin_setflags(sc->porst_pin, GPIO_PIN_OUTPUT); 381 if (error != 0) { 382 device_printf(dev, "Cannot configure power-on reset GPIO: %d\n", 383 error); 384 goto fail; 385 } 386 387 error = gpio_pin_get_by_ofw_property(dev, node, "pwren-gpios", 388 &sc->pwren_pin); 389 if (error != 0) { 390 device_printf(dev, "Cannot get power enable GPIO: %d\n", 391 error); 392 goto fail; 393 } 394 error = gpio_pin_setflags(sc->pwren_pin, GPIO_PIN_OUTPUT); 395 if (error != 0) { 396 device_printf(dev, "Cannot configure power enable GPIO: %d\n", 397 error); 398 goto fail; 399 } 400 401 error = clk_get_by_ofw_name(dev, node, "pcie_aux", &sc->pcie_aux_clk); 402 /* Old U-Boot device tree uses pcieaux */ 403 if (error == ENOENT) 404 error = clk_get_by_ofw_name(dev, node, "pcieaux", 405 &sc->pcie_aux_clk); 406 if (error != 0) { 407 device_printf(dev, "Cannot get aux clock: %d\n", error); 408 goto fail; 409 } 410 411 error = hwreset_get_by_ofw_idx(dev, node, 0, &sc->pcie_aux_rst); 412 if (error != 0) { 413 device_printf(dev, "Cannot get aux reset: %d\n", error); 414 goto fail; 415 } 416 417 error = fupci_phy_init(sc); 418 if (error != 0) 419 goto fail; 420 421 error = pci_dw_init(dev); 422 if (error != 0) 423 goto fail; 424 425 error = fupci_init(sc); 426 if (error != 0) 427 goto fail; 428 429 return (bus_generic_attach(dev)); 430 431 fail: 432 /* XXX Cleanup */ 433 return (error); 434 } 435 436 static int 437 fupci_get_link(device_t dev, bool *status) 438 { 439 uint32_t reg; 440 441 reg = pci_dw_dbi_rd4(dev, FUDW_DBI_PORT_DBG1); 442 *status = (reg & FUDW_DBI_PORT_DBG1_LINK_UP) != 0 && 443 (reg & FUDW_DBI_PORT_DBG1_LINK_IN_TRAINING) == 0; 444 445 return (0); 446 } 447 448 static device_method_t fupci_methods[] = { 449 /* Device interface */ 450 DEVMETHOD(device_probe, fupci_probe), 451 DEVMETHOD(device_attach, fupci_attach), 452 453 /* PCI DW interface */ 454 DEVMETHOD(pci_dw_get_link, fupci_get_link), 455 456 DEVMETHOD_END 457 }; 458 459 DEFINE_CLASS_1(pcib, fupci_driver, fupci_methods, 460 sizeof(struct fupci_softc), pci_dw_driver); 461 DRIVER_MODULE(fu740_pci_dw, simplebus, fupci_driver, NULL, NULL); 462