brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · 824d930 Raw
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