? arch/arm64/compile/GENERIC.MP/obj Index: dev/fdt/dwpcie.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/dwpcie.c,v retrieving revision 1.46 diff -u -p -r1.46 dwpcie.c --- dev/fdt/dwpcie.c 25 Apr 2023 11:36:55 -0000 1.46 +++ dev/fdt/dwpcie.c 26 Apr 2023 11:28:11 -0000 @@ -86,6 +86,7 @@ #define IATU_LWR_TARGET_ADDR 0x14 #define IATU_UPPER_TARGET_ADDR 0x18 +/* Marvell ARMADA 8k registers */ #define PCIE_GLOBAL_CTRL 0x8000 #define PCIE_GLOBAL_CTRL_APP_LTSSM_EN (1 << 2) #define PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK (0xf << 4) @@ -171,11 +172,13 @@ #define ANATOP_PLLOUT_DIV 0x7c #define ANATOP_PLLOUT_DIV_SYSPLL1 0x7 -/* Rockchip */ +/* Rockchip RK3568/RK3588 registers */ #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_INTR_STATUS_LEGACY 0x0008 +#define PCIE_CLIENT_INTR_MASK_LEGACY 0x001c #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 @@ -200,6 +203,18 @@ struct dwpcie_range { uint64_t size; }; +struct dwpcie_intx { + int (*di_func)(void *); + void *di_arg; + int di_ipl; + int di_flags; + int di_pin; + struct evcount di_count; + char *di_name; + struct dwpcie_softc *di_sc; + TAILQ_ENTRY(dwpcie_intx) di_next; +}; + #define DWPCIE_NUM_MSI 32 struct dwpcie_msi { @@ -262,6 +277,8 @@ struct dwpcie_softc { int sc_atu_viewport; void *sc_ih; + struct interrupt_controller sc_ic; + TAILQ_HEAD(,dwpcie_intx) sc_intx[4]; uint64_t sc_msi_addr; struct dwpcie_msi sc_msi[DWPCIE_NUM_MSI]; @@ -298,6 +315,7 @@ dwpcie_match(struct device *parent, void OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie") || OF_is_compatible(faa->fa_node, "qcom,pcie-sc8280xp") || OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie") || + OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie") || OF_is_compatible(faa->fa_node, "sifive,fu740-pcie")); } @@ -320,7 +338,14 @@ int dwpcie_imx8mq_init(struct dwpcie_sof int dwpcie_imx8mq_intr(void *); int dwpcie_fu740_init(struct dwpcie_softc *); + int dwpcie_rk3568_init(struct dwpcie_softc *); +int dwpcie_rk3568_intr(void *); +void *dwpcie_rk3568_intr_establish(void *, int *, int, + struct cpu_info *, int (*)(void *), void *, char *); +void dwpcie_rk3568_intr_disestablish(void *); +void dwpcie_rk3568_intr_barrier(void *); + int dwpcie_sc8280xp_init(struct dwpcie_softc *); void dwpcie_attach_hook(struct device *, struct device *, @@ -400,7 +425,8 @@ dwpcie_attach(struct device *parent, str sc->sc_glue_size = faa->fa_reg[glue].size; } - if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie")) { + if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie") || + OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie")) { glue = OF_getindex(faa->fa_node, "apb", "reg-names"); if (glue < 0 || glue >= faa->fa_nreg) { printf(": no glue registers\n"); @@ -509,7 +535,8 @@ dwpcie_attach_deferred(struct device *se error = dwpcie_imx8mq_init(sc); if (OF_is_compatible(sc->sc_node, "qcom,pcie-sc8280xp")) error = dwpcie_sc8280xp_init(sc); - if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-pcie")) + if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-pcie") || + OF_is_compatible(sc->sc_node, "rockchip,rk3588-pcie")) error = dwpcie_rk3568_init(sc); if (OF_is_compatible(sc->sc_node, "sifive,fu740-pcie")) error = dwpcie_fu740_init(sc); @@ -610,8 +637,7 @@ dwpcie_attach_deferred(struct device *se /* Set up bus range. */ if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range, - sizeof(bus_range)) != sizeof(bus_range) || - bus_range[0] >= 32 || bus_range[1] >= 32) { + sizeof(bus_range)) != sizeof(bus_range)) { bus_range[0] = 0; bus_range[1] = 31; } @@ -700,11 +726,14 @@ dwpcie_attach_deferred(struct device *se pba.pba_bus = sc->sc_bus; if (OF_is_compatible(sc->sc_node, "baikal,bm1000-pcie") || OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie") || - OF_is_compatible(sc->sc_node, "rockchip,rk3568-pcie") || OF_getproplen(sc->sc_node, "msi-map") > 0 || sc->sc_msi_addr) pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; + /* XXX No working MSI on RK3588 yet. */ + if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-pcie")) + pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED; + pci_dopm = 1; config_found(self, &pba, NULL); @@ -1273,7 +1302,8 @@ dwpcie_rk3568_init(struct dwpcie_softc * { uint32_t *reset_gpio; ssize_t reset_gpiolen; - int error, timo; + int error, idx, node; + int pin, timo; sc->sc_num_viewport = 8; @@ -1339,6 +1369,25 @@ dwpcie_rk3568_init(struct dwpcie_softc * goto err; } + node = OF_getnodebyname(sc->sc_node, "legacy-interrupt-controller"); + idx = OF_getindex(sc->sc_node, "legacy", "interrupt-names"); + if (node && idx != -1) { + sc->sc_ih = fdt_intr_establish_idx(sc->sc_node, idx, + IPL_BIO | IPL_MPSAFE, dwpcie_rk3568_intr, sc, + sc->sc_dev.dv_xname); + } + + if (sc->sc_ih) { + for (pin = 0; pin < nitems(sc->sc_intx); pin++) + TAILQ_INIT(&sc->sc_intx[pin]); + sc->sc_ic.ic_node = node; + sc->sc_ic.ic_cookie = sc; + sc->sc_ic.ic_establish = dwpcie_rk3568_intr_establish; + sc->sc_ic.ic_disestablish = dwpcie_rk3568_intr_disestablish; + sc->sc_ic.ic_barrier = dwpcie_rk3568_intr_barrier; + fdt_intr_register(&sc->sc_ic); + } + error = 0; err: if (reset_gpiolen > 0) @@ -1348,6 +1397,108 @@ err: } int +dwpcie_rk3568_intr(void *arg) +{ + struct dwpcie_softc *sc = arg; + struct dwpcie_intx *di; + uint32_t status; + int pin, s; + + status = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_INTR_STATUS_LEGACY); + for (pin = 0; pin < nitems(sc->sc_intx); pin++) { + if ((status & (1 << pin)) == 0) + continue; + + TAILQ_FOREACH(di, &sc->sc_intx[pin], di_next) { + if ((di->di_flags & IPL_MPSAFE) == 0) + KERNEL_LOCK(); + s = splraise(di->di_ipl); + if (di->di_func(di->di_arg)) + di->di_count.ec_count++; + splx(s); + if ((di->di_flags & IPL_MPSAFE) == 0) + KERNEL_UNLOCK(); + } + } + + return 1; +} + +void * +dwpcie_rk3568_intr_establish(void *cookie, int *cell, int level, + struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct dwpcie_softc *sc = (struct dwpcie_softc *)cookie; + struct dwpcie_intx *di; + int pin = cell[0]; + uint32_t mask = (1U << pin); + + if (ci != NULL && !CPU_IS_PRIMARY(ci)) + return NULL; + + if (pin < 0 || pin >= nitems(sc->sc_intx)) + return NULL; + + /* Mask the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_INTR_MASK_LEGACY, (mask << 16) | mask); + intr_barrier(sc->sc_ih); + + di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); + di->di_func = func; + di->di_arg = arg; + di->di_ipl = level & IPL_IRQMASK; + di->di_flags = level & IPL_FLAGMASK; + di->di_pin = pin; + di->di_name = name; + if (name != NULL) + evcount_attach(&di->di_count, name, &di->di_pin); + di->di_sc = sc; + TAILQ_INSERT_TAIL(&sc->sc_intx[pin], di, di_next); + + /* Unmask the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_INTR_MASK_LEGACY, mask << 16); + + return di; +} + +void +dwpcie_rk3568_intr_disestablish(void *cookie) +{ + struct dwpcie_intx *di = cookie; + struct dwpcie_softc *sc = di->di_sc; + uint32_t mask = (1U << di->di_pin); + + /* Mask the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_INTR_MASK_LEGACY, (mask << 16) | mask); + intr_barrier(sc->sc_ih); + + if (di->di_name) + evcount_detach(&di->di_count); + + TAILQ_REMOVE(&sc->sc_intx[di->di_pin], di, di_next); + free(di, M_DEVBUF, sizeof(*di)); + + if (!TAILQ_EMPTY(&sc->sc_intx[di->di_pin])) { + /* Unmask the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, + PCIE_CLIENT_INTR_MASK_LEGACY, mask << 16); + } +} + +void +dwpcie_rk3568_intr_barrier(void *cookie) +{ + struct dwpcie_intx *di = cookie; + struct dwpcie_softc *sc = di->di_sc; + + intr_barrier(sc->sc_ih); +} + +int dwpcie_sc8280xp_init(struct dwpcie_softc *sc) { sc->sc_num_viewport = 8; @@ -1482,6 +1633,7 @@ dwpcie_conf_read(void *v, pcitag_t tag, dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); if (bus == sc->sc_bus) { KASSERT(dev == 0); + tag = dwpcie_make_tag(sc, 0, dev, fn); return HREAD4(sc, tag | reg); } @@ -1515,6 +1667,7 @@ dwpcie_conf_write(void *v, pcitag_t tag, dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); if (bus == sc->sc_bus) { KASSERT(dev == 0); + tag = dwpcie_make_tag(sc, 0, dev, fn); HWRITE4(sc, tag | reg, data); return; } Index: dev/fdt/rkclock.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkclock.c,v retrieving revision 1.75 diff -u -p -r1.75 rkclock.c --- dev/fdt/rkclock.c 18 Apr 2023 05:28:41 -0000 1.75 +++ dev/fdt/rkclock.c 26 Apr 2023 11:28:11 -0000 @@ -210,8 +210,10 @@ #define RK3588_CRU_CLKSEL_CON(i) (0x00300 + (i) * 4) #define RK3588_CRU_GATE_CON(i) (0x00800 + (i) * 4) +#define RK3588_CRU_SOFTRST_CON(i) (0x00a00 + (i) * 4) #define RK3588_PHPTOPCRU_PPLL_CON(i) (0x08200 + (i) * 4) +#define RK3588_PHPTOPCRU_SOFTRST_CON(i) (0x08a00 + (i) * 4) #define RK3588_PMUCRU_CLKSEL_CON(i) (0x30300 + (i) * 4) #include "rkclock_clocks.h" @@ -4116,6 +4118,21 @@ const struct rkclock rk3588_clocks[] = { { RK3588_CLK_UART0 } }, { + RK3588_CLK_REF_PIPE_PHY0_OSC_SRC, 0, 0, 0, + { RK3588_XIN24M } + }, + { + RK3588_CLK_REF_PIPE_PHY0_PLL_SRC, RK3588_CRU_CLKSEL_CON(176), + 0, DIV(5, 0), + { RK3588_PLL_PPLL } + }, + { + RK3588_CLK_REF_PIPE_PHY0, RK3588_CRU_CLKSEL_CON(177), + SEL(6, 6), 0, + { RK3588_CLK_REF_PIPE_PHY0_OSC_SRC, + RK3588_CLK_REF_PIPE_PHY0_PLL_SRC }, + }, + { /* Sentinel */ } }; @@ -4315,7 +4332,28 @@ rk3588_enable(void *cookie, uint32_t *ce void rk3588_reset(void *cookie, uint32_t *cells, int on) { + struct rkclock_softc *sc = cookie; uint32_t idx = cells[0]; + uint32_t bit, mask, reg; - printf("%s: 0x%08x\n", __func__, idx); + switch (idx) { + case RK3588_SRST_PCIE4_POWER_UP: + reg = RK3588_CRU_SOFTRST_CON(33); + bit = 1; + break; + case RK3588_SRST_REF_PIPE_PHY0: + reg = RK3588_CRU_SOFTRST_CON(77); + bit = 6; + break; + case RK3588_SRST_P_PCIE2_PHY0: + reg = RK3588_PHPTOPCRU_SOFTRST_CON(0); + bit = 5; + break; + default: + printf("%s: 0x%08x\n", __func__, idx); + return; + } + + mask = (1 << bit); + HWRITE4(sc, reg, mask << 16 | (on ? mask : 0)); } Index: dev/fdt/rkclock_clocks.h =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkclock_clocks.h,v retrieving revision 1.47 diff -u -p -r1.47 rkclock_clocks.h --- dev/fdt/rkclock_clocks.h 18 Apr 2023 05:27:04 -0000 1.47 +++ dev/fdt/rkclock_clocks.h 26 Apr 2023 11:28:11 -0000 @@ -460,6 +460,13 @@ #define RK3588_CLK_UART0_FRAC 665 #define RK3588_CLK_UART0 666 #define RK3588_SCLK_UART0 667 +#define RK3588_CLK_REF_PIPE_PHY0_OSC_SRC 674 +#define RK3588_CLK_REF_PIPE_PHY0_PLL_SRC 677 +#define RK3588_CLK_REF_PIPE_PHY0 680 #define RK3588_PLL_SPLL 1022 #define RK3588_XIN24M 1023 + +#define RK3588_SRST_PCIE4_POWER_UP 298 +#define RK3588_SRST_REF_PIPE_PHY0 572 +#define RK3588_SRST_P_PCIE2_PHY0 579 Index: dev/fdt/rkcomphy.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkcomphy.c,v retrieving revision 1.1 diff -u -p -r1.1 rkcomphy.c --- dev/fdt/rkcomphy.c 12 Mar 2023 14:29:50 -0000 1.1 +++ dev/fdt/rkcomphy.c 26 Apr 2023 11:28:11 -0000 @@ -28,6 +28,12 @@ #include #include +/* + * WARNING: Most (but not all!) of the register numbers in the Linux + * driver are off-by-one! This driver uses 0-based register numbers + * like in the TRM. + */ + /* Combo PHY registers */ #define COMBO_PIPE_PHY_REG(idx) ((idx) * 4) /* REG_005 */ @@ -49,6 +55,8 @@ #define COMBO_PIPE_PHY_SSC_CNT_HI_VALUE (0x5f << 0) /* REG_017 */ #define COMBO_PIPE_PHY_PLL_LOOP 0x32 +/* REG_027 */ +#define COMBO_PIPE_PHY_RX_TRIM_RK3588 0x4c /* REG_031 */ #define COMBO_PIPE_PHY_SSC_DIR_MASK (0x3 << 4) #define COMBO_PIPE_PHY_SSC_DIR_DOWN (0x1 << 4) @@ -57,10 +65,14 @@ /* REG_032 */ #define COMBO_PIPE_PHY_PLL_KVCO_MASK (0x7 << 2) #define COMBO_PIPE_PHY_PLL_KVCO_VALUE (0x2 << 2) +#define COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3588 (0x4 << 2) /* GRF registers */ #define PIPE_GRF_PIPE_CON0 0x0000 +/* PHP GRF registers (for RK3588) */ +#define PHP_GRF_PCIESEL_CON 0x0100 + /* PHY GRF registers */ #define PIPE_PHY_GRF_PIPE_CON(idx) ((idx) * 4) /* CON0 */ @@ -112,15 +124,17 @@ struct cfdriver rkcomphy_cd = { NULL, "rkcomphy", DV_DULL }; -int rkcomphy_enable(void *, uint32_t *); +int rkcomphy_rk3568_enable(void *, uint32_t *); +int rkcomphy_rk3588_enable(void *, uint32_t *); int rkcomphy_match(struct device *parent, void *match, void *aux) { struct fdt_attach_args *faa = aux; + int node = faa->fa_node; - return OF_is_compatible(faa->fa_node, - "rockchip,rk3568-naneng-combphy"); + return OF_is_compatible(node, "rockchip,rk3568-naneng-combphy") || + OF_is_compatible(node, "rockchip,rk3588-naneng-combphy"); } void @@ -147,12 +161,15 @@ rkcomphy_attach(struct device *parent, s sc->sc_pd.pd_node = faa->fa_node; sc->sc_pd.pd_cookie = sc; - sc->sc_pd.pd_enable = rkcomphy_enable; + if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-naneng-combphy")) + sc->sc_pd.pd_enable = rkcomphy_rk3568_enable; + else + sc->sc_pd.pd_enable = rkcomphy_rk3588_enable; phy_register(&sc->sc_pd); } void -rkcomphy_pll_tune(struct rkcomphy_softc *sc) +rkcomphy_rk3568_pll_tune(struct rkcomphy_softc *sc) { uint32_t reg; @@ -173,7 +190,7 @@ rkcomphy_pll_tune(struct rkcomphy_softc } int -rkcomphy_enable(void *cookie, uint32_t *cells) +rkcomphy_rk3568_enable(void *cookie, uint32_t *cells) { struct rkcomphy_softc *sc = cookie; struct regmap *rm, *phy_rm; @@ -238,7 +255,7 @@ rkcomphy_enable(void *cookie, uint32_t * regmap_write_4(rm, PIPE_GRF_PIPE_CON0, 0xffff2220); break; case PHY_TYPE_USB3: - rkcomphy_pll_tune(sc); + rkcomphy_rk3568_pll_tune(sc); regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), PIPE_PHY_GRF_PIPE_MODE_USB); @@ -276,7 +293,7 @@ rkcomphy_enable(void *cookie, uint32_t * PIPE_PHY_GRF_PIPE_CLK_100M); switch (type) { case PHY_TYPE_PCIE: - rkcomphy_pll_tune(sc); + rkcomphy_rk3568_pll_tune(sc); break; case PHY_TYPE_SATA: reg = HREAD4(sc, COMBO_PIPE_PHY_REG(31)); @@ -305,6 +322,84 @@ rkcomphy_enable(void *cookie, uint32_t * return ETIMEDOUT; } } + + return 0; +} + +void +rkcomphy_rk3588_pll_tune(struct rkcomphy_softc *sc) +{ + uint32_t reg; + + reg = HREAD4(sc, COMBO_PIPE_PHY_REG(32)); + reg &= ~COMBO_PIPE_PHY_PLL_KVCO_MASK; + reg |= COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3588; + HWRITE4(sc, COMBO_PIPE_PHY_REG(32), reg); + + HWRITE4(sc, COMBO_PIPE_PHY_REG(11), COMBO_PIPE_PHY_PLL_LPF_ADJ_VALUE); + + HWRITE4(sc, COMBO_PIPE_PHY_REG(27), COMBO_PIPE_PHY_RX_TRIM_RK3588); + HWRITE4(sc, COMBO_PIPE_PHY_REG(10), COMBO_PIPE_PHY_SU_TRIM_0_7); +} + +int +rkcomphy_rk3588_enable(void *cookie, uint32_t *cells) +{ + struct rkcomphy_softc *sc = cookie; + struct regmap *rm, *phy_rm; + int node = sc->sc_pd.pd_node; + uint32_t type = cells[0]; + uint32_t freq, grf, phy_grf; + + /* We only support PCIe for now. */ + switch (type) { + case PHY_TYPE_PCIE: + break; + default: + return EINVAL; + } + + grf = OF_getpropint(node, "rockchip,pipe-grf", 0); + rm = regmap_byphandle(grf); + if (rm == NULL) + return ENXIO; + + phy_grf = OF_getpropint(node, "rockchip,pipe-phy-grf", 0); + phy_rm = regmap_byphandle(phy_grf); + if (phy_rm == NULL) + return ENXIO; + + clock_set_assigned(node); + clock_enable_all(node); + + switch (type) { + case PHY_TYPE_PCIE: + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), 0xffff1000); + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), 0xffff0000); + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2), 0xffff0101); + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(3), 0xffff0200); + regmap_write_4(rm, PHP_GRF_PCIESEL_CON, 0x00010000); + regmap_write_4(rm, PHP_GRF_PCIESEL_CON, 0x00020000); + break; + } + + freq = clock_get_frequency(node, "ref"); + switch (freq) { + case 25000000: + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), + PIPE_PHY_GRF_PIPE_CLK_25M); + break; + case 100000000: + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), + PIPE_PHY_GRF_PIPE_CLK_100M); + switch (type) { + case PHY_TYPE_PCIE: + rkcomphy_rk3588_pll_tune(sc); + break; + } + } + + reset_deassert_all(node); return 0; }