From f98fd0540501dc8455a314678fa8841f3eed9503 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 16 Mar 2023 18:33:19 +0000 Subject: [PATCH] Add code to bring up the PCIe controller on the RK356x. ok dlg@ --- sys/dev/fdt/dwpcie.c | 95 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c index 31813d60b67..f17523c8459 100644 --- a/sys/dev/fdt/dwpcie.c +++ b/sys/dev/fdt/dwpcie.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwpcie.c,v 1.40 2023/03/07 10:24:11 kettenis Exp $ */ +/* $OpenBSD: dwpcie.c,v 1.41 2023/03/16 18:33:19 kettenis Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -171,6 +171,19 @@ #define ANATOP_PLLOUT_DIV 0x7c #define ANATOP_PLLOUT_DIV_SYSPLL1 0x7 +/* Rockchip */ +#define PCIE_CLIENT_GENERAL_CON 0x0000 +#define PCIE_CLIENT_DEV_TYPE_RC ((0xf << 4) << 16 | (0x4 << 4)) +#define PCIE_CLIENT_LINK_REQ_RST_GRT ((1 << 3) << 16 | (1 << 3)) +#define PCIE_CLIENT_APP_LTSSM_ENABLE ((1 << 2) << 16 | (1 << 2)) +#define PCIE_CLIENT_HOT_RESET_CTRL 0x0180 +#define PCIE_CLIENT_APP_LTSSM_ENABLE_ENHANCE ((1 << 4) << 16 | (1 << 4)) +#define PCIE_CLIENT_LTSSM_STATUS 0x0300 +#define PCIE_CLIENT_RDLH_LINK_UP (1 << 17) +#define PCIE_CLIENT_SMLH_LINK_UP (1 << 16) +#define PCIE_CLIENT_LTSSM_MASK (0x1f << 0) +#define PCIE_CLIENT_LTSSM_UP (0x11 << 0) + #define HREAD4(sc, reg) \ (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) #define HWRITE4(sc, reg, val) \ @@ -386,6 +399,17 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux) sc->sc_glue_size = faa->fa_reg[glue].size; } + if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie")) { + glue = OF_getindex(faa->fa_node, "apb", "reg-names"); + if (glue < 0 || glue >= faa->fa_nreg) { + printf(": no glue registers\n"); + return; + } + + sc->sc_glue_base = faa->fa_reg[glue].addr; + sc->sc_glue_size = faa->fa_reg[glue].size; + } + sc->sc_iot = faa->fa_iot; sc->sc_dmat = faa->fa_dmat; sc->sc_node = faa->fa_node; @@ -1225,19 +1249,44 @@ dwpcie_fu740_init(struct dwpcie_softc *sc) return 0; } +int +dwpcie_rk3568_link_up(struct dwpcie_softc *sc) +{ + uint32_t reg; + + reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_LTSSM_STATUS); + if ((reg & PCIE_CLIENT_SMLH_LINK_UP) && + (reg & PCIE_CLIENT_RDLH_LINK_UP) && + (reg & PCIE_CLIENT_LTSSM_MASK) == PCIE_CLIENT_LTSSM_UP) + return 1; + return 0; +} + int dwpcie_rk3568_init(struct dwpcie_softc *sc) { uint32_t *reset_gpio; ssize_t reset_gpiolen; + int error, timo; + + sc->sc_num_viewport = 8; + + if (bus_space_map(sc->sc_iot, sc->sc_glue_base, + sc->sc_glue_size, 0, &sc->sc_glue_ioh)) + return ENOMEM; reset_assert_all(sc->sc_node); + /* Power must be enabled before initializing the PHY. */ regulator_enable(OF_getpropint(sc->sc_node, "vpcie3v3-supply", 0)); phy_enable(sc->sc_node, "pcie-phy"); reset_deassert_all(sc->sc_node); clock_enable_all(sc->sc_node); + if (dwpcie_rk3568_link_up(sc)) + return 0; + reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpios"); if (reset_gpiolen > 0) { reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); @@ -1245,12 +1294,50 @@ dwpcie_rk3568_init(struct dwpcie_softc *sc) reset_gpiolen); gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); gpio_controller_set_pin(reset_gpio, 1); - free(reset_gpio, M_TEMP, reset_gpiolen); } - sc->sc_num_viewport = 8; + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_HOT_RESET_CTRL, PCIE_CLIENT_APP_LTSSM_ENABLE_ENHANCE); + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_GENERAL_CON, PCIE_CLIENT_DEV_TYPE_RC); - return 0; + /* Assert PERST#. */ + if (reset_gpiolen > 0) + gpio_controller_set_pin(reset_gpio, 0); + + /* Enable LTSSM. */ + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CLIENT_GENERAL_CON, + PCIE_CLIENT_LINK_REQ_RST_GRT | PCIE_CLIENT_APP_LTSSM_ENABLE); + + /* + * PERST# must remain asserted for at least 100us after the + * reference clock becomes stable. But also has to remain + * active at least 100ms after power up. Since we may have + * just powered on the device, play it safe and use 100ms. + */ + delay(100000); + + /* Deassert PERST#. */ + if (reset_gpiolen > 0) + gpio_controller_set_pin(reset_gpio, 1); + + /* Wait for the link to come up. */ + for (timo = 100; timo > 0; timo--) { + if (dwpcie_rk3568_link_up(sc)) + break; + delay(10000); + } + if (timo == 0) { + error = ETIMEDOUT; + goto err; + } + + error = 0; +err: + if (reset_gpiolen > 0) + free(reset_gpio, M_TEMP, reset_gpiolen); + + return error; } int -- 2.20.1