rk_gmac.c revision 1.2
1/* $NetBSD: rk_gmac.c,v 1.2 2018/06/17 00:33:05 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30 31__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.2 2018/06/17 00:33:05 jmcneill Exp $"); 32 33#include <sys/param.h> 34#include <sys/bus.h> 35#include <sys/device.h> 36#include <sys/intr.h> 37#include <sys/systm.h> 38#include <sys/gpio.h> 39 40#include <net/if.h> 41#include <net/if_ether.h> 42#include <net/if_media.h> 43 44#include <dev/mii/miivar.h> 45 46#include <dev/ic/dwc_gmac_var.h> 47#include <dev/ic/dwc_gmac_reg.h> 48 49#include <dev/fdt/fdtvar.h> 50 51#define RK3328_GRF_MAC_CON0 0x0900 52#define RK3328_GRF_MAC_CON0_RXDLY __BITS(13,7) 53#define RK3328_GRF_MAC_CON0_TXDLY __BITS(6,0) 54 55#define RK3328_GRF_MAC_CON1 0x0904 56#define RK3328_GRF_MAC_CON1_CLKSEL __BITS(12,11) 57#define RK3328_GRF_MAC_CON1_CLKSEL_125M 0 58#define RK3328_GRF_MAC_CON1_CLKSEL_2_5M 2 59#define RK3328_GRF_MAC_CON1_CLKSEL_25M 3 60#define RK3328_GRF_MAC_CON1_MODE __BIT(9) 61#define RK3328_GRF_MAC_CON1_SEL __BITS(6,4) 62#define RK3328_GRF_MAC_CON1_SEL_RGMII 1 63#define RK3328_GRF_MAC_CON1_RXDLY_EN __BIT(1) 64#define RK3328_GRF_MAC_CON1_TXDLY_EN __BIT(0) 65 66#define RK_GMAC_TXDLY_DEFAULT 0x30 67#define RK_GMAC_RXDLY_DEFAULT 0x10 68 69static const char * compatible[] = { 70 "rockchip,rk3328-gmac", 71 NULL 72}; 73 74struct rk_gmac_softc { 75 struct dwc_gmac_softc sc_base; 76 bus_space_handle_t sc_grf_bsh; 77}; 78 79static int 80rk_gmac_reset(const int phandle) 81{ 82 struct fdtbus_gpio_pin *pin_reset; 83 const u_int *reset_delay_us; 84 bool reset_active_low; 85 int len; 86 87 if (!of_hasprop(phandle, "snps,reset-gpio")) 88 return 0; 89 90 pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", GPIO_PIN_OUTPUT); 91 if (pin_reset == NULL) 92 return ENOENT; 93 94 reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len); 95 if (reset_delay_us == NULL || len != 12) 96 return ENXIO; 97 98 reset_active_low = of_hasprop(phandle, "snps,reset-active-low"); 99 100 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); 101 delay(be32toh(reset_delay_us[0])); 102 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1); 103 delay(be32toh(reset_delay_us[1])); 104 fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); 105 delay(be32toh(reset_delay_us[2])); 106 107 return 0; 108} 109 110static int 111rk_gmac_intr(void *arg) 112{ 113 return dwc_gmac_intr(arg); 114} 115 116static void 117rk3328_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay) 118{ 119 struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; 120 121 const uint32_t write_mask = 122 (RK3328_GRF_MAC_CON1_MODE | RK3328_GRF_MAC_CON1_SEL | 123 RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN) << 16; 124 const uint32_t write_val = 125 __SHIFTIN(RK3328_GRF_MAC_CON1_SEL_RGMII, RK3328_GRF_MAC_CON1_SEL) | 126 RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN; 127 128 bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, write_mask | write_val); 129 bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON0, 130 (RK3328_GRF_MAC_CON0_TXDLY << 16) | 131 (RK3328_GRF_MAC_CON0_RXDLY << 16) | 132 __SHIFTIN(tx_delay, RK3328_GRF_MAC_CON0_TXDLY) | 133 __SHIFTIN(rx_delay, RK3328_GRF_MAC_CON0_RXDLY)); 134} 135 136static void 137rk3328_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed) 138{ 139 struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; 140 u_int clksel; 141 142 switch (speed) { 143 case IFM_10_T: 144 clksel = RK3328_GRF_MAC_CON1_CLKSEL_2_5M; 145 break; 146 case IFM_100_TX: 147 clksel = RK3328_GRF_MAC_CON1_CLKSEL_25M; 148 break; 149 default: 150 clksel = RK3328_GRF_MAC_CON1_CLKSEL_125M; 151 break; 152 } 153 154 bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, 155 (RK3328_GRF_MAC_CON1_CLKSEL << 16) | 156 __SHIFTIN(RK3328_GRF_MAC_CON1_CLKSEL_125M, RK3328_GRF_MAC_CON1_CLKSEL)); 157} 158 159static int 160rk_gmac_setup_clocks(int phandle) 161{ 162 static const char * const clknames[] = { 163#if 0 164 "stmmaceth", 165 "mac_clk_rx", 166 "mac_clk_tx", 167 "clk_mac_ref", 168 "clk_mac_refout", 169 "aclk_mac", 170 "pclk_mac" 171#else 172 "stmmaceth", 173 "aclk_mac", 174 "pclk_mac", 175 "mac_clk_tx", 176#endif 177 }; 178 static const char * const rstnames[] = { 179 "stmmaceth" 180 }; 181 struct fdtbus_reset *rst; 182 struct clk *clk; 183 int error, n; 184 185 fdtbus_clock_assign(phandle); 186 187 for (n = 0; n < __arraycount(clknames); n++) { 188 clk = fdtbus_clock_get(phandle, clknames[n]); 189 if (clk == NULL) { 190 aprint_error(": couldn't get %s clock\n", clknames[n]); 191 return ENXIO; 192 } 193 error = clk_enable(clk); 194 if (error != 0) { 195 aprint_error(": couldn't enable %s clock: %d\n", 196 clknames[n], error); 197 return error; 198 } 199 } 200 201 for (n = 0; n < __arraycount(rstnames); n++) { 202 rst = fdtbus_reset_get(phandle, rstnames[n]); 203 if (rst == NULL) { 204 aprint_error(": couldn't get %s reset\n", rstnames[n]); 205 return ENXIO; 206 } 207 error = fdtbus_reset_deassert(rst); 208 if (error != 0) { 209 aprint_error(": couldn't de-assert %s reset: %d\n", 210 rstnames[n], error); 211 return error; 212 } 213 } 214 215 delay(5000); 216 217 return 0; 218} 219 220static int 221rk_gmac_match(device_t parent, cfdata_t cf, void *aux) 222{ 223 struct fdt_attach_args * const faa = aux; 224 225 return of_match_compatible(faa->faa_phandle, compatible); 226} 227 228static void 229rk_gmac_attach(device_t parent, device_t self, void *aux) 230{ 231 struct rk_gmac_softc * const rk_sc = device_private(self); 232 struct dwc_gmac_softc * const sc = &rk_sc->sc_base; 233 struct fdt_attach_args * const faa = aux; 234 const int phandle = faa->faa_phandle; 235 const char *phy_mode; 236 char intrstr[128]; 237 bus_addr_t addr, grf_addr; 238 bus_size_t size, grf_size; 239 u_int tx_delay, rx_delay; 240 241 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 242 aprint_error(": couldn't get registers\n"); 243 return; 244 } 245 246 const int grf_phandle = fdtbus_get_phandle(phandle, "rockchip,grf"); 247 if (grf_phandle == -1) { 248 aprint_error(": couldn't get grf phandle\n"); 249 return; 250 } 251 if (fdtbus_get_reg(grf_phandle, 0, &grf_addr, &grf_size) != 0) { 252 aprint_error(": couldn't get grf registers\n"); 253 return; 254 } 255 if (bus_space_map(faa->faa_bst, grf_addr, grf_size, 0, &rk_sc->sc_grf_bsh) != 0) { 256 aprint_error(": couldn't map grf registers\n"); 257 return; 258 } 259 260 if (of_getprop_uint32(phandle, "tx_delay", &tx_delay) != 0) 261 tx_delay = RK_GMAC_TXDLY_DEFAULT; 262 263 if (of_getprop_uint32(phandle, "rx_delay", &rx_delay) != 0) 264 rx_delay = RK_GMAC_RXDLY_DEFAULT; 265 266 sc->sc_dev = self; 267 sc->sc_bst = faa->faa_bst; 268 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 269 aprint_error(": couldn't map registers\n"); 270 return; 271 } 272 sc->sc_dmat = faa->faa_dmat; 273 274 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 275 aprint_error(": failed to decode interrupt\n"); 276 return; 277 } 278 279 if (rk_gmac_setup_clocks(phandle) != 0) 280 return; 281 282 if (rk_gmac_reset(phandle) != 0) 283 aprint_error_dev(self, "PHY reset failed\n"); 284 285 if (of_hasprop(phandle, "snps,force_thresh_dma_mode")) 286 sc->sc_flags |= DWC_GMAC_FORCE_THRESH_DMA_MODE; 287 288 phy_mode = fdtbus_get_string(phandle, "phy-mode"); 289 if (phy_mode == NULL) { 290 aprint_error(": missing 'phy-mode' property\n"); 291 return; 292 } 293 294 if (strcmp(phy_mode, "rgmii") == 0) { 295 rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay); 296 297 sc->sc_set_speed = rk3328_gmac_set_speed_rgmii; 298 } else { 299 aprint_error(": unsupported phy-mode '%s'\n", phy_mode); 300 return; 301 } 302 303 aprint_naive("\n"); 304 aprint_normal(": GMAC\n"); 305 306 if (fdtbus_intr_establish(phandle, 0, IPL_NET, 0, rk_gmac_intr, sc) == NULL) { 307 aprint_error_dev(self, "failed to establish interrupt on %s\n", intrstr); 308 return; 309 } 310 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 311 312 dwc_gmac_attach(sc, GMAC_MII_CLK_150_250M_DIV102); 313} 314 315CFATTACH_DECL_NEW(rk_gmac, sizeof(struct rk_gmac_softc), 316 rk_gmac_match, rk_gmac_attach, NULL, NULL); 317