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