From: Jonathan Matthew Subject: rkcomphy: add rk3528 support To: tech@openbsd.org Cc: kettenis@openbsd.org Date: Sun, 22 Mar 2026 21:48:59 +1000 This adds support for the RK3528 variant of the combo phy, currently only in PCIe mode. It looks like it can do USB3 too but I don't see any devices that do that. Hopefully a TRM for the 3528 will turn up at some point so we can do this properly. The rkclock change just ignores attempts at setting the pcie inner phy clock rate, since it's fixed at 100Mhz but the device tree indicates the driver should set it. With this I can get pcie and the second nic on a Radxa E20C working with u-boot 2026.04rc4 and some device tree bits pulled from linux. ok? Index: rkclock.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkclock.c,v diff -u -p -u -p -r1.96 rkclock.c --- rkclock.c 12 Mar 2026 20:44:38 -0000 1.96 +++ rkclock.c 22 Mar 2026 10:33:52 -0000 @@ -3291,6 +3291,8 @@ rk3528_get_frequency(void *cookie, uint3 return rk3328_get_pll(sc, RK3528_PCIE_CRU_PLL_CON(32)); case RK3528_XIN24M: return 24000000; + case RK3528_CLK_REF_PCIE_INNER_PHY: + return 100000000; default: break; } @@ -3303,6 +3305,13 @@ rk3528_set_frequency(void *cookie, uint3 { struct rkclock_softc *sc = cookie; uint32_t idx = cells[0]; + + switch (idx) { + case RK3528_CLK_REF_PCIE_INNER_PHY: + return 0; + default: + break; + } return rkclock_set_frequency(sc, idx, freq); } Index: rkclock_clocks.h =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkclock_clocks.h,v diff -u -p -u -p -r1.68 rkclock_clocks.h --- rkclock_clocks.h 12 Mar 2026 20:44:38 -0000 1.68 +++ rkclock_clocks.h 22 Mar 2026 10:33:52 -0000 @@ -297,6 +297,7 @@ #define RK3528_CLK_MATRIX_200M_SRC 10 #define RK3528_CLK_PWM0 111 #define RK3528_CLK_PWM1 114 +#define RK3528_CLK_REF_PCIE_INNER_PHY 123 #define RK3528_CLK_PPLL_125M_MATRIX 127 #define RK3528_CCLK_SRC_EMMC 140 #define RK3528_BCLK_EMMC 143 Index: rkcomphy.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkcomphy.c,v diff -u -p -u -p -r1.2 rkcomphy.c --- rkcomphy.c 27 Apr 2023 08:56:39 -0000 1.2 +++ rkcomphy.c 22 Mar 2026 10:33:52 -0000 @@ -36,9 +36,13 @@ /* Combo PHY registers */ #define COMBO_PIPE_PHY_REG(idx) ((idx) * 4) +/* REG_004 */ +#define COMBO_PIPE_PHY_GATE_TX_PCK_DLY_PLL_OFF (1 << 3) /* REG_005 */ #define COMBO_PIPE_PHY_PLL_DIV_MASK (0x3 << 6) #define COMBO_PIPE_PHY_PLL_DIV_2 (0x1 << 6) +#define COMBO_PIPE_PHY_PLL_KVCO_MASK_RK3528 (0x7 << 10) +#define COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3528 (0x2 << 10) /* REG_006 */ #define COMBO_PIPE_PHY_TX_RTERM_50OHM (0x8 << 4) #define COMBO_PIPE_PHY_RX_RTERM_44OHM (0xf << 4) @@ -124,6 +128,7 @@ struct cfdriver rkcomphy_cd = { NULL, "rkcomphy", DV_DULL }; +int rkcomphy_rk3528_enable(void *, uint32_t *); int rkcomphy_rk3568_enable(void *, uint32_t *); int rkcomphy_rk3588_enable(void *, uint32_t *); @@ -133,7 +138,8 @@ rkcomphy_match(struct device *parent, vo struct fdt_attach_args *faa = aux; int node = faa->fa_node; - return OF_is_compatible(node, "rockchip,rk3568-naneng-combphy") || + return OF_is_compatible(node, "rockchip,rk3528-naneng-combphy") || + OF_is_compatible(node, "rockchip,rk3568-naneng-combphy") || OF_is_compatible(node, "rockchip,rk3588-naneng-combphy"); } @@ -161,11 +167,86 @@ rkcomphy_attach(struct device *parent, s sc->sc_pd.pd_node = faa->fa_node; sc->sc_pd.pd_cookie = sc; - if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-naneng-combphy")) + if (OF_is_compatible(faa->fa_node, "rockchip,rk3528-naneng-combphy")) + sc->sc_pd.pd_enable = rkcomphy_rk3528_enable; + else 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_rk3528_pll_tune(struct rkcomphy_softc *sc) +{ + uint32_t reg; + + reg = HREAD4(sc, COMBO_PIPE_PHY_REG(4)); + reg |= COMBO_PIPE_PHY_GATE_TX_PCK_DLY_PLL_OFF; + HWRITE4(sc, COMBO_PIPE_PHY_REG(4), reg); + + reg = HREAD4(sc, COMBO_PIPE_PHY_REG(5)); + reg &= ~COMBO_PIPE_PHY_PLL_KVCO_MASK_RK3528; + reg |= COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3528; + HWRITE4(sc, COMBO_PIPE_PHY_REG(5), reg); + + /* su_trim[6:4]=111, [10:7]=1001, [2:0]=000, swing 650mv */ + HWRITE4(sc, COMBO_PIPE_PHY_REG(41), 0x570804f0); +} + +int +rkcomphy_rk3528_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 grf, phy_grf, reg; + + /* We only support PCIe for now. (maybe USB3 later?) */ + 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); + + reg = HREAD4(sc, COMBO_PIPE_PHY_REG(31)); + reg &= ~COMBO_PIPE_PHY_SSC_OFFSET_MASK; + reg &= ~COMBO_PIPE_PHY_SSC_DIR_MASK; + reg |= COMBO_PIPE_PHY_SSC_DIR_DOWN; + HWRITE4(sc, COMBO_PIPE_PHY_REG(31), reg); + + switch (type) { + case PHY_TYPE_PCIE: + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), 0xffff0110); + 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); + break; + } + + regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), + PIPE_PHY_GRF_PIPE_CLK_100M); + if (type == PHY_TYPE_PCIE) + rkcomphy_rk3528_pll_tune(sc); + + reset_deassert_all(node); + + return 0; } void