421 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Microchip LAN937X switch driver main logic3 * Copyright (C) 2019-2022 Microchip Technology Inc.4 */5#include <linux/kernel.h>6#include <linux/module.h>7#include <linux/iopoll.h>8#include <linux/phy.h>9#include <linux/of_net.h>10#include <linux/if_bridge.h>11#include <linux/if_vlan.h>12#include <linux/math.h>13#include <net/dsa.h>14#include <net/switchdev.h>15 16#include "lan937x_reg.h"17#include "ksz_common.h"18#include "ksz9477.h"19#include "lan937x.h"20 21static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)22{23 return regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0);24}25 26static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset,27 u8 bits, bool set)28{29 return regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset),30 bits, set ? bits : 0);31}32 33static int lan937x_enable_spi_indirect_access(struct ksz_device *dev)34{35 u16 data16;36 int ret;37 38 /* Enable Phy access through SPI */39 ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false);40 if (ret < 0)41 return ret;42 43 ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16);44 if (ret < 0)45 return ret;46 47 /* Allow SPI access */48 data16 |= VPHY_SPI_INDIRECT_ENABLE;49 50 return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16);51}52 53static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg)54{55 u16 addr_base = REG_PORT_T1_PHY_CTRL_BASE;56 u16 temp;57 58 if (is_lan937x_tx_phy(dev, addr))59 addr_base = REG_PORT_TX_PHY_CTRL_BASE;60 61 /* get register address based on the logical port */62 temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2)));63 64 return ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp);65}66 67static int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg,68 u16 val)69{70 unsigned int value;71 int ret;72 73 /* Check for internal phy port */74 if (!dev->info->internal_phy[addr])75 return -EOPNOTSUPP;76 77 ret = lan937x_vphy_ind_addr_wr(dev, addr, reg);78 if (ret < 0)79 return ret;80 81 /* Write the data to be written to the VPHY reg */82 ret = ksz_write16(dev, REG_VPHY_IND_DATA__2, val);83 if (ret < 0)84 return ret;85 86 /* Write the Write En and Busy bit */87 ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2,88 (VPHY_IND_WRITE | VPHY_IND_BUSY));89 if (ret < 0)90 return ret;91 92 ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2,93 value, !(value & VPHY_IND_BUSY), 10,94 1000);95 if (ret < 0) {96 dev_err(dev->dev, "Failed to write phy register\n");97 return ret;98 }99 100 return 0;101}102 103static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg,104 u16 *val)105{106 unsigned int value;107 int ret;108 109 /* Check for internal phy port, return 0xffff for non-existent phy */110 if (!dev->info->internal_phy[addr])111 return 0xffff;112 113 ret = lan937x_vphy_ind_addr_wr(dev, addr, reg);114 if (ret < 0)115 return ret;116 117 /* Write Read and Busy bit to start the transaction */118 ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY);119 if (ret < 0)120 return ret;121 122 ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2,123 value, !(value & VPHY_IND_BUSY), 10,124 1000);125 if (ret < 0) {126 dev_err(dev->dev, "Failed to read phy register\n");127 return ret;128 }129 130 /* Read the VPHY register which has the PHY data */131 return ksz_read16(dev, REG_VPHY_IND_DATA__2, val);132}133 134int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)135{136 return lan937x_internal_phy_read(dev, addr, reg, data);137}138 139int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)140{141 return lan937x_internal_phy_write(dev, addr, reg, val);142}143 144int lan937x_reset_switch(struct ksz_device *dev)145{146 u32 data32;147 int ret;148 149 /* reset switch */150 ret = lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true);151 if (ret < 0)152 return ret;153 154 /* Enable Auto Aging */155 ret = lan937x_cfg(dev, REG_SW_LUE_CTRL_1, SW_LINK_AUTO_AGING, true);156 if (ret < 0)157 return ret;158 159 /* disable interrupts */160 ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);161 if (ret < 0)162 return ret;163 164 ret = ksz_write32(dev, REG_SW_INT_STATUS__4, POR_READY_INT);165 if (ret < 0)166 return ret;167 168 ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF);169 if (ret < 0)170 return ret;171 172 return ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);173}174 175void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port)176{177 const u32 *masks = dev->info->masks;178 const u16 *regs = dev->info->regs;179 struct dsa_switch *ds = dev->ds;180 u8 member;181 182 /* enable tag tail for host port */183 if (cpu_port)184 lan937x_port_cfg(dev, port, REG_PORT_CTRL_0,185 PORT_TAIL_TAG_ENABLE, true);186 187 /* Enable the Port Queue split */188 ksz9477_port_queue_split(dev, port);189 190 /* set back pressure for half duplex */191 lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE,192 true);193 194 /* enable 802.1p priority */195 lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);196 197 if (!dev->info->internal_phy[port])198 lan937x_port_cfg(dev, port, regs[P_XMII_CTRL_0],199 masks[P_MII_TX_FLOW_CTRL] |200 masks[P_MII_RX_FLOW_CTRL],201 true);202 203 if (cpu_port)204 member = dsa_user_ports(ds);205 else206 member = BIT(dsa_upstream_port(ds, port));207 208 dev->dev_ops->cfg_port_member(dev, port, member);209}210 211void lan937x_config_cpu_port(struct dsa_switch *ds)212{213 struct ksz_device *dev = ds->priv;214 struct dsa_port *dp;215 216 dsa_switch_for_each_cpu_port(dp, ds) {217 if (dev->info->cpu_ports & (1 << dp->index)) {218 dev->cpu_port = dp->index;219 220 /* enable cpu port */221 lan937x_port_setup(dev, dp->index, true);222 }223 }224 225 dsa_switch_for_each_user_port(dp, ds) {226 ksz_port_stp_state_set(ds, dp->index, BR_STATE_DISABLED);227 }228}229 230int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)231{232 struct dsa_switch *ds = dev->ds;233 int ret;234 235 new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN;236 237 if (dsa_is_cpu_port(ds, port))238 new_mtu += LAN937X_TAG_LEN;239 240 if (new_mtu >= FR_MIN_SIZE)241 ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,242 PORT_JUMBO_PACKET, true);243 else244 ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,245 PORT_JUMBO_PACKET, false);246 if (ret < 0) {247 dev_err(ds->dev, "failed to enable jumbo\n");248 return ret;249 }250 251 /* Write the frame size in PORT_MAX_FR_SIZE register */252 ret = ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu);253 if (ret) {254 dev_err(ds->dev, "failed to update mtu for port %d\n", port);255 return ret;256 }257 258 return 0;259}260 261int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs)262{263 u32 secs = msecs / 1000;264 u32 value;265 int ret;266 267 value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);268 269 ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value);270 if (ret < 0)271 return ret;272 273 value = FIELD_GET(SW_AGE_PERIOD_19_8_M, secs);274 275 return ksz_write16(dev, REG_SW_AGE_PERIOD__2, value);276}277 278static void lan937x_set_tune_adj(struct ksz_device *dev, int port,279 u16 reg, u8 val)280{281 u16 data16;282 283 ksz_pread16(dev, port, reg, &data16);284 285 /* Update tune Adjust */286 data16 |= FIELD_PREP(PORT_TUNE_ADJ, val);287 ksz_pwrite16(dev, port, reg, data16);288 289 /* write DLL reset to take effect */290 data16 |= PORT_DLL_RESET;291 ksz_pwrite16(dev, port, reg, data16);292}293 294static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port)295{296 u8 val;297 298 /* Apply different codes based on the ports as per characterization299 * results300 */301 val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS :302 RGMII_2_TX_DELAY_2NS;303 304 lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val);305}306 307static void lan937x_set_rgmii_rx_delay(struct ksz_device *dev, int port)308{309 u8 val;310 311 val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS :312 RGMII_2_RX_DELAY_2NS;313 314 lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_4, val);315}316 317void lan937x_phylink_get_caps(struct ksz_device *dev, int port,318 struct phylink_config *config)319{320 config->mac_capabilities = MAC_100FD;321 322 if (dev->info->supports_rgmii[port]) {323 /* MII/RMII/RGMII ports */324 config->mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE |325 MAC_100HD | MAC_10 | MAC_1000FD;326 } else if (is_lan937x_tx_phy(dev, port)) {327 config->mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE |328 MAC_100HD | MAC_10;329 }330}331 332void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port)333{334 struct ksz_port *p = &dev->ports[port];335 336 if (p->rgmii_tx_val) {337 lan937x_set_rgmii_tx_delay(dev, port);338 dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n",339 port);340 }341 342 if (p->rgmii_rx_val) {343 lan937x_set_rgmii_rx_delay(dev, port);344 dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n",345 port);346 }347}348 349int lan937x_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)350{351 return ksz_pwrite32(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);352}353 354int lan937x_switch_init(struct ksz_device *dev)355{356 dev->port_mask = (1 << dev->info->port_cnt) - 1;357 358 return 0;359}360 361int lan937x_setup(struct dsa_switch *ds)362{363 struct ksz_device *dev = ds->priv;364 int ret;365 366 /* enable Indirect Access from SPI to the VPHY registers */367 ret = lan937x_enable_spi_indirect_access(dev);368 if (ret < 0) {369 dev_err(dev->dev, "failed to enable spi indirect access");370 return ret;371 }372 373 /* The VLAN aware is a global setting. Mixed vlan374 * filterings are not supported.375 */376 ds->vlan_filtering_is_global = true;377 378 /* Enable aggressive back off for half duplex & UNH mode */379 ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_0, (SW_PAUSE_UNH_MODE |380 SW_NEW_BACKOFF |381 SW_AGGR_BACKOFF), true);382 if (ret < 0)383 return ret;384 385 /* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop386 * packets when 16 or more collisions occur387 */388 ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, true);389 if (ret < 0)390 return ret;391 392 /* enable global MIB counter freeze function */393 ret = lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);394 if (ret < 0)395 return ret;396 397 /* disable CLK125 & CLK25, 1: disable, 0: enable */398 ret = lan937x_cfg(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1,399 (SW_CLK125_ENB | SW_CLK25_ENB), true);400 if (ret < 0)401 return ret;402 403 /* Disable global VPHY support. Related to CPU interface only? */404 return ksz_rmw32(dev, REG_SW_CFG_STRAP_OVR, SW_VPHY_DISABLE,405 SW_VPHY_DISABLE);406}407 408void lan937x_teardown(struct dsa_switch *ds)409{410 411}412 413void lan937x_switch_exit(struct ksz_device *dev)414{415 lan937x_reset_switch(dev);416}417 418MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>");419MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver");420MODULE_LICENSE("GPL");421