1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Adrian Chadd <adrian@FreeBSD.org>. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/bus.h> 30 #include <sys/errno.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/socket.h> 35 #include <sys/sockio.h> 36 #include <sys/sysctl.h> 37 #include <sys/systm.h> 38 39 #include <net/if.h> 40 #include <net/if_var.h> 41 #include <net/if_arp.h> 42 #include <net/ethernet.h> 43 #include <net/if_dl.h> 44 #include <net/if_media.h> 45 #include <net/if_types.h> 46 47 #include <machine/bus.h> 48 #include <dev/iicbus/iic.h> 49 #include <dev/iicbus/iiconf.h> 50 #include <dev/iicbus/iicbus.h> 51 #include <dev/mii/mii.h> 52 #include <dev/mii/miivar.h> 53 #include <dev/mdio/mdio.h> 54 #include <dev/extres/clk/clk.h> 55 #include <dev/extres/hwreset/hwreset.h> 56 57 #include <dev/fdt/fdt_common.h> 58 #include <dev/ofw/ofw_bus.h> 59 #include <dev/ofw/ofw_bus_subr.h> 60 61 #include <dev/etherswitch/etherswitch.h> 62 63 #include <dev/etherswitch/ar40xx/ar40xx_var.h> 64 #include <dev/etherswitch/ar40xx/ar40xx_reg.h> 65 #include <dev/etherswitch/ar40xx/ar40xx_hw.h> 66 #include <dev/etherswitch/ar40xx/ar40xx_debug.h> 67 68 /* 69 * XXX these are here for now; move the code using these 70 * into main.c once this is all done! 71 */ 72 #include <dev/etherswitch/ar40xx/ar40xx_hw_vtu.h> 73 #include <dev/etherswitch/ar40xx/ar40xx_hw_port.h> 74 #include <dev/etherswitch/ar40xx/ar40xx_hw_mirror.h> 75 76 #include "mdio_if.h" 77 #include "miibus_if.h" 78 #include "etherswitch_if.h" 79 80 /* 81 * Reset the ESS switch. This also resets the ESS ethernet 82 * and PSGMII block. 83 */ 84 int 85 ar40xx_hw_ess_reset(struct ar40xx_softc *sc) 86 { 87 int ret; 88 89 AR40XX_DPRINTF(sc, AR40XX_DBG_HW_RESET, "%s: called\n", __func__); 90 91 ret = hwreset_assert(sc->sc_ess_rst); 92 if (ret != 0) { 93 device_printf(sc->sc_dev, "ERROR: failed to assert reset\n"); 94 return ret; 95 } 96 DELAY(10*1000); 97 98 ret = hwreset_deassert(sc->sc_ess_rst); 99 if (ret != 0) { 100 device_printf(sc->sc_dev, 101 "ERROR: failed to deassert reset\n"); 102 return ret; 103 } 104 105 DELAY(10*1000); 106 107 return (0); 108 } 109 110 int 111 ar40xx_hw_init_globals(struct ar40xx_softc *sc) 112 { 113 uint32_t reg; 114 115 AR40XX_DPRINTF(sc, AR40XX_DBG_HW_INIT, "%s: called\n", __func__); 116 117 /* enable CPU port and disable mirror port */ 118 reg = AR40XX_FWD_CTRL0_CPU_PORT_EN 119 | AR40XX_FWD_CTRL0_MIRROR_PORT; 120 AR40XX_REG_WRITE(sc, AR40XX_REG_FWD_CTRL0, reg); 121 122 /* forward multicast and broadcast frames to CPU */ 123 reg = (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_UC_FLOOD_S) 124 | (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_MC_FLOOD_S) 125 | (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_BC_FLOOD_S); 126 AR40XX_REG_WRITE(sc, AR40XX_REG_FWD_CTRL1, reg); 127 128 /* enable jumbo frames */ 129 reg = AR40XX_REG_READ(sc, AR40XX_REG_MAX_FRAME_SIZE); 130 reg &= ~AR40XX_MAX_FRAME_SIZE_MTU; 131 reg |= 9018 + 8 + 2; 132 AR40XX_REG_WRITE(sc, AR40XX_REG_MAX_FRAME_SIZE, reg); 133 134 /* Enable MIB counters */ 135 reg = AR40XX_REG_READ(sc, AR40XX_REG_MODULE_EN); 136 reg |= AR40XX_MODULE_EN_MIB; 137 AR40XX_REG_WRITE(sc, AR40XX_REG_MODULE_EN, reg); 138 139 /* Disable AZ */ 140 AR40XX_REG_WRITE(sc, AR40XX_REG_EEE_CTRL, 0); 141 142 /* set flowctrl thershold for cpu port */ 143 reg = (AR40XX_PORT0_FC_THRESH_ON_DFLT << 16) 144 | AR40XX_PORT0_FC_THRESH_OFF_DFLT; 145 AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_FLOWCTRL_THRESH(0), reg); 146 147 AR40XX_REG_BARRIER_WRITE(sc); 148 149 return (0); 150 } 151 152 int 153 ar40xx_hw_vlan_init(struct ar40xx_softc *sc) 154 { 155 int i; 156 157 AR40XX_DPRINTF(sc, AR40XX_DBG_HW_INIT, "%s: called\n", __func__); 158 159 /* Enable VLANs by default */ 160 sc->sc_vlan.vlan = 1; 161 162 /* Configure initial LAN/WAN bitmap and include CPU port as tagged */ 163 sc->sc_vlan.vlan_id[AR40XX_LAN_VLAN] = AR40XX_LAN_VLAN 164 | ETHERSWITCH_VID_VALID; 165 sc->sc_vlan.vlan_id[AR40XX_WAN_VLAN] = AR40XX_WAN_VLAN 166 | ETHERSWITCH_VID_VALID; 167 168 sc->sc_vlan.vlan_ports[AR40XX_LAN_VLAN] = 169 sc->sc_config.switch_cpu_bmp | sc->sc_config.switch_lan_bmp; 170 sc->sc_vlan.vlan_untagged[AR40XX_LAN_VLAN] = 171 sc->sc_config.switch_lan_bmp; 172 173 sc->sc_vlan.vlan_ports[AR40XX_WAN_VLAN] = 174 sc->sc_config.switch_cpu_bmp | sc->sc_config.switch_wan_bmp; 175 sc->sc_vlan.vlan_untagged[AR40XX_WAN_VLAN] = 176 sc->sc_config.switch_wan_bmp; 177 178 /* Populate the per-port PVID - pvid[] is an index into vlan_id[] */ 179 for (i = 0; i < AR40XX_NUM_PORTS; i++) { 180 if (sc->sc_config.switch_lan_bmp & (1U << i)) 181 sc->sc_vlan.pvid[i] = AR40XX_LAN_VLAN; 182 if (sc->sc_config.switch_wan_bmp & (1U << i)) 183 sc->sc_vlan.pvid[i] = AR40XX_WAN_VLAN; 184 } 185 186 return (0); 187 } 188 189 /* 190 * Apply the per-port and global configuration from software. 191 * 192 * This is useful if we ever start doing the linux switch framework 193 * thing of updating the config in one hit and pushing it to the 194 * hardware. For now it's just used in the reset path. 195 */ 196 int 197 ar40xx_hw_sw_hw_apply(struct ar40xx_softc *sc) 198 { 199 uint8_t portmask[AR40XX_NUM_PORTS]; 200 int i, j, ret; 201 202 AR40XX_DPRINTF(sc, AR40XX_DBG_HW_INIT, "%s: called\n", __func__); 203 204 /* 205 * Flush the VTU configuration. 206 */ 207 ret = ar40xx_hw_vtu_flush(sc); 208 if (ret != 0) { 209 device_printf(sc->sc_dev, 210 "ERROR: couldn't apply config; vtu flush failed (%d)\n", 211 ret); 212 return (ret); 213 } 214 215 memset(portmask, 0, sizeof(portmask)); 216 217 /* 218 * Configure the ports based on whether it's 802.1q 219 * VLANs, or just straight up per-port VLANs. 220 */ 221 if (sc->sc_vlan.vlan) { 222 device_printf(sc->sc_dev, "%s: configuring 802.1q VLANs\n", 223 __func__); 224 for (j = 0; j < AR40XX_NUM_VTU_ENTRIES; j++) { 225 uint8_t vp = sc->sc_vlan.vlan_ports[j]; 226 227 if (!vp) 228 continue; 229 if ((sc->sc_vlan.vlan_id[j] 230 & ETHERSWITCH_VID_VALID) == 0) 231 continue; 232 233 for (i = 0; i < AR40XX_NUM_PORTS; i++) { 234 uint8_t mask = (1U << i); 235 236 if (vp & mask) 237 portmask[i] |= vp & ~mask; 238 } 239 240 ar40xx_hw_vtu_load_vlan(sc, 241 sc->sc_vlan.vlan_id[j] & ETHERSWITCH_VID_MASK, 242 sc->sc_vlan.vlan_ports[j], 243 sc->sc_vlan.vlan_untagged[j]); 244 } 245 } else { 246 device_printf(sc->sc_dev, "%s: configuring per-port VLANs\n", 247 __func__); 248 for (i = 0; i < AR40XX_NUM_PORTS; i++) { 249 if (i == AR40XX_PORT_CPU) 250 continue; 251 252 portmask[i] = (1U << AR40XX_PORT_CPU); 253 portmask[AR40XX_PORT_CPU] |= (1U << i); 254 } 255 } 256 257 /* 258 * Update per-port destination mask, vlan tag settings 259 */ 260 for (i = 0; i < AR40XX_NUM_PORTS; i++) 261 (void) ar40xx_hw_port_setup(sc, i, portmask[i]); 262 263 /* Set the mirror register config */ 264 ret = ar40xx_hw_mirror_set_registers(sc); 265 if (ret != 0) { 266 device_printf(sc->sc_dev, 267 "ERROR: couldn't apply config; mirror config failed" 268 " (%d)\n", 269 ret); 270 return (ret); 271 } 272 273 return (0); 274 } 275 276 int 277 ar40xx_hw_wait_bit(struct ar40xx_softc *sc, int reg, uint32_t mask, 278 uint32_t val) 279 { 280 int timeout = 20; 281 uint32_t t; 282 283 while (true) { 284 AR40XX_REG_BARRIER_READ(sc); 285 t = AR40XX_REG_READ(sc, reg); 286 if ((t & mask) == val) 287 return 0; 288 289 if (timeout-- <= 0) 290 break; 291 292 DELAY(20); 293 } 294 295 device_printf(sc->sc_dev, "ERROR: timeout for reg " 296 "%08x: %08x & %08x != %08x\n", 297 (unsigned int)reg, t, mask, val); 298 return (ETIMEDOUT); 299 } 300 301 /* 302 * Read the switch MAC address. 303 */ 304 int 305 ar40xx_hw_read_switch_mac_address(struct ar40xx_softc *sc, 306 struct ether_addr *ea) 307 { 308 uint32_t ret0, ret1; 309 char *s; 310 311 s = (void *) ea; 312 313 AR40XX_LOCK_ASSERT(sc); 314 315 AR40XX_REG_BARRIER_READ(sc); 316 ret0 = AR40XX_REG_READ(sc, AR40XX_REG_SW_MAC_ADDR0); 317 ret1 = AR40XX_REG_READ(sc, AR40XX_REG_SW_MAC_ADDR1); 318 319 s[5] = MS(ret0, AR40XX_REG_SW_MAC_ADDR0_BYTE5); 320 s[4] = MS(ret0, AR40XX_REG_SW_MAC_ADDR0_BYTE4); 321 s[3] = MS(ret1, AR40XX_REG_SW_MAC_ADDR1_BYTE3); 322 s[2] = MS(ret1, AR40XX_REG_SW_MAC_ADDR1_BYTE2); 323 s[1] = MS(ret1, AR40XX_REG_SW_MAC_ADDR1_BYTE1); 324 s[0] = MS(ret1, AR40XX_REG_SW_MAC_ADDR1_BYTE0); 325 326 return (0); 327 } 328 329 /* 330 * Set the switch MAC address. 331 */ 332 int 333 ar40xx_hw_write_switch_mac_address(struct ar40xx_softc *sc, 334 struct ether_addr *ea) 335 { 336 uint32_t ret0 = 0, ret1 = 0; 337 char *s; 338 339 s = (void *) ea; 340 341 AR40XX_LOCK_ASSERT(sc); 342 343 ret0 |= SM(s[5], AR40XX_REG_SW_MAC_ADDR0_BYTE5); 344 ret0 |= SM(s[4], AR40XX_REG_SW_MAC_ADDR0_BYTE4); 345 346 ret1 |= SM(s[3], AR40XX_REG_SW_MAC_ADDR1_BYTE3); 347 ret1 |= SM(s[2], AR40XX_REG_SW_MAC_ADDR1_BYTE2); 348 ret1 |= SM(s[1], AR40XX_REG_SW_MAC_ADDR1_BYTE1); 349 ret1 |= SM(s[0], AR40XX_REG_SW_MAC_ADDR1_BYTE0); 350 351 AR40XX_REG_WRITE(sc, AR40XX_REG_SW_MAC_ADDR0, ret0); 352 AR40XX_REG_WRITE(sc, AR40XX_REG_SW_MAC_ADDR1, ret1); 353 354 AR40XX_REG_BARRIER_WRITE(sc); 355 356 return (0); 357 } 358