1 /* $NetBSD: rk3399_pcie_phy.c,v 1.5 2024/11/19 08:24:47 skrll Exp $ */ 2 /* $OpenBSD: rkpcie.c,v 1.6 2018/08/28 09:33:18 jsg Exp $ */ 3 /* 4 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 21 __KERNEL_RCSID(1, "$NetBSD: rk3399_pcie_phy.c,v 1.5 2024/11/19 08:24:47 skrll Exp $"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <sys/kmem.h> 27 28 #include <machine/intr.h> 29 #include <sys/bus.h> 30 #include <dev/fdt/fdtvar.h> 31 #include <dev/fdt/syscon.h> 32 33 #include <sys/gpio.h> 34 35 #define RKPCIEPHY_MAXPHY 4 36 37 struct rkpciephy_softc { 38 device_t sc_dev; 39 int sc_phy_node; 40 uint8_t sc_phys[RKPCIEPHY_MAXPHY]; 41 u_int sc_phys_on; 42 }; 43 44 static int rkpciephy_match(device_t, cfdata_t, void *); 45 static void rkpciephy_attach(device_t, device_t, void *); 46 47 CFATTACH_DECL_NEW(rkpciephy, sizeof(struct rkpciephy_softc), 48 rkpciephy_match, rkpciephy_attach, NULL, NULL); 49 50 static const struct device_compatible_entry compat_data[] = { 51 { .compat = "rockchip,rk3399-pcie-phy" }, 52 DEVICE_COMPAT_EOL 53 }; 54 55 static int 56 rkpciephy_match(device_t parent, cfdata_t cf, void *aux) 57 { 58 struct fdt_attach_args *faa = aux; 59 60 return of_compatible_match(faa->faa_phandle, compat_data); 61 } 62 63 static void rkpcie_phy_poweron(struct rkpciephy_softc *, u_int); 64 65 static inline void 66 clock_enable(int phandle, const char *name) 67 { 68 struct clk * clk = fdtbus_clock_get(phandle, name); 69 if (clk == NULL) 70 return; 71 if (clk_enable(clk) != 0) 72 return; 73 } 74 75 static void 76 reset_assert(int phandle, const char *name) 77 { 78 struct fdtbus_reset *rst; 79 80 rst = fdtbus_reset_get(phandle, name); 81 fdtbus_reset_assert(rst); 82 fdtbus_reset_put(rst); 83 } 84 85 static void 86 reset_deassert(int phandle, const char *name) 87 { 88 struct fdtbus_reset *rst; 89 90 rst = fdtbus_reset_get(phandle, name); 91 fdtbus_reset_deassert(rst); 92 fdtbus_reset_put(rst); 93 } 94 95 static void * 96 rkpciephy_phy_acquire(device_t dev, const void *data, size_t len) 97 { 98 struct rkpciephy_softc * const sc = device_private(dev); 99 100 if (len != 4) 101 return NULL; 102 103 const int phy_id = be32dec(data); 104 if (phy_id >= RKPCIEPHY_MAXPHY) 105 return NULL; 106 // device_printf(dev, "%s phy_id %d %d\n", __func__, phy_id, sc->sc_phys[phy_id]); 107 108 if (true /*XXX*/ || sc->sc_phys_on == 0) { 109 clock_enable(sc->sc_phy_node, "refclk"); 110 reset_assert(sc->sc_phy_node, "phy"); 111 } 112 113 return &sc->sc_phys[phy_id]; 114 } 115 116 static int 117 rkpciephy_phy_enable(device_t dev, void *priv, bool enable) 118 { 119 struct rkpciephy_softc * const sc = device_private(dev); 120 uint8_t * const lane = priv; 121 122 // device_printf(dev, "%s %u %u\n", __func__, *lane, enable); 123 124 if (enable) { 125 rkpcie_phy_poweron(sc, *lane); 126 sc->sc_phys_on |= 1U << *lane; 127 } else { 128 #if notyet 129 sc->sc_phys_on &= ~(1U << *lane); 130 #endif 131 } 132 133 return 0; 134 } 135 136 const struct fdtbus_phy_controller_func rkpciephy_phy_funcs = { 137 .acquire = rkpciephy_phy_acquire, 138 .release = (void *)voidop, 139 .enable = rkpciephy_phy_enable, 140 }; 141 142 static void 143 rkpciephy_attach(device_t parent, device_t self, void *aux) 144 { 145 struct rkpciephy_softc *sc = device_private(self); 146 struct fdt_attach_args *faa = aux; 147 148 sc->sc_dev = self; 149 sc->sc_phy_node = faa->faa_phandle; 150 151 aprint_naive("\n"); 152 aprint_normal(": RK3399 PCIe PHY\n"); 153 154 for (size_t i = 0; i < RKPCIEPHY_MAXPHY; i++) 155 sc->sc_phys[i] = i; 156 157 fdtbus_register_phy_controller(self, faa->faa_phandle, &rkpciephy_phy_funcs); 158 } 159 160 /* 161 * PHY Support. 162 */ 163 164 #define RK3399_GRF_SOC_CON5_PCIE 0xe214 165 #define RK3399_TX_ELEC_IDLE_OFF_MASK ((1 << 3) << 16) 166 #define RK3399_TX_ELEC_IDLE_OFF (1 << 3) 167 #define RK3399_GRF_SOC_CON8 0xe220 168 #define RK3399_PCIE_TEST_DATA_MASK ((0xf << 7) << 16) 169 #define RK3399_PCIE_TEST_DATA_SHIFT 7 170 #define RK3399_PCIE_TEST_ADDR_MASK ((0x3f << 1) << 16) 171 #define RK3399_PCIE_TEST_ADDR_SHIFT 1 172 #define RK3399_PCIE_TEST_WRITE_ENABLE (((1 << 0) << 16) | (1 << 0)) 173 #define RK3399_PCIE_TEST_WRITE_DISABLE (((1 << 0) << 16) | (0 << 0)) 174 #define RK3399_GRF_SOC_STATUS1 0xe2a4 175 #define RK3399_PCIE_PHY_PLL_LOCKED (1 << 9) 176 #define RK3399_PCIE_PHY_PLL_OUTPUT (1 << 10) 177 178 #define RK3399_PCIE_PHY_CFG_PLL_LOCK 0x10 179 #define RK3399_PCIE_PHY_CFG_CLK_TEST 0x10 180 #define RK3399_PCIE_PHY_CFG_SEPE_RATE (1 << 3) 181 #define RK3399_PCIE_PHY_CFG_CLK_SCC 0x12 182 #define RK3399_PCIE_PHY_CFG_PLL_100M (1 << 3) 183 184 static void 185 rkpcie_phy_write_conf(struct syscon *rm, uint8_t addr, uint8_t data) 186 { 187 syscon_write_4(rm, RK3399_GRF_SOC_CON8, 188 RK3399_PCIE_TEST_ADDR_MASK | 189 (addr << RK3399_PCIE_TEST_ADDR_SHIFT) | 190 RK3399_PCIE_TEST_DATA_MASK | 191 (data << RK3399_PCIE_TEST_DATA_SHIFT) | 192 RK3399_PCIE_TEST_WRITE_DISABLE); 193 delay(1); 194 syscon_write_4(rm, RK3399_GRF_SOC_CON8, 195 RK3399_PCIE_TEST_WRITE_ENABLE); 196 delay(1); 197 syscon_write_4(rm, RK3399_GRF_SOC_CON8, 198 RK3399_PCIE_TEST_WRITE_DISABLE); 199 } 200 201 static void 202 rkpcie_phy_poweron(struct rkpciephy_softc *sc, u_int lane) 203 { 204 struct syscon *rm; 205 uint32_t status; 206 int timo; 207 208 reset_deassert(sc->sc_phy_node, "phy"); 209 210 rm = fdtbus_syscon_lookup(OF_parent(sc->sc_phy_node)); 211 if (rm == NULL) 212 return; 213 214 syscon_lock(rm); 215 syscon_write_4(rm, RK3399_GRF_SOC_CON8, 216 RK3399_PCIE_TEST_ADDR_MASK | 217 RK3399_PCIE_PHY_CFG_PLL_LOCK << RK3399_PCIE_TEST_ADDR_SHIFT); 218 syscon_write_4(rm, RK3399_GRF_SOC_CON5_PCIE, 219 RK3399_TX_ELEC_IDLE_OFF_MASK << lane | 0); 220 //printf("%s %x\n", __func__, syscon_read_4(rm, RK3399_GRF_SOC_CON5_PCIE)); 221 222 for (timo = 50; timo > 0; timo--) { 223 status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1); 224 if (status & RK3399_PCIE_PHY_PLL_LOCKED) 225 break; 226 delay(20000); 227 } 228 if (timo == 0) { 229 device_printf(sc->sc_dev, "PHY PLL lock timeout\n"); 230 syscon_unlock(rm); 231 return; 232 } 233 234 rkpcie_phy_write_conf(rm, RK3399_PCIE_PHY_CFG_CLK_TEST, 235 RK3399_PCIE_PHY_CFG_SEPE_RATE); 236 rkpcie_phy_write_conf(rm, RK3399_PCIE_PHY_CFG_CLK_SCC, 237 RK3399_PCIE_PHY_CFG_PLL_100M); 238 239 for (timo = 50; timo > 0; timo--) { 240 status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1); 241 if ((status & RK3399_PCIE_PHY_PLL_OUTPUT) == 0) 242 break; 243 delay(20000); 244 } 245 if (timo == 0) { 246 device_printf(sc->sc_dev, "PHY PLL output enable timeout\n"); 247 syscon_unlock(rm); 248 return; 249 } 250 251 syscon_write_4(rm, RK3399_GRF_SOC_CON8, 252 RK3399_PCIE_TEST_ADDR_MASK | 253 RK3399_PCIE_PHY_CFG_PLL_LOCK << RK3399_PCIE_TEST_ADDR_SHIFT); 254 255 for (timo = 50; timo > 0; timo--) { 256 status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1); 257 if (status & RK3399_PCIE_PHY_PLL_LOCKED) 258 break; 259 delay(20000); 260 } 261 if (timo == 0) { 262 device_printf(sc->sc_dev, "PHY PLL relock timeout\n"); 263 syscon_unlock(rm); 264 return; 265 } 266 syscon_unlock(rm); 267 } 268