1 /* $NetBSD: rk_eqos.c,v 1.1 2022/08/23 05:40:46 ryo Exp $ */ 2 3 /*- 4 * Copyright (c) 2022 Ryo Shimizu <ryo@nerv.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 #include "opt_net_mpsafe.h" 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: rk_eqos.c,v 1.1 2022/08/23 05:40:46 ryo Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/device.h> 36 #include <sys/rndsource.h> 37 38 #include <net/if_ether.h> 39 #include <net/if_media.h> 40 41 #include <dev/fdt/fdtvar.h> 42 #include <dev/fdt/syscon.h> 43 44 #include <dev/mii/miivar.h> 45 #include <dev/ic/dwc_eqos_var.h> 46 47 struct rk_eqos_softc { 48 struct eqos_softc sc_base; 49 50 struct syscon *sc_grf; 51 struct syscon *sc_php_grf; 52 int sc_id; /* ethernet0 or 1? */ 53 }; 54 55 static int rk_eqos_match(device_t, cfdata_t, void *); 56 static void rk_eqos_attach(device_t, device_t, void *); 57 58 struct rk_eqos_ops { 59 void (*set_mode_rgmii)(struct rk_eqos_softc *, int, int); 60 void (*set_speed_rgmii)(struct rk_eqos_softc *, int); 61 void (*clock_selection)(struct rk_eqos_softc *, int); 62 int (*get_unit)(struct rk_eqos_softc *, int); 63 }; 64 65 CFATTACH_DECL_NEW(rk_eqos, sizeof(struct rk_eqos_softc), 66 rk_eqos_match, rk_eqos_attach, NULL, NULL); 67 68 /* 69 * RK3588 specific 70 */ 71 #define RK3588_ETHERNET1_ADDR 0xfe1c0000 72 73 /* grf */ 74 #define RK3588_GRF_GMAC_TXRXCLK_DELAY_EN_REG (0x0300 + (4 * 7)) 75 #define RK3588_GMAC_RXCLK_DELAY_EN(id) __BIT(3 + 2 * (id)) 76 #define RK3588_GMAC_RXCLK_DELAY_DISABLE 0 77 #define RK3588_GMAC_RXCLK_DELAY_ENABLE 1 78 #define RK3588_GMAC_TXCLK_DELAY_EN(id) __BIT(2 + 2 * (id)) 79 #define RK3588_GMAC_TXCLK_DELAY_DISABLE 0 80 #define RK3588_GMAC_TXCLK_DELAY_ENABLE 1 81 #define RK3588_GRF_GMAC_TXRX_DELAY_CFG_REG(id) (0x0300 + (4 * 8) + (4 * (id))) 82 #define RK3588_GMAC_RXCLK_DELAY_CFG __BITS(15,8) 83 #define RK3588_GMAC_TXCLK_DELAY_CFG __BITS(7,0) 84 85 /* grf_php */ 86 #define RK3588_GRF_GMAC_PHY_REG 0x0008 87 #define RK3588_GMAC_PHY_IFACE_SEL(id) (__BITS(5,3) << ((id) * 6)) 88 #define RK3588_GMAC_PHY_IFACE_SEL_RGMII 1 89 #define RK3588_GMAC_PHY_IFACE_SEL_RMII 4 90 #define RK3588_GRF_CLK_CON1 0x0070 91 #define RK3588_GRF_GMAC_CLK_REG 0x0070 92 #define RK3588_GMAC_CLK_SELECT(id) __BIT(4 + 5 * (id)) 93 #define RK3588_GMAC_CLK_SELECT_IO 0 94 #define RK3588_GMAC_CLK_SELECT_CRU 1 95 #define RK3588_GMAC_CLK_RMII_DIV(id) __BIT(2 + 5 * (id)) 96 #define RK3588_GMA_CLK_RMII_DIV_DIV20 0 97 #define RK3588_GMA_CLK_RMII_DIV_DIV2 1 98 #define RK3588_GMAC_CLK_RGMII_DIV(id) (__BITS(3,2) << ((id) * 5)) 99 #define RK3588_GMAC_CLK_RGMII_DIV_DIV1 1 100 #define RK3588_GMAC_CLK_RGMII_DIV_DIV50 2 101 #define RK3588_GMAC_CLK_RGMII_DIV_DIV5 3 102 #define RK3588_GMAC_CLK_RMII_GATE_EN(id) __BIT(1 + (id) * 5) 103 #define RK3588_GMAC_CLK_RMII_GATE_DISABLE 0 104 #define RK3588_GMAC_CLK_RMII_GATE_ENABLE 1 105 #define RK3588_GMAC_CLK_MODE(id) __BIT(0 + (id) * 5) 106 #define RK3588_GMAC_CLK_MODE_RGMII 0 107 #define RK3588_GMAC_CLK_MODE_RMII 1 108 109 static void 110 rk3588_eqos_set_mode_rgmii(struct rk_eqos_softc *rk_sc, 111 int tx_delay, int rx_delay) 112 { 113 const int id = rk_sc->sc_id; 114 uint32_t txen, rxen; 115 116 if (tx_delay >= 0) { 117 txen = RK3588_GMAC_TXCLK_DELAY_ENABLE; 118 } else { 119 txen = RK3588_GMAC_TXCLK_DELAY_DISABLE; 120 tx_delay = 0; 121 } 122 if (rx_delay >= 0) { 123 rxen = RK3588_GMAC_RXCLK_DELAY_ENABLE; 124 } else { 125 rxen = RK3588_GMAC_RXCLK_DELAY_DISABLE; 126 rx_delay = 0; 127 } 128 129 syscon_lock(rk_sc->sc_grf); 130 syscon_write_4(rk_sc->sc_grf, RK3588_GRF_GMAC_TXRXCLK_DELAY_EN_REG, 131 RK3588_GMAC_TXCLK_DELAY_EN(id) << 16 | /* masks */ 132 RK3588_GMAC_RXCLK_DELAY_EN(id) << 16 | 133 __SHIFTIN(txen, RK3588_GMAC_TXCLK_DELAY_EN(id)) | /* values */ 134 __SHIFTIN(rxen, RK3588_GMAC_RXCLK_DELAY_EN(id))); 135 syscon_write_4(rk_sc->sc_grf, RK3588_GRF_GMAC_TXRX_DELAY_CFG_REG(id), 136 RK3588_GMAC_TXCLK_DELAY_CFG << 16 | /* masks */ 137 RK3588_GMAC_RXCLK_DELAY_CFG << 16 | 138 __SHIFTIN(tx_delay, RK3588_GMAC_TXCLK_DELAY_CFG) | /* values */ 139 __SHIFTIN(rx_delay, RK3588_GMAC_RXCLK_DELAY_CFG)); 140 syscon_unlock(rk_sc->sc_grf); 141 142 syscon_lock(rk_sc->sc_php_grf); 143 syscon_write_4(rk_sc->sc_php_grf, RK3588_GRF_GMAC_PHY_REG, 144 RK3588_GMAC_PHY_IFACE_SEL(id) << 16 | /* mask */ 145 __SHIFTIN(RK3588_GMAC_PHY_IFACE_SEL_RGMII, /* value */ 146 RK3588_GMAC_PHY_IFACE_SEL(id))); 147 syscon_write_4(rk_sc->sc_php_grf, RK3588_GRF_GMAC_CLK_REG, 148 RK3588_GMAC_CLK_MODE(id) << 16 | /* mask */ 149 __SHIFTIN(RK3588_GMAC_CLK_MODE_RGMII, /* value */ 150 RK3588_GMAC_CLK_MODE(id))); 151 syscon_unlock(rk_sc->sc_php_grf); 152 } 153 154 static void 155 rk3588_eqos_set_speed_rgmii(struct rk_eqos_softc *rk_sc, int speed) 156 { 157 const int id = rk_sc->sc_id; 158 u_int clksel; 159 160 switch (speed) { 161 case IFM_10_T: 162 clksel = RK3588_GMAC_CLK_RGMII_DIV_DIV50; 163 break; 164 case IFM_100_TX: 165 clksel = RK3588_GMAC_CLK_RGMII_DIV_DIV5; 166 break; 167 case IFM_1000_T: 168 default: 169 clksel = RK3588_GMAC_CLK_RGMII_DIV_DIV1; 170 break; 171 } 172 173 syscon_lock(rk_sc->sc_php_grf); 174 syscon_write_4(rk_sc->sc_php_grf, RK3588_GRF_GMAC_CLK_REG, 175 RK3588_GMAC_CLK_RGMII_DIV(id) << 16 | /* mask */ 176 __SHIFTIN(clksel, RK3588_GMAC_CLK_RGMII_DIV(id))); /* value */ 177 syscon_unlock(rk_sc->sc_php_grf); 178 } 179 180 static void 181 rk3588_eqos_clock_selection(struct rk_eqos_softc *rk_sc, int phandle) 182 { 183 const int id = rk_sc->sc_id; 184 const char *clock_in_out; 185 186 clock_in_out = fdtbus_get_string(phandle, "clock_in_out"); 187 if (clock_in_out != NULL) { 188 bool input = (strcmp(clock_in_out, "input") == 0) ? 189 true : false; 190 uint32_t clksel, gate; 191 192 if (input) { 193 clksel = RK3588_GMAC_CLK_SELECT_IO; 194 gate = RK3588_GMAC_CLK_RMII_GATE_DISABLE; 195 } else { 196 clksel = RK3588_GMAC_CLK_SELECT_CRU; 197 gate = RK3588_GMAC_CLK_RMII_GATE_ENABLE; 198 } 199 200 syscon_lock(rk_sc->sc_php_grf); 201 syscon_write_4(rk_sc->sc_php_grf, RK3588_GRF_GMAC_CLK_REG, 202 /* masks */ 203 RK3588_GMAC_CLK_SELECT(id) << 16 | 204 RK3588_GMAC_CLK_RMII_GATE_EN(id) << 16 | 205 /* values */ 206 __SHIFTIN(clksel, RK3588_GMAC_CLK_SELECT(id)) | 207 __SHIFTIN(gate, RK3588_GMAC_CLK_RMII_GATE_EN(id))); 208 syscon_unlock(rk_sc->sc_php_grf); 209 } 210 } 211 212 static int 213 rk3588_eqos_get_unit(struct rk_eqos_softc *rk_sc, int phandle) 214 { 215 bus_addr_t addr; 216 bus_size_t size; 217 218 fdtbus_get_reg(phandle, 0, &addr, &size); 219 if (addr == RK3588_ETHERNET1_ADDR) 220 return 1; 221 return 0; 222 } 223 224 static const struct rk_eqos_ops rk3588_ops = { 225 .set_mode_rgmii = rk3588_eqos_set_mode_rgmii, 226 .set_speed_rgmii = rk3588_eqos_set_speed_rgmii, 227 .clock_selection = rk3588_eqos_clock_selection, 228 .get_unit = rk3588_eqos_get_unit 229 }; 230 231 static const struct device_compatible_entry compat_data[] = { 232 { .compat = "rockchip,rk3588-gmac", .value = (uintptr_t)&rk3588_ops }, 233 DEVICE_COMPAT_EOL 234 }; 235 236 static int 237 rk_eqos_reset_gpio(const int phandle) 238 { 239 struct fdtbus_gpio_pin *pin_reset; 240 const u_int *reset_delay_us; 241 bool reset_active_low; 242 int len; 243 244 if (!of_hasprop(phandle, "snps,reset-gpio")) 245 return 0; 246 247 pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", 248 GPIO_PIN_OUTPUT); 249 if (pin_reset == NULL) 250 return ENOENT; 251 252 reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len); 253 if (reset_delay_us == NULL || len != 12) 254 return ENXIO; 255 256 reset_active_low = of_hasprop(phandle, "snps,reset-active-low"); 257 258 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); 259 delay(be32toh(reset_delay_us[0])); 260 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1); 261 delay(be32toh(reset_delay_us[1])); 262 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); 263 delay(be32toh(reset_delay_us[2])); 264 265 return 0; 266 } 267 268 static void 269 rk_eqos_init_props(struct eqos_softc *sc, int phandle) 270 { 271 prop_dictionary_t prop = device_properties(sc->sc_dev); 272 273 /* Defaults */ 274 prop_dictionary_set_uint(prop, "snps,wr_osr_lmt", 4); 275 prop_dictionary_set_uint(prop, "snps,rd_osr_lmt", 8); 276 277 if (of_hasprop(phandle, "snps,mixed-burst")) 278 prop_dictionary_set_bool(prop, "snps,mixed-burst", true); 279 if (of_hasprop(phandle, "snps,tso")) 280 prop_dictionary_set_bool(prop, "snps,tso", true); 281 } 282 283 static int 284 rk_eqos_match(device_t parent, cfdata_t cf, void *aux) 285 { 286 struct fdt_attach_args * const faa = aux; 287 288 return of_compatible_match(faa->faa_phandle, compat_data); 289 } 290 291 static void 292 rk_eqos_attach(device_t parent, device_t self, void *aux) 293 { 294 struct rk_eqos_softc * const rk_sc = device_private(self); 295 struct eqos_softc * const sc = &rk_sc->sc_base; 296 struct fdt_attach_args * const faa = aux; 297 const int phandle = faa->faa_phandle; 298 const char *phy_mode; 299 char intrstr[128]; 300 bus_addr_t addr; 301 bus_size_t size; 302 u_int tx_delay, rx_delay; 303 int n; 304 305 struct rk_eqos_ops *ops = (struct rk_eqos_ops *) 306 of_compatible_lookup(phandle, compat_data)->value; 307 308 /* multiple ethernet? */ 309 if (ops->get_unit != NULL) 310 rk_sc->sc_id = ops->get_unit(rk_sc, phandle); 311 312 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 313 aprint_error(": couldn't get registers\n"); 314 return; 315 } 316 317 rk_sc->sc_grf = fdtbus_syscon_acquire(phandle, "rockchip,grf"); 318 if (rk_sc->sc_grf == NULL) { 319 aprint_error(": couldn't get grf syscon\n"); 320 return; 321 } 322 rk_sc->sc_php_grf = fdtbus_syscon_acquire(phandle, "rockchip,php_grf"); 323 if (rk_sc->sc_php_grf == NULL) { 324 aprint_error(": couldn't get php_grf syscon\n"); 325 return; 326 } 327 328 sc->sc_dev = self; 329 sc->sc_bst = faa->faa_bst; 330 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 331 aprint_error(": couldn't map registers\n"); 332 return; 333 } 334 sc->sc_dmat = faa->faa_dmat; 335 336 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 337 aprint_error(": failed to decode interrupt\n"); 338 return; 339 } 340 341 /* enable clocks */ 342 struct clk *clk; 343 fdtbus_clock_assign(phandle); 344 for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++) { 345 if (clk_enable(clk) != 0) { 346 aprint_error(": couldn't enable clock #%d\n", n); 347 return; 348 } 349 } 350 /* de-assert resets */ 351 struct fdtbus_reset *rst; 352 for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++) { 353 if (fdtbus_reset_deassert(rst) != 0) { 354 aprint_error(": couldn't de-assert reset #%d\n", n); 355 return; 356 } 357 } 358 if (rk_eqos_reset_gpio(phandle) != 0) 359 aprint_error(": GPIO reset failed\n"); /* ignore */ 360 361 if (ops->clock_selection != NULL) 362 ops->clock_selection(rk_sc, phandle); 363 364 if (of_getprop_uint32(phandle, "tx_delay", &tx_delay) != 0) 365 tx_delay = -1; 366 if (of_getprop_uint32(phandle, "rx_delay", &rx_delay) != 0) 367 rx_delay = -1; 368 369 phy_mode = fdtbus_get_string(phandle, "phy-mode"); 370 if (phy_mode == NULL) 371 phy_mode = "rgmii"; /* default: RGMII */ 372 373 if (strncmp(phy_mode, "rgmii", 5) == 0) { 374 ops->set_mode_rgmii(rk_sc, tx_delay, rx_delay); 375 if (ops->set_speed_rgmii != NULL) { 376 /* 377 * XXX: should be called back from 378 * sys/dev/ic/dwc_eqos.c:eqos_update_link() ? 379 */ 380 ops->set_speed_rgmii(rk_sc, IFM_1000_T); 381 } 382 } else { 383 aprint_error(": unsupported phy-mode '%s'\n", phy_mode); 384 return; 385 } 386 387 rk_eqos_init_props(sc, phandle); 388 sc->sc_phy_id = MII_PHY_ANY; 389 #define CSR_RATE_RGMII 125000000 /* default */ 390 sc->sc_csr_clock = CSR_RATE_RGMII; 391 392 if (eqos_attach(sc) != 0) 393 return; 394 395 #ifdef NET_MPSAFE 396 #define FDT_INTR_FLAGS FDT_INTR_MPSAFE 397 #else 398 #define FDT_INTR_FLAGS 0 399 #endif 400 if (fdtbus_intr_establish_xname(phandle, 0, IPL_NET, FDT_INTR_FLAGS, 401 eqos_intr, sc, device_xname(self)) == NULL) { 402 aprint_error_dev(self, "failed to establish interrupt on %s\n", 403 intrstr); 404 return; 405 } 406 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 407 } 408