1 /* $OpenBSD: rkpciephy.c,v 1.3 2023/07/09 19:11:30 patrick Exp $ */ 2 /* 3 * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/intr.h> 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/ofw_clock.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/fdt.h> 30 31 /* RK3568 GRF registers */ 32 #define GRF_PCIE30PHY_CON(idx) ((idx) * 4) 33 /* CON1 */ 34 #define GRF_PCIE30PHY_DA_OCM 0x80008000 35 /* CON5 */ 36 #define GRF_PCIE30PHY_LANE0_LINK_NUM_MASK (0xf << 16) 37 #define GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT 0 38 /* CON6 */ 39 #define GRF_PCIE30PHY_LANE1_LINK_NUM_MASK (0xf << 16) 40 #define GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT 0 41 /* STATUS0 */ 42 #define GRF_PCIE30PHY_STATUS0 0x80 43 #define GRF_PCIE30PHY_SRAM_INIT_DONE (1 << 14) 44 45 /* RK3588 GRF registers */ 46 #define RK3588_PCIE3PHY_GRF_CMN_CON(idx) ((idx) * 4) 47 #define RK3588_GRF_PCIE3PHY_DA_OCM ((0x1 << 24) | (1 << 8)) 48 #define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1 (1 << 0) 49 #define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3 (1 << 1) 50 #define RK3588_GRF_PCIE3PHY_LANE_AGGREGATE (1 << 2) 51 #define RK3588_GRF_PCIE3PHY_LANE_MASK (0x7 << 16) 52 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 53 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 54 #define RK3588_PCIE3PHY_SRAM_INIT_DONE (1 << 0) 55 #define RK3588_PHP_GRF_PCIESEL_CON 0x100 56 #define RK3588_PHP_GRF_PCIE0L0_PCIE3 (1 << 0) 57 #define RK3588_PHP_GRF_PCIE0L1_PCIE3 (1 << 1) 58 #define RK3588_PHP_GRF_PCIE0L0_MASK (0x1 << 16) 59 #define RK3588_PHP_GRF_PCIE0L1_MASK (0x1 << 17) 60 61 struct rkpciephy_softc { 62 struct device sc_dev; 63 bus_space_tag_t sc_iot; 64 bus_space_handle_t sc_ioh; 65 66 struct phy_device sc_pd; 67 }; 68 69 int rkpciephy_match(struct device *, void *, void *); 70 void rkpciephy_attach(struct device *, struct device *, void *); 71 72 const struct cfattach rkpciephy_ca = { 73 sizeof (struct rkpciephy_softc), rkpciephy_match, rkpciephy_attach 74 }; 75 76 struct cfdriver rkpciephy_cd = { 77 NULL, "rkpciephy", DV_DULL 78 }; 79 80 int rk3568_pciephy_enable(void *, uint32_t *); 81 int rk3588_pciephy_enable(void *, uint32_t *); 82 83 int 84 rkpciephy_match(struct device *parent, void *match, void *aux) 85 { 86 struct fdt_attach_args *faa = aux; 87 88 return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy") || 89 OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy")); 90 } 91 92 void 93 rkpciephy_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct rkpciephy_softc *sc = (struct rkpciephy_softc *)self; 96 struct fdt_attach_args *faa = aux; 97 98 printf("\n"); 99 100 sc->sc_pd.pd_node = faa->fa_node; 101 sc->sc_pd.pd_cookie = sc; 102 if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy")) 103 sc->sc_pd.pd_enable = rk3568_pciephy_enable; 104 if (OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy")) 105 sc->sc_pd.pd_enable = rk3588_pciephy_enable; 106 phy_register(&sc->sc_pd); 107 } 108 109 int 110 rk3568_pciephy_enable(void *cookie, uint32_t *cells) 111 { 112 struct rkpciephy_softc *sc = cookie; 113 struct regmap *rm; 114 int node = sc->sc_pd.pd_node; 115 uint32_t data_lanes[2] = { 0, 0 }; 116 uint32_t grf, stat; 117 int timo; 118 119 grf = OF_getpropint(node, "rockchip,phy-grf", 0); 120 rm = regmap_byphandle(grf); 121 if (rm == NULL) 122 return ENXIO; 123 124 clock_enable_all(node); 125 reset_assert(node, "phy"); 126 delay(1); 127 128 regmap_write_4(rm, GRF_PCIE30PHY_CON(9), GRF_PCIE30PHY_DA_OCM); 129 130 OF_getpropintarray(node, "data-lanes", data_lanes, sizeof(data_lanes)); 131 if (data_lanes[0] > 0) { 132 regmap_write_4(rm, GRF_PCIE30PHY_CON(5), 133 GRF_PCIE30PHY_LANE0_LINK_NUM_MASK | 134 (data_lanes[0] - 1) << GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT); 135 } 136 if (data_lanes[1] > 0) { 137 regmap_write_4(rm, GRF_PCIE30PHY_CON(6), 138 GRF_PCIE30PHY_LANE1_LINK_NUM_MASK | 139 (data_lanes[1] - 1) << GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT); 140 } 141 if (data_lanes[0] > 1 || data_lanes[1] > 1) 142 regmap_write_4(rm, GRF_PCIE30PHY_CON(1), GRF_PCIE30PHY_DA_OCM); 143 144 reset_deassert(node, "phy"); 145 146 for (timo = 500; timo > 0; timo--) { 147 stat = regmap_read_4(rm, GRF_PCIE30PHY_STATUS0); 148 if (stat & GRF_PCIE30PHY_SRAM_INIT_DONE) 149 break; 150 delay(100); 151 } 152 if (timo == 0) { 153 printf("%s: timeout\n", sc->sc_dev.dv_xname); 154 return ETIMEDOUT; 155 } 156 157 return 0; 158 } 159 160 int 161 rk3588_pciephy_enable(void *cookie, uint32_t *cells) 162 { 163 struct rkpciephy_softc *sc = cookie; 164 struct regmap *phy, *pipe; 165 int node = sc->sc_pd.pd_node; 166 uint32_t data_lanes[4] = { 1, 1, 1, 1 }; 167 uint32_t grf, reg, stat; 168 int num_lanes, timo; 169 170 grf = OF_getpropint(node, "rockchip,phy-grf", 0); 171 phy = regmap_byphandle(grf); 172 if (phy == NULL) 173 return ENXIO; 174 175 clock_enable_all(node); 176 reset_assert(node, "phy"); 177 delay(1); 178 179 regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0), 180 RK3588_GRF_PCIE3PHY_DA_OCM); 181 182 num_lanes = OF_getpropintarray(node, "data-lanes", data_lanes, 183 sizeof(data_lanes)); 184 /* Use default setting in case of missing properties. */ 185 if (num_lanes <= 0) 186 num_lanes = sizeof(data_lanes); 187 num_lanes /= sizeof(uint32_t); 188 189 reg = RK3588_GRF_PCIE3PHY_LANE_MASK; 190 /* If all links go to the first, aggregate toward x4 */ 191 if (num_lanes >= 4 && 192 data_lanes[0] == 1 && data_lanes[1] == 1 && 193 data_lanes[2] == 1 && data_lanes[3] == 1) { 194 reg |= RK3588_GRF_PCIE3PHY_LANE_AGGREGATE; 195 } else { 196 /* If lanes 0+1 are not towards the same controller, split. */ 197 if (num_lanes >= 2 && data_lanes[0] != data_lanes[1]) 198 reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1; 199 /* If lanes 2+3 are not towards the same controller, split. */ 200 if (num_lanes >= 4 && data_lanes[2] != data_lanes[3]) 201 reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3; 202 } 203 regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0), reg); 204 205 grf = OF_getpropint(node, "rockchip,pipe-grf", 0); 206 pipe = regmap_byphandle(grf); 207 if (pipe != NULL) { 208 reg = RK3588_PHP_GRF_PCIE0L0_MASK | RK3588_PHP_GRF_PCIE0L1_MASK; 209 /* If lane 1 goes to PCIe3_1L0, move from Combo to PCIE3 PHY */ 210 if (num_lanes >= 2 && data_lanes[1] == 2) 211 reg |= RK3588_PHP_GRF_PCIE0L0_PCIE3; 212 /* If lane 3 goes to PCIe3_1L1, move from Combo to PCIE3 PHY */ 213 if (num_lanes >= 4 && data_lanes[3] == 4) 214 reg |= RK3588_PHP_GRF_PCIE0L1_PCIE3; 215 regmap_write_4(pipe, RK3588_PHP_GRF_PCIESEL_CON, reg); 216 } 217 218 reset_deassert(node, "phy"); 219 220 for (timo = 500; timo > 0; timo--) { 221 stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY0_STATUS1); 222 if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE) 223 break; 224 delay(100); 225 } 226 for (; timo > 0; timo--) { 227 stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY1_STATUS1); 228 if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE) 229 break; 230 delay(100); 231 } 232 if (timo == 0) { 233 printf("%s: timeout\n", sc->sc_dev.dv_xname); 234 return ETIMEDOUT; 235 } 236 237 return 0; 238 } 239