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