1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Soren Schmidt <sos@deepcore.dk> 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 AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: eqos_fdt.c 1049 2022-12-03 14:25:46Z sos $ 29 */ 30 31 #include "opt_platform.h" 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/systm.h> 38 #include <sys/endian.h> 39 #include <sys/hash.h> 40 #include <sys/gpio.h> 41 #include <sys/rman.h> 42 #include <sys/socket.h> 43 #include <machine/bus.h> 44 45 #include <net/if.h> 46 #include <net/if_media.h> 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 50 #include <dev/ofw/ofw_bus.h> 51 #include <dev/ofw/ofw_bus_subr.h> 52 53 #include <dev/extres/hwreset/hwreset.h> 54 #include <dev/extres/regulator/regulator.h> 55 #include <dev/extres/syscon/syscon.h> 56 57 #include <dev/eqos/if_eqos_var.h> 58 59 #include "if_eqos_if.h" 60 #include "syscon_if.h" 61 #include "gpio_if.h" 62 #include "rk_otp_if.h" 63 64 #define RK356XGMAC0 0xfe2a0000 65 #define RK356XGMAC1 0xfe010000 66 #define RK3588GMAC0 0xfe1b0000 67 #define RK3588GMAC1 0xfe1c0000 68 69 #define EQOS_GRF_GMAC0 0x0380 70 #define EQOS_GRF_GMAC1 0x0388 71 #define EQOS_CON0_OFFSET 0 72 #define EQOS_CON1_OFFSET 4 73 74 #define EQOS_GMAC_PHY_INTF_SEL_RGMII 0x00fc0010 75 #define EQOS_GMAC_PHY_INTF_SEL_RMII 0x00fc0040 76 #define EQOS_GMAC_RXCLK_DLY_ENABLE 0x00020002 77 #define EQOS_GMAC_RXCLK_DLY_DISABLE 0x00020000 78 #define EQOS_GMAC_TXCLK_DLY_ENABLE 0x00010001 79 #define EQOS_GMAC_TXCLK_DLY_DISABLE 0x00010000 80 #define EQOS_GMAC_CLK_RX_DL_CFG(val) (0x7f000000 | val << 8) 81 #define EQOS_GMAC_CLK_TX_DL_CFG(val) (0x007f0000 | val) 82 83 #define WR4(sc, o, v) bus_write_4(sc->res[EQOS_RES_MEM], (o), (v)) 84 85 static const struct ofw_compat_data compat_data[] = { 86 {"snps,dwmac-4.20a", 1}, 87 { NULL, 0 } 88 }; 89 90 91 static int 92 eqos_phy_reset(device_t dev) 93 { 94 pcell_t gpio_prop[4]; 95 pcell_t delay_prop[3]; 96 phandle_t node, gpio_node; 97 device_t gpio; 98 uint32_t pin, flags; 99 uint32_t pin_value; 100 101 node = ofw_bus_get_node(dev); 102 if (OF_getencprop(node, "snps,reset-gpio", 103 gpio_prop, sizeof(gpio_prop)) <= 0) 104 return (0); 105 106 if (OF_getencprop(node, "snps,reset-delays-us", 107 delay_prop, sizeof(delay_prop)) <= 0) { 108 device_printf(dev, 109 "Wrong property for snps,reset-delays-us"); 110 return (ENXIO); 111 } 112 113 gpio_node = OF_node_from_xref(gpio_prop[0]); 114 if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) { 115 device_printf(dev, 116 "Can't find gpio controller for phy reset\n"); 117 return (ENXIO); 118 } 119 120 if (GPIO_MAP_GPIOS(gpio, node, gpio_node, 121 nitems(gpio_prop) - 1, 122 gpio_prop + 1, &pin, &flags) != 0) { 123 device_printf(dev, "Can't map gpio for phy reset\n"); 124 return (ENXIO); 125 } 126 127 pin_value = GPIO_PIN_LOW; 128 if (OF_hasprop(node, "snps,reset-active-low")) 129 pin_value = GPIO_PIN_HIGH; 130 131 GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); 132 GPIO_PIN_SET(gpio, pin, pin_value); 133 DELAY(delay_prop[0]); 134 GPIO_PIN_SET(gpio, pin, !pin_value); 135 DELAY(delay_prop[1]); 136 GPIO_PIN_SET(gpio, pin, pin_value); 137 DELAY(delay_prop[2]); 138 139 return (0); 140 } 141 142 static int 143 eqos_fdt_init(device_t dev) 144 { 145 struct eqos_softc *sc = device_get_softc(dev); 146 phandle_t node = ofw_bus_get_node(dev); 147 hwreset_t eqos_reset; 148 regulator_t eqos_supply; 149 uint32_t rx_delay, tx_delay; 150 uint8_t buffer[16]; 151 152 if (OF_hasprop(node, "rockchip,grf") && 153 syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf)) { 154 device_printf(dev, "cannot get grf driver handle\n"); 155 return (ENXIO); 156 } 157 158 /* figure out if gmac0 or gmac1 offset */ 159 switch (rman_get_start(sc->res[EQOS_RES_MEM])) { 160 case RK356XGMAC0: /* RK356X gmac0 */ 161 sc->grf_offset = EQOS_GRF_GMAC0; 162 break; 163 case RK356XGMAC1: /* RK356X gmac1 */ 164 sc->grf_offset = EQOS_GRF_GMAC1; 165 break; 166 case RK3588GMAC0: /* RK3588 gmac0 */ 167 case RK3588GMAC1: /* RK3588 gmac1 */ 168 default: 169 device_printf(dev, "Unknown eqos address\n"); 170 return (ENXIO); 171 } 172 173 if (hwreset_get_by_ofw_idx(dev, node, 0, &eqos_reset)) { 174 device_printf(dev, "cannot get reset\n"); 175 return (ENXIO); 176 } 177 else 178 hwreset_assert(eqos_reset); 179 180 sc->csr_clock = 125000000; 181 sc->csr_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_100_150; 182 183 if (OF_getencprop(node, "tx_delay", &tx_delay, sizeof(tx_delay)) <= 0) 184 tx_delay = 0x30; 185 if (OF_getencprop(node, "rx_delay", &rx_delay, sizeof(rx_delay)) <= 0) 186 rx_delay = 0x10; 187 188 SYSCON_WRITE_4(sc->grf, sc->grf_offset + EQOS_CON0_OFFSET, 189 EQOS_GMAC_CLK_RX_DL_CFG(rx_delay) | 190 EQOS_GMAC_CLK_TX_DL_CFG(tx_delay)); 191 SYSCON_WRITE_4(sc->grf, sc->grf_offset + EQOS_CON1_OFFSET, 192 EQOS_GMAC_PHY_INTF_SEL_RGMII | 193 EQOS_GMAC_RXCLK_DLY_ENABLE | 194 EQOS_GMAC_TXCLK_DLY_ENABLE); 195 196 if (!regulator_get_by_ofw_property(dev, 0, "phy-supply", 197 &eqos_supply)) { 198 if (regulator_enable(eqos_supply)) 199 device_printf(dev, "cannot enable 'phy' regulator\n"); 200 } 201 else 202 device_printf(dev, "no phy-supply property\n"); 203 204 if (eqos_phy_reset(dev)) 205 return (ENXIO); 206 207 if (eqos_reset) 208 hwreset_deassert(eqos_reset); 209 210 /* set the MAC address if we have OTP data handy */ 211 if (!RK_OTP_READ(dev, buffer, 0, sizeof(buffer))) { 212 uint32_t mac; 213 214 mac = hash32_buf(buffer, sizeof(buffer), HASHINIT); 215 WR4(sc, GMAC_MAC_ADDRESS0_LOW, 216 htobe32((mac & 0xffffff00) | 0x22)); 217 218 mac = hash32_buf(buffer, sizeof(buffer), mac); 219 WR4(sc, GMAC_MAC_ADDRESS0_HIGH, 220 htobe16((mac & 0x0000ffff) + (device_get_unit(dev) << 8))); 221 } 222 223 return (0); 224 } 225 226 static int 227 eqos_fdt_probe(device_t dev) 228 { 229 230 if (!ofw_bus_status_okay(dev)) 231 return (ENXIO); 232 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 233 return (ENXIO); 234 235 device_set_desc(dev, "DesignWare EQOS Gigabit ethernet"); 236 237 return (BUS_PROBE_DEFAULT); 238 } 239 240 241 static device_method_t eqos_fdt_methods[] = { 242 /* Device interface */ 243 DEVMETHOD(device_probe, eqos_fdt_probe), 244 245 /* EQOS interface */ 246 DEVMETHOD(if_eqos_init, eqos_fdt_init), 247 248 DEVMETHOD_END 249 }; 250 251 DEFINE_CLASS_1(eqos, eqos_fdt_driver, eqos_fdt_methods, 252 sizeof(struct eqos_softc), eqos_driver); 253 DRIVER_MODULE(eqos, simplebus, eqos_fdt_driver, 0, 0); 254 MODULE_DEPEND(eqos, ether, 1, 1, 1); 255 MODULE_DEPEND(eqos, miibus, 1, 1, 1); 256