File Index
Files and directories
Sign in
FILE

rzn1_a5psw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/dsa/rzn1_a5psw.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2022 Schneider-Electric
   4 *
   5 * Clément Léger <clement.leger@bootlin.com>
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/etherdevice.h>
  10#include <linux/if_bridge.h>
  11#include <linux/if_ether.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/of.h>
  15#include <linux/of_mdio.h>
  16#include <net/dsa.h>
  17
  18#include "rzn1_a5psw.h"
  19
  20struct a5psw_stats {
  21	u16 offset;
  22	const char name[ETH_GSTRING_LEN];
  23};
  24
  25#define STAT_DESC(_offset) {	\
  26	.offset = A5PSW_##_offset,	\
  27	.name = __stringify(_offset),	\
  28}
  29
  30static const struct a5psw_stats a5psw_stats[] = {
  31	STAT_DESC(aFramesTransmittedOK),
  32	STAT_DESC(aFramesReceivedOK),
  33	STAT_DESC(aFrameCheckSequenceErrors),
  34	STAT_DESC(aAlignmentErrors),
  35	STAT_DESC(aOctetsTransmittedOK),
  36	STAT_DESC(aOctetsReceivedOK),
  37	STAT_DESC(aTxPAUSEMACCtrlFrames),
  38	STAT_DESC(aRxPAUSEMACCtrlFrames),
  39	STAT_DESC(ifInErrors),
  40	STAT_DESC(ifOutErrors),
  41	STAT_DESC(ifInUcastPkts),
  42	STAT_DESC(ifInMulticastPkts),
  43	STAT_DESC(ifInBroadcastPkts),
  44	STAT_DESC(ifOutDiscards),
  45	STAT_DESC(ifOutUcastPkts),
  46	STAT_DESC(ifOutMulticastPkts),
  47	STAT_DESC(ifOutBroadcastPkts),
  48	STAT_DESC(etherStatsDropEvents),
  49	STAT_DESC(etherStatsOctets),
  50	STAT_DESC(etherStatsPkts),
  51	STAT_DESC(etherStatsUndersizePkts),
  52	STAT_DESC(etherStatsOversizePkts),
  53	STAT_DESC(etherStatsPkts64Octets),
  54	STAT_DESC(etherStatsPkts65to127Octets),
  55	STAT_DESC(etherStatsPkts128to255Octets),
  56	STAT_DESC(etherStatsPkts256to511Octets),
  57	STAT_DESC(etherStatsPkts1024to1518Octets),
  58	STAT_DESC(etherStatsPkts1519toXOctets),
  59	STAT_DESC(etherStatsJabbers),
  60	STAT_DESC(etherStatsFragments),
  61	STAT_DESC(VLANReceived),
  62	STAT_DESC(VLANTransmitted),
  63	STAT_DESC(aDeferred),
  64	STAT_DESC(aMultipleCollisions),
  65	STAT_DESC(aSingleCollisions),
  66	STAT_DESC(aLateCollisions),
  67	STAT_DESC(aExcessiveCollisions),
  68	STAT_DESC(aCarrierSenseErrors),
  69};
  70
  71static void a5psw_reg_writel(struct a5psw *a5psw, int offset, u32 value)
  72{
  73	writel(value, a5psw->base + offset);
  74}
  75
  76static u32 a5psw_reg_readl(struct a5psw *a5psw, int offset)
  77{
  78	return readl(a5psw->base + offset);
  79}
  80
  81static void a5psw_reg_rmw(struct a5psw *a5psw, int offset, u32 mask, u32 val)
  82{
  83	u32 reg;
  84
  85	spin_lock(&a5psw->reg_lock);
  86
  87	reg = a5psw_reg_readl(a5psw, offset);
  88	reg &= ~mask;
  89	reg |= val;
  90	a5psw_reg_writel(a5psw, offset, reg);
  91
  92	spin_unlock(&a5psw->reg_lock);
  93}
  94
  95static enum dsa_tag_protocol a5psw_get_tag_protocol(struct dsa_switch *ds,
  96						    int port,
  97						    enum dsa_tag_protocol mp)
  98{
  99	return DSA_TAG_PROTO_RZN1_A5PSW;
 100}
 101
 102static void a5psw_port_pattern_set(struct a5psw *a5psw, int port, int pattern,
 103				   bool enable)
 104{
 105	u32 rx_match = 0;
 106
 107	if (enable)
 108		rx_match |= A5PSW_RXMATCH_CONFIG_PATTERN(pattern);
 109
 110	a5psw_reg_rmw(a5psw, A5PSW_RXMATCH_CONFIG(port),
 111		      A5PSW_RXMATCH_CONFIG_PATTERN(pattern), rx_match);
 112}
 113
 114static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable)
 115{
 116	/* Enable "management forward" pattern matching, this will forward
 117	 * packets from this port only towards the management port and thus
 118	 * isolate the port.
 119	 */
 120	a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable);
 121}
 122
 123static void a5psw_port_tx_enable(struct a5psw *a5psw, int port, bool enable)
 124{
 125	u32 mask = A5PSW_PORT_ENA_TX(port);
 126	u32 reg = enable ? mask : 0;
 127
 128	/* Even though the port TX is disabled through TXENA bit in the
 129	 * PORT_ENA register, it can still send BPDUs. This depends on the tag
 130	 * configuration added when sending packets from the CPU port to the
 131	 * switch port. Indeed, when using forced forwarding without filtering,
 132	 * even disabled ports will be able to send packets that are tagged.
 133	 * This allows to implement STP support when ports are in a state where
 134	 * forwarding traffic should be stopped but BPDUs should still be sent.
 135	 */
 136	a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, mask, reg);
 137}
 138
 139static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable)
 140{
 141	u32 port_ena = 0;
 142
 143	if (enable)
 144		port_ena |= A5PSW_PORT_ENA_TX_RX(port);
 145
 146	a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, A5PSW_PORT_ENA_TX_RX(port),
 147		      port_ena);
 148}
 149
 150static int a5psw_lk_execute_ctrl(struct a5psw *a5psw, u32 *ctrl)
 151{
 152	int ret;
 153
 154	a5psw_reg_writel(a5psw, A5PSW_LK_ADDR_CTRL, *ctrl);
 155
 156	ret = readl_poll_timeout(a5psw->base + A5PSW_LK_ADDR_CTRL, *ctrl,
 157				 !(*ctrl & A5PSW_LK_ADDR_CTRL_BUSY),
 158				 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
 159	if (ret)
 160		dev_err(a5psw->dev, "LK_CTRL timeout waiting for BUSY bit\n");
 161
 162	return ret;
 163}
 164
 165static void a5psw_port_fdb_flush(struct a5psw *a5psw, int port)
 166{
 167	u32 ctrl = A5PSW_LK_ADDR_CTRL_DELETE_PORT | BIT(port);
 168
 169	mutex_lock(&a5psw->lk_lock);
 170	a5psw_lk_execute_ctrl(a5psw, &ctrl);
 171	mutex_unlock(&a5psw->lk_lock);
 172}
 173
 174static void a5psw_port_authorize_set(struct a5psw *a5psw, int port,
 175				     bool authorize)
 176{
 177	u32 reg = a5psw_reg_readl(a5psw, A5PSW_AUTH_PORT(port));
 178
 179	if (authorize)
 180		reg |= A5PSW_AUTH_PORT_AUTHORIZED;
 181	else
 182		reg &= ~A5PSW_AUTH_PORT_AUTHORIZED;
 183
 184	a5psw_reg_writel(a5psw, A5PSW_AUTH_PORT(port), reg);
 185}
 186
 187static void a5psw_port_disable(struct dsa_switch *ds, int port)
 188{
 189	struct a5psw *a5psw = ds->priv;
 190
 191	a5psw_port_authorize_set(a5psw, port, false);
 192	a5psw_port_enable_set(a5psw, port, false);
 193}
 194
 195static int a5psw_port_enable(struct dsa_switch *ds, int port,
 196			     struct phy_device *phy)
 197{
 198	struct a5psw *a5psw = ds->priv;
 199
 200	a5psw_port_authorize_set(a5psw, port, true);
 201	a5psw_port_enable_set(a5psw, port, true);
 202
 203	return 0;
 204}
 205
 206static int a5psw_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
 207{
 208	struct a5psw *a5psw = ds->priv;
 209
 210	new_mtu += ETH_HLEN + A5PSW_EXTRA_MTU_LEN + ETH_FCS_LEN;
 211	a5psw_reg_writel(a5psw, A5PSW_FRM_LENGTH(port), new_mtu);
 212
 213	return 0;
 214}
 215
 216static int a5psw_port_max_mtu(struct dsa_switch *ds, int port)
 217{
 218	return A5PSW_MAX_MTU;
 219}
 220
 221static void a5psw_phylink_get_caps(struct dsa_switch *ds, int port,
 222				   struct phylink_config *config)
 223{
 224	unsigned long *intf = config->supported_interfaces;
 225
 226	config->mac_capabilities = MAC_1000FD;
 227
 228	if (dsa_is_cpu_port(ds, port)) {
 229		/* GMII is used internally and GMAC2 is connected to the switch
 230		 * using 1000Mbps Full-Duplex mode only (cf ethernet manual)
 231		 */
 232		__set_bit(PHY_INTERFACE_MODE_GMII, intf);
 233	} else {
 234		config->mac_capabilities |= MAC_100 | MAC_10;
 235		phy_interface_set_rgmii(intf);
 236		__set_bit(PHY_INTERFACE_MODE_RMII, intf);
 237		__set_bit(PHY_INTERFACE_MODE_MII, intf);
 238	}
 239}
 240
 241static struct phylink_pcs *
 242a5psw_phylink_mac_select_pcs(struct phylink_config *config,
 243			     phy_interface_t interface)
 244{
 245	struct dsa_port *dp = dsa_phylink_to_port(config);
 246	struct a5psw *a5psw = dp->ds->priv;
 247
 248	if (dsa_port_is_cpu(dp))
 249		return NULL;
 250
 251	return a5psw->pcs[dp->index];
 252}
 253
 254static void a5psw_phylink_mac_config(struct phylink_config *config,
 255				     unsigned int mode,
 256				     const struct phylink_link_state *state)
 257{
 258}
 259
 260static void a5psw_phylink_mac_link_down(struct phylink_config *config,
 261					unsigned int mode,
 262					phy_interface_t interface)
 263{
 264	struct dsa_port *dp = dsa_phylink_to_port(config);
 265	struct a5psw *a5psw = dp->ds->priv;
 266	int port = dp->index;
 267	u32 cmd_cfg;
 268
 269	cmd_cfg = a5psw_reg_readl(a5psw, A5PSW_CMD_CFG(port));
 270	cmd_cfg &= ~(A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA);
 271	a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
 272}
 273
 274static void a5psw_phylink_mac_link_up(struct phylink_config *config,
 275				      struct phy_device *phydev,
 276				      unsigned int mode,
 277				      phy_interface_t interface,
 278				      int speed, int duplex, bool tx_pause,
 279				      bool rx_pause)
 280{
 281	u32 cmd_cfg = A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA |
 282		      A5PSW_CMD_CFG_TX_CRC_APPEND;
 283	struct dsa_port *dp = dsa_phylink_to_port(config);
 284	struct a5psw *a5psw = dp->ds->priv;
 285
 286	if (speed == SPEED_1000)
 287		cmd_cfg |= A5PSW_CMD_CFG_ETH_SPEED;
 288
 289	if (duplex == DUPLEX_HALF)
 290		cmd_cfg |= A5PSW_CMD_CFG_HD_ENA;
 291
 292	cmd_cfg |= A5PSW_CMD_CFG_CNTL_FRM_ENA;
 293
 294	if (!rx_pause)
 295		cmd_cfg &= ~A5PSW_CMD_CFG_PAUSE_IGNORE;
 296
 297	a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(dp->index), cmd_cfg);
 298}
 299
 300static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
 301{
 302	struct a5psw *a5psw = ds->priv;
 303	unsigned long rate;
 304	u64 max, tmp;
 305	u32 agetime;
 306
 307	rate = clk_get_rate(a5psw->clk);
 308	max = div64_ul(((u64)A5PSW_LK_AGETIME_MASK * A5PSW_TABLE_ENTRIES * 1024),
 309		       rate) * 1000;
 310	if (msecs > max)
 311		return -EINVAL;
 312
 313	tmp = div_u64(rate, MSEC_PER_SEC);
 314	agetime = div_u64(msecs * tmp, 1024 * A5PSW_TABLE_ENTRIES);
 315
 316	a5psw_reg_writel(a5psw, A5PSW_LK_AGETIME, agetime);
 317
 318	return 0;
 319}
 320
 321static void a5psw_port_learning_set(struct a5psw *a5psw, int port, bool learn)
 322{
 323	u32 mask = A5PSW_INPUT_LEARN_DIS(port);
 324	u32 reg = !learn ? mask : 0;
 325
 326	a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
 327}
 328
 329static void a5psw_port_rx_block_set(struct a5psw *a5psw, int port, bool block)
 330{
 331	u32 mask = A5PSW_INPUT_LEARN_BLOCK(port);
 332	u32 reg = block ? mask : 0;
 333
 334	a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
 335}
 336
 337static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
 338					  bool set)
 339{
 340	static const u8 offsets[] = {
 341		A5PSW_UCAST_DEF_MASK, A5PSW_BCAST_DEF_MASK, A5PSW_MCAST_DEF_MASK
 342	};
 343	int i;
 344
 345	for (i = 0; i < ARRAY_SIZE(offsets); i++)
 346		a5psw_reg_rmw(a5psw, offsets[i], BIT(port),
 347			      set ? BIT(port) : 0);
 348}
 349
 350static void a5psw_port_set_standalone(struct a5psw *a5psw, int port,
 351				      bool standalone)
 352{
 353	a5psw_port_learning_set(a5psw, port, !standalone);
 354	a5psw_flooding_set_resolution(a5psw, port, !standalone);
 355	a5psw_port_mgmtfwd_set(a5psw, port, standalone);
 356}
 357
 358static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
 359				  struct dsa_bridge bridge,
 360				  bool *tx_fwd_offload,
 361				  struct netlink_ext_ack *extack)
 362{
 363	struct a5psw *a5psw = ds->priv;
 364
 365	/* We only support 1 bridge device */
 366	if (a5psw->br_dev && bridge.dev != a5psw->br_dev) {
 367		NL_SET_ERR_MSG_MOD(extack,
 368				   "Forwarding offload supported for a single bridge");
 369		return -EOPNOTSUPP;
 370	}
 371
 372	a5psw->br_dev = bridge.dev;
 373	a5psw_port_set_standalone(a5psw, port, false);
 374
 375	a5psw->bridged_ports |= BIT(port);
 376
 377	return 0;
 378}
 379
 380static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
 381				    struct dsa_bridge bridge)
 382{
 383	struct a5psw *a5psw = ds->priv;
 384
 385	a5psw->bridged_ports &= ~BIT(port);
 386
 387	a5psw_port_set_standalone(a5psw, port, true);
 388
 389	/* No more ports bridged */
 390	if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT))
 391		a5psw->br_dev = NULL;
 392}
 393
 394static int a5psw_port_pre_bridge_flags(struct dsa_switch *ds, int port,
 395				       struct switchdev_brport_flags flags,
 396				       struct netlink_ext_ack *extack)
 397{
 398	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
 399			   BR_BCAST_FLOOD))
 400		return -EINVAL;
 401
 402	return 0;
 403}
 404
 405static int
 406a5psw_port_bridge_flags(struct dsa_switch *ds, int port,
 407			struct switchdev_brport_flags flags,
 408			struct netlink_ext_ack *extack)
 409{
 410	struct a5psw *a5psw = ds->priv;
 411	u32 val;
 412
 413	/* If a port is set as standalone, we do not want to be able to
 414	 * configure flooding nor learning which would result in joining the
 415	 * unique bridge. This can happen when a port leaves the bridge, in
 416	 * which case the DSA core will try to "clear" all flags for the
 417	 * standalone port (ie enable flooding, disable learning). In that case
 418	 * do not fail but do not apply the flags.
 419	 */
 420	if (!(a5psw->bridged_ports & BIT(port)))
 421		return 0;
 422
 423	if (flags.mask & BR_LEARNING) {
 424		val = flags.val & BR_LEARNING ? 0 : A5PSW_INPUT_LEARN_DIS(port);
 425		a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN,
 426			      A5PSW_INPUT_LEARN_DIS(port), val);
 427	}
 428
 429	if (flags.mask & BR_FLOOD) {
 430		val = flags.val & BR_FLOOD ? BIT(port) : 0;
 431		a5psw_reg_rmw(a5psw, A5PSW_UCAST_DEF_MASK, BIT(port), val);
 432	}
 433
 434	if (flags.mask & BR_MCAST_FLOOD) {
 435		val = flags.val & BR_MCAST_FLOOD ? BIT(port) : 0;
 436		a5psw_reg_rmw(a5psw, A5PSW_MCAST_DEF_MASK, BIT(port), val);
 437	}
 438
 439	if (flags.mask & BR_BCAST_FLOOD) {
 440		val = flags.val & BR_BCAST_FLOOD ? BIT(port) : 0;
 441		a5psw_reg_rmw(a5psw, A5PSW_BCAST_DEF_MASK, BIT(port), val);
 442	}
 443
 444	return 0;
 445}
 446
 447static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 448{
 449	bool learning_enabled, rx_enabled, tx_enabled;
 450	struct dsa_port *dp = dsa_to_port(ds, port);
 451	struct a5psw *a5psw = ds->priv;
 452
 453	switch (state) {
 454	case BR_STATE_DISABLED:
 455	case BR_STATE_BLOCKING:
 456	case BR_STATE_LISTENING:
 457		rx_enabled = false;
 458		tx_enabled = false;
 459		learning_enabled = false;
 460		break;
 461	case BR_STATE_LEARNING:
 462		rx_enabled = false;
 463		tx_enabled = false;
 464		learning_enabled = dp->learning;
 465		break;
 466	case BR_STATE_FORWARDING:
 467		rx_enabled = true;
 468		tx_enabled = true;
 469		learning_enabled = dp->learning;
 470		break;
 471	default:
 472		dev_err(ds->dev, "invalid STP state: %d\n", state);
 473		return;
 474	}
 475
 476	a5psw_port_learning_set(a5psw, port, learning_enabled);
 477	a5psw_port_rx_block_set(a5psw, port, !rx_enabled);
 478	a5psw_port_tx_enable(a5psw, port, tx_enabled);
 479}
 480
 481static void a5psw_port_fast_age(struct dsa_switch *ds, int port)
 482{
 483	struct a5psw *a5psw = ds->priv;
 484
 485	a5psw_port_fdb_flush(a5psw, port);
 486}
 487
 488static int a5psw_lk_execute_lookup(struct a5psw *a5psw, union lk_data *lk_data,
 489				   u16 *entry)
 490{
 491	u32 ctrl;
 492	int ret;
 493
 494	a5psw_reg_writel(a5psw, A5PSW_LK_DATA_LO, lk_data->lo);
 495	a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data->hi);
 496
 497	ctrl = A5PSW_LK_ADDR_CTRL_LOOKUP;
 498	ret = a5psw_lk_execute_ctrl(a5psw, &ctrl);
 499	if (ret)
 500		return ret;
 501
 502	*entry = ctrl & A5PSW_LK_ADDR_CTRL_ADDRESS;
 503
 504	return 0;
 505}
 506
 507static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
 508			      const unsigned char *addr, u16 vid,
 509			      struct dsa_db db)
 510{
 511	struct a5psw *a5psw = ds->priv;
 512	union lk_data lk_data = {0};
 513	bool inc_learncount = false;
 514	int ret = 0;
 515	u16 entry;
 516	u32 reg;
 517
 518	ether_addr_copy(lk_data.entry.mac, addr);
 519	lk_data.entry.port_mask = BIT(port);
 520
 521	mutex_lock(&a5psw->lk_lock);
 522
 523	/* Set the value to be written in the lookup table */
 524	ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
 525	if (ret)
 526		goto lk_unlock;
 527
 528	lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
 529	if (!lk_data.entry.valid) {
 530		inc_learncount = true;
 531		/* port_mask set to 0x1f when entry is not valid, clear it */
 532		lk_data.entry.port_mask = 0;
 533		lk_data.entry.prio = 0;
 534	}
 535
 536	lk_data.entry.port_mask |= BIT(port);
 537	lk_data.entry.is_static = 1;
 538	lk_data.entry.valid = 1;
 539
 540	a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
 541
 542	reg = A5PSW_LK_ADDR_CTRL_WRITE | entry;
 543	ret = a5psw_lk_execute_ctrl(a5psw, &reg);
 544	if (ret)
 545		goto lk_unlock;
 546
 547	if (inc_learncount) {
 548		reg = A5PSW_LK_LEARNCOUNT_MODE_INC;
 549		a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
 550	}
 551
 552lk_unlock:
 553	mutex_unlock(&a5psw->lk_lock);
 554
 555	return ret;
 556}
 557
 558static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
 559			      const unsigned char *addr, u16 vid,
 560			      struct dsa_db db)
 561{
 562	struct a5psw *a5psw = ds->priv;
 563	union lk_data lk_data = {0};
 564	bool clear = false;
 565	u16 entry;
 566	u32 reg;
 567	int ret;
 568
 569	ether_addr_copy(lk_data.entry.mac, addr);
 570
 571	mutex_lock(&a5psw->lk_lock);
 572
 573	ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
 574	if (ret)
 575		goto lk_unlock;
 576
 577	lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
 578
 579	/* Our hardware does not associate any VID to the FDB entries so this
 580	 * means that if two entries were added for the same mac but for
 581	 * different VID, then, on the deletion of the first one, we would also
 582	 * delete the second one. Since there is unfortunately nothing we can do
 583	 * about that, do not return an error...
 584	 */
 585	if (!lk_data.entry.valid)
 586		goto lk_unlock;
 587
 588	lk_data.entry.port_mask &= ~BIT(port);
 589	/* If there is no more port in the mask, clear the entry */
 590	if (lk_data.entry.port_mask == 0)
 591		clear = true;
 592
 593	a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
 594
 595	reg = entry;
 596	if (clear)
 597		reg |= A5PSW_LK_ADDR_CTRL_CLEAR;
 598	else
 599		reg |= A5PSW_LK_ADDR_CTRL_WRITE;
 600
 601	ret = a5psw_lk_execute_ctrl(a5psw, &reg);
 602	if (ret)
 603		goto lk_unlock;
 604
 605	/* Decrement LEARNCOUNT */
 606	if (clear) {
 607		reg = A5PSW_LK_LEARNCOUNT_MODE_DEC;
 608		a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
 609	}
 610
 611lk_unlock:
 612	mutex_unlock(&a5psw->lk_lock);
 613
 614	return ret;
 615}
 616
 617static int a5psw_port_fdb_dump(struct dsa_switch *ds, int port,
 618			       dsa_fdb_dump_cb_t *cb, void *data)
 619{
 620	struct a5psw *a5psw = ds->priv;
 621	union lk_data lk_data;
 622	int i = 0, ret = 0;
 623	u32 reg;
 624
 625	mutex_lock(&a5psw->lk_lock);
 626
 627	for (i = 0; i < A5PSW_TABLE_ENTRIES; i++) {
 628		reg = A5PSW_LK_ADDR_CTRL_READ | A5PSW_LK_ADDR_CTRL_WAIT | i;
 629
 630		ret = a5psw_lk_execute_ctrl(a5psw, &reg);
 631		if (ret)
 632			goto out_unlock;
 633
 634		lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
 635		/* If entry is not valid or does not contain the port, skip */
 636		if (!lk_data.entry.valid ||
 637		    !(lk_data.entry.port_mask & BIT(port)))
 638			continue;
 639
 640		lk_data.lo = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_LO);
 641
 642		ret = cb(lk_data.entry.mac, 0, lk_data.entry.is_static, data);
 643		if (ret)
 644			goto out_unlock;
 645	}
 646
 647out_unlock:
 648	mutex_unlock(&a5psw->lk_lock);
 649
 650	return ret;
 651}
 652
 653static int a5psw_port_vlan_filtering(struct dsa_switch *ds, int port,
 654				     bool vlan_filtering,
 655				     struct netlink_ext_ack *extack)
 656{
 657	u32 mask = BIT(port + A5PSW_VLAN_VERI_SHIFT) |
 658		   BIT(port + A5PSW_VLAN_DISC_SHIFT);
 659	u32 val = vlan_filtering ? mask : 0;
 660	struct a5psw *a5psw = ds->priv;
 661
 662	/* Disable/enable vlan tagging */
 663	a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE_ENA, BIT(port),
 664		      vlan_filtering ? BIT(port) : 0);
 665
 666	/* Disable/enable vlan input filtering */
 667	a5psw_reg_rmw(a5psw, A5PSW_VLAN_VERIFY, mask, val);
 668
 669	return 0;
 670}
 671
 672static int a5psw_find_vlan_entry(struct a5psw *a5psw, u16 vid)
 673{
 674	u32 vlan_res;
 675	int i;
 676
 677	/* Find vlan for this port */
 678	for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
 679		vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
 680		if (FIELD_GET(A5PSW_VLAN_RES_VLANID, vlan_res) == vid)
 681			return i;
 682	}
 683
 684	return -1;
 685}
 686
 687static int a5psw_new_vlan_res_entry(struct a5psw *a5psw, u16 newvid)
 688{
 689	u32 vlan_res;
 690	int i;
 691
 692	/* Find a free VLAN entry */
 693	for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
 694		vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
 695		if (!(FIELD_GET(A5PSW_VLAN_RES_PORTMASK, vlan_res))) {
 696			vlan_res = FIELD_PREP(A5PSW_VLAN_RES_VLANID, newvid);
 697			a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(i), vlan_res);
 698			return i;
 699		}
 700	}
 701
 702	return -1;
 703}
 704
 705static void a5psw_port_vlan_tagged_cfg(struct a5psw *a5psw,
 706				       unsigned int vlan_res_id, int port,
 707				       bool set)
 708{
 709	u32 mask = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_RD_TAGMASK |
 710		   BIT(port);
 711	u32 vlan_res_off = A5PSW_VLAN_RES(vlan_res_id);
 712	u32 val = A5PSW_VLAN_RES_WR_TAGMASK, reg;
 713
 714	if (set)
 715		val |= BIT(port);
 716
 717	/* Toggle tag mask read */
 718	a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
 719	reg = a5psw_reg_readl(a5psw, vlan_res_off);
 720	a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
 721
 722	reg &= ~mask;
 723	reg |= val;
 724	a5psw_reg_writel(a5psw, vlan_res_off, reg);
 725}
 726
 727static void a5psw_port_vlan_cfg(struct a5psw *a5psw, unsigned int vlan_res_id,
 728				int port, bool set)
 729{
 730	u32 mask = A5PSW_VLAN_RES_WR_TAGMASK | BIT(port);
 731	u32 reg = A5PSW_VLAN_RES_WR_PORTMASK;
 732
 733	if (set)
 734		reg |= BIT(port);
 735
 736	a5psw_reg_rmw(a5psw, A5PSW_VLAN_RES(vlan_res_id), mask, reg);
 737}
 738
 739static int a5psw_port_vlan_add(struct dsa_switch *ds, int port,
 740			       const struct switchdev_obj_port_vlan *vlan,
 741			       struct netlink_ext_ack *extack)
 742{
 743	bool tagged = !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
 744	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
 745	struct a5psw *a5psw = ds->priv;
 746	u16 vid = vlan->vid;
 747	int vlan_res_id;
 748
 749	vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
 750	if (vlan_res_id < 0) {
 751		vlan_res_id = a5psw_new_vlan_res_entry(a5psw, vid);
 752		if (vlan_res_id < 0)
 753			return -ENOSPC;
 754	}
 755
 756	a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, true);
 757	if (tagged)
 758		a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, true);
 759
 760	/* Configure port to tag with corresponding VID, but do not enable it
 761	 * yet: wait for vlan filtering to be enabled to enable vlan port
 762	 * tagging
 763	 */
 764	if (pvid)
 765		a5psw_reg_writel(a5psw, A5PSW_SYSTEM_TAGINFO(port), vid);
 766
 767	return 0;
 768}
 769
 770static int a5psw_port_vlan_del(struct dsa_switch *ds, int port,
 771			       const struct switchdev_obj_port_vlan *vlan)
 772{
 773	struct a5psw *a5psw = ds->priv;
 774	u16 vid = vlan->vid;
 775	int vlan_res_id;
 776
 777	vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
 778	if (vlan_res_id < 0)
 779		return -EINVAL;
 780
 781	a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, false);
 782	a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, false);
 783
 784	return 0;
 785}
 786
 787static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port)
 788{
 789	u32 reg_lo, reg_hi;
 790
 791	reg_lo = a5psw_reg_readl(a5psw, offset + A5PSW_PORT_OFFSET(port));
 792	/* A5PSW_STATS_HIWORD is latched on stat read */
 793	reg_hi = a5psw_reg_readl(a5psw, A5PSW_STATS_HIWORD);
 794
 795	return ((u64)reg_hi << 32) | reg_lo;
 796}
 797
 798static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset,
 799			      uint8_t *data)
 800{
 801	unsigned int u;
 802
 803	if (stringset != ETH_SS_STATS)
 804		return;
 805
 806	for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
 807		ethtool_puts(&data, a5psw_stats[u].name);
 808}
 809
 810static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port,
 811				    uint64_t *data)
 812{
 813	struct a5psw *a5psw = ds->priv;
 814	unsigned int u;
 815
 816	for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
 817		data[u] = a5psw_read_stat(a5psw, a5psw_stats[u].offset, port);
 818}
 819
 820static int a5psw_get_sset_count(struct dsa_switch *ds, int port, int sset)
 821{
 822	if (sset != ETH_SS_STATS)
 823		return 0;
 824
 825	return ARRAY_SIZE(a5psw_stats);
 826}
 827
 828static void a5psw_get_eth_mac_stats(struct dsa_switch *ds, int port,
 829				    struct ethtool_eth_mac_stats *mac_stats)
 830{
 831	struct a5psw *a5psw = ds->priv;
 832
 833#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
 834	mac_stats->FramesTransmittedOK = RD(aFramesTransmittedOK);
 835	mac_stats->SingleCollisionFrames = RD(aSingleCollisions);
 836	mac_stats->MultipleCollisionFrames = RD(aMultipleCollisions);
 837	mac_stats->FramesReceivedOK = RD(aFramesReceivedOK);
 838	mac_stats->FrameCheckSequenceErrors = RD(aFrameCheckSequenceErrors);
 839	mac_stats->AlignmentErrors = RD(aAlignmentErrors);
 840	mac_stats->OctetsTransmittedOK = RD(aOctetsTransmittedOK);
 841	mac_stats->FramesWithDeferredXmissions = RD(aDeferred);
 842	mac_stats->LateCollisions = RD(aLateCollisions);
 843	mac_stats->FramesAbortedDueToXSColls = RD(aExcessiveCollisions);
 844	mac_stats->FramesLostDueToIntMACXmitError = RD(ifOutErrors);
 845	mac_stats->CarrierSenseErrors = RD(aCarrierSenseErrors);
 846	mac_stats->OctetsReceivedOK = RD(aOctetsReceivedOK);
 847	mac_stats->FramesLostDueToIntMACRcvError = RD(ifInErrors);
 848	mac_stats->MulticastFramesXmittedOK = RD(ifOutMulticastPkts);
 849	mac_stats->BroadcastFramesXmittedOK = RD(ifOutBroadcastPkts);
 850	mac_stats->FramesWithExcessiveDeferral = RD(aDeferred);
 851	mac_stats->MulticastFramesReceivedOK = RD(ifInMulticastPkts);
 852	mac_stats->BroadcastFramesReceivedOK = RD(ifInBroadcastPkts);
 853#undef RD
 854}
 855
 856static const struct ethtool_rmon_hist_range a5psw_rmon_ranges[] = {
 857	{ 0, 64 },
 858	{ 65, 127 },
 859	{ 128, 255 },
 860	{ 256, 511 },
 861	{ 512, 1023 },
 862	{ 1024, 1518 },
 863	{ 1519, A5PSW_MAX_MTU },
 864	{}
 865};
 866
 867static void a5psw_get_rmon_stats(struct dsa_switch *ds, int port,
 868				 struct ethtool_rmon_stats *rmon_stats,
 869				 const struct ethtool_rmon_hist_range **ranges)
 870{
 871	struct a5psw *a5psw = ds->priv;
 872
 873#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
 874	rmon_stats->undersize_pkts = RD(etherStatsUndersizePkts);
 875	rmon_stats->oversize_pkts = RD(etherStatsOversizePkts);
 876	rmon_stats->fragments = RD(etherStatsFragments);
 877	rmon_stats->jabbers = RD(etherStatsJabbers);
 878	rmon_stats->hist[0] = RD(etherStatsPkts64Octets);
 879	rmon_stats->hist[1] = RD(etherStatsPkts65to127Octets);
 880	rmon_stats->hist[2] = RD(etherStatsPkts128to255Octets);
 881	rmon_stats->hist[3] = RD(etherStatsPkts256to511Octets);
 882	rmon_stats->hist[4] = RD(etherStatsPkts512to1023Octets);
 883	rmon_stats->hist[5] = RD(etherStatsPkts1024to1518Octets);
 884	rmon_stats->hist[6] = RD(etherStatsPkts1519toXOctets);
 885#undef RD
 886
 887	*ranges = a5psw_rmon_ranges;
 888}
 889
 890static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
 891				     struct ethtool_eth_ctrl_stats *ctrl_stats)
 892{
 893	struct a5psw *a5psw = ds->priv;
 894	u64 stat;
 895
 896	stat = a5psw_read_stat(a5psw, A5PSW_aTxPAUSEMACCtrlFrames, port);
 897	ctrl_stats->MACControlFramesTransmitted = stat;
 898	stat = a5psw_read_stat(a5psw, A5PSW_aRxPAUSEMACCtrlFrames, port);
 899	ctrl_stats->MACControlFramesReceived = stat;
 900}
 901
 902static void a5psw_vlan_setup(struct a5psw *a5psw, int port)
 903{
 904	u32 reg;
 905
 906	/* Enable TAG always mode for the port, this is actually controlled
 907	 * by VLAN_IN_MODE_ENA field which will be used for PVID insertion
 908	 */
 909	reg = A5PSW_VLAN_IN_MODE_TAG_ALWAYS;
 910	reg <<= A5PSW_VLAN_IN_MODE_PORT_SHIFT(port);
 911	a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE, A5PSW_VLAN_IN_MODE_PORT(port),
 912		      reg);
 913
 914	/* Set transparent mode for output frame manipulation, this will depend
 915	 * on the VLAN_RES configuration mode
 916	 */
 917	reg = A5PSW_VLAN_OUT_MODE_TRANSPARENT;
 918	reg <<= A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port);
 919	a5psw_reg_rmw(a5psw, A5PSW_VLAN_OUT_MODE,
 920		      A5PSW_VLAN_OUT_MODE_PORT(port), reg);
 921}
 922
 923static int a5psw_setup(struct dsa_switch *ds)
 924{
 925	struct a5psw *a5psw = ds->priv;
 926	int port, vlan, ret;
 927	struct dsa_port *dp;
 928	u32 reg;
 929
 930	/* Validate that there is only 1 CPU port with index A5PSW_CPU_PORT */
 931	dsa_switch_for_each_cpu_port(dp, ds) {
 932		if (dp->index != A5PSW_CPU_PORT) {
 933			dev_err(a5psw->dev, "Invalid CPU port\n");
 934			return -EINVAL;
 935		}
 936	}
 937
 938	/* Configure management port */
 939	reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_ENABLE;
 940	a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg);
 941
 942	/* Set pattern 0 to forward all frame to mgmt port */
 943	a5psw_reg_writel(a5psw, A5PSW_PATTERN_CTRL(A5PSW_PATTERN_MGMTFWD),
 944			 A5PSW_PATTERN_CTRL_MGMTFWD);
 945
 946	/* Enable port tagging */
 947	reg = FIELD_PREP(A5PSW_MGMT_TAG_CFG_TAGFIELD, ETH_P_DSA_A5PSW);
 948	reg |= A5PSW_MGMT_TAG_CFG_ENABLE | A5PSW_MGMT_TAG_CFG_ALL_FRAMES;
 949	a5psw_reg_writel(a5psw, A5PSW_MGMT_TAG_CFG, reg);
 950
 951	/* Enable normal switch operation */
 952	reg = A5PSW_LK_ADDR_CTRL_BLOCKING | A5PSW_LK_ADDR_CTRL_LEARNING |
 953	      A5PSW_LK_ADDR_CTRL_AGEING | A5PSW_LK_ADDR_CTRL_ALLOW_MIGR |
 954	      A5PSW_LK_ADDR_CTRL_CLEAR_TABLE;
 955	a5psw_reg_writel(a5psw, A5PSW_LK_CTRL, reg);
 956
 957	ret = readl_poll_timeout(a5psw->base + A5PSW_LK_CTRL, reg,
 958				 !(reg & A5PSW_LK_ADDR_CTRL_CLEAR_TABLE),
 959				 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
 960	if (ret) {
 961		dev_err(a5psw->dev, "Failed to clear lookup table\n");
 962		return ret;
 963	}
 964
 965	/* Reset learn count to 0 */
 966	reg = A5PSW_LK_LEARNCOUNT_MODE_SET;
 967	a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
 968
 969	/* Clear VLAN resource table */
 970	reg = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_WR_TAGMASK;
 971	for (vlan = 0; vlan < A5PSW_VLAN_COUNT; vlan++)
 972		a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(vlan), reg);
 973
 974	/* Reset all ports */
 975	dsa_switch_for_each_port(dp, ds) {
 976		port = dp->index;
 977
 978		/* Reset the port */
 979		a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port),
 980				 A5PSW_CMD_CFG_SW_RESET);
 981
 982		/* Enable only CPU port */
 983		a5psw_port_enable_set(a5psw, port, dsa_port_is_cpu(dp));
 984
 985		if (dsa_port_is_unused(dp))
 986			continue;
 987
 988		/* Enable egress flooding and learning for CPU port */
 989		if (dsa_port_is_cpu(dp)) {
 990			a5psw_flooding_set_resolution(a5psw, port, true);
 991			a5psw_port_learning_set(a5psw, port, true);
 992		}
 993
 994		/* Enable standalone mode for user ports */
 995		if (dsa_port_is_user(dp))
 996			a5psw_port_set_standalone(a5psw, port, true);
 997
 998		a5psw_vlan_setup(a5psw, port);
 999	}
1000
1001	return 0;
1002}
1003
1004static const struct phylink_mac_ops a5psw_phylink_mac_ops = {
1005	.mac_select_pcs = a5psw_phylink_mac_select_pcs,
1006	.mac_config = a5psw_phylink_mac_config,
1007	.mac_link_down = a5psw_phylink_mac_link_down,
1008	.mac_link_up = a5psw_phylink_mac_link_up,
1009};
1010
1011static const struct dsa_switch_ops a5psw_switch_ops = {
1012	.get_tag_protocol = a5psw_get_tag_protocol,
1013	.setup = a5psw_setup,
1014	.port_disable = a5psw_port_disable,
1015	.port_enable = a5psw_port_enable,
1016	.phylink_get_caps = a5psw_phylink_get_caps,
1017	.port_change_mtu = a5psw_port_change_mtu,
1018	.port_max_mtu = a5psw_port_max_mtu,
1019	.get_sset_count = a5psw_get_sset_count,
1020	.get_strings = a5psw_get_strings,
1021	.get_ethtool_stats = a5psw_get_ethtool_stats,
1022	.get_eth_mac_stats = a5psw_get_eth_mac_stats,
1023	.get_eth_ctrl_stats = a5psw_get_eth_ctrl_stats,
1024	.get_rmon_stats = a5psw_get_rmon_stats,
1025	.set_ageing_time = a5psw_set_ageing_time,
1026	.port_bridge_join = a5psw_port_bridge_join,
1027	.port_bridge_leave = a5psw_port_bridge_leave,
1028	.port_pre_bridge_flags = a5psw_port_pre_bridge_flags,
1029	.port_bridge_flags = a5psw_port_bridge_flags,
1030	.port_stp_state_set = a5psw_port_stp_state_set,
1031	.port_fast_age = a5psw_port_fast_age,
1032	.port_vlan_filtering = a5psw_port_vlan_filtering,
1033	.port_vlan_add = a5psw_port_vlan_add,
1034	.port_vlan_del = a5psw_port_vlan_del,
1035	.port_fdb_add = a5psw_port_fdb_add,
1036	.port_fdb_del = a5psw_port_fdb_del,
1037	.port_fdb_dump = a5psw_port_fdb_dump,
1038	.port_hsr_join = dsa_port_simple_hsr_join,
1039	.port_hsr_leave = dsa_port_simple_hsr_leave,
1040};
1041
1042static int a5psw_mdio_wait_busy(struct a5psw *a5psw)
1043{
1044	u32 status;
1045	int err;
1046
1047	err = readl_poll_timeout(a5psw->base + A5PSW_MDIO_CFG_STATUS, status,
1048				 !(status & A5PSW_MDIO_CFG_STATUS_BUSY), 10,
1049				 1000 * USEC_PER_MSEC);
1050	if (err)
1051		dev_err(a5psw->dev, "MDIO command timeout\n");
1052
1053	return err;
1054}
1055
1056static int a5psw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
1057{
1058	struct a5psw *a5psw = bus->priv;
1059	u32 cmd, status;
1060	int ret;
1061
1062	cmd = A5PSW_MDIO_COMMAND_READ;
1063	cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
1064	cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
1065
1066	a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
1067
1068	ret = a5psw_mdio_wait_busy(a5psw);
1069	if (ret)
1070		return ret;
1071
1072	ret = a5psw_reg_readl(a5psw, A5PSW_MDIO_DATA) & A5PSW_MDIO_DATA_MASK;
1073
1074	status = a5psw_reg_readl(a5psw, A5PSW_MDIO_CFG_STATUS);
1075	if (status & A5PSW_MDIO_CFG_STATUS_READERR)
1076		return -EIO;
1077
1078	return ret;
1079}
1080
1081static int a5psw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
1082			    u16 phy_data)
1083{
1084	struct a5psw *a5psw = bus->priv;
1085	u32 cmd;
1086
1087	cmd = FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
1088	cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
1089
1090	a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
1091	a5psw_reg_writel(a5psw, A5PSW_MDIO_DATA, phy_data);
1092
1093	return a5psw_mdio_wait_busy(a5psw);
1094}
1095
1096static int a5psw_mdio_config(struct a5psw *a5psw, u32 mdio_freq)
1097{
1098	unsigned long rate;
1099	unsigned long div;
1100	u32 cfgstatus;
1101
1102	rate = clk_get_rate(a5psw->hclk);
1103	div = ((rate / mdio_freq) / 2);
1104	if (div > FIELD_MAX(A5PSW_MDIO_CFG_STATUS_CLKDIV) ||
1105	    div < A5PSW_MDIO_CLK_DIV_MIN) {
1106		dev_err(a5psw->dev, "MDIO clock div %ld out of range\n", div);
1107		return -ERANGE;
1108	}
1109
1110	cfgstatus = FIELD_PREP(A5PSW_MDIO_CFG_STATUS_CLKDIV, div);
1111
1112	a5psw_reg_writel(a5psw, A5PSW_MDIO_CFG_STATUS, cfgstatus);
1113
1114	return 0;
1115}
1116
1117static int a5psw_probe_mdio(struct a5psw *a5psw, struct device_node *node)
1118{
1119	struct device *dev = a5psw->dev;
1120	struct mii_bus *bus;
1121	u32 mdio_freq;
1122	int ret;
1123
1124	if (of_property_read_u32(node, "clock-frequency", &mdio_freq))
1125		mdio_freq = A5PSW_MDIO_DEF_FREQ;
1126
1127	ret = a5psw_mdio_config(a5psw, mdio_freq);
1128	if (ret)
1129		return ret;
1130
1131	bus = devm_mdiobus_alloc(dev);
1132	if (!bus)
1133		return -ENOMEM;
1134
1135	bus->name = "a5psw_mdio";
1136	bus->read = a5psw_mdio_read;
1137	bus->write = a5psw_mdio_write;
1138	bus->priv = a5psw;
1139	bus->parent = dev;
1140	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
1141
1142	a5psw->mii_bus = bus;
1143
1144	return devm_of_mdiobus_register(dev, bus, node);
1145}
1146
1147static void a5psw_pcs_free(struct a5psw *a5psw)
1148{
1149	int i;
1150
1151	for (i = 0; i < ARRAY_SIZE(a5psw->pcs); i++) {
1152		if (a5psw->pcs[i])
1153			miic_destroy(a5psw->pcs[i]);
1154	}
1155}
1156
1157static int a5psw_pcs_get(struct a5psw *a5psw)
1158{
1159	struct device_node *ports, *port, *pcs_node;
1160	struct phylink_pcs *pcs;
1161	int ret;
1162	u32 reg;
1163
1164	ports = of_get_child_by_name(a5psw->dev->of_node, "ethernet-ports");
1165	if (!ports)
1166		return -EINVAL;
1167
1168	for_each_available_child_of_node(ports, port) {
1169		pcs_node = of_parse_phandle(port, "pcs-handle", 0);
1170		if (!pcs_node)
1171			continue;
1172
1173		if (of_property_read_u32(port, "reg", &reg)) {
1174			ret = -EINVAL;
1175			goto free_pcs;
1176		}
1177
1178		if (reg >= ARRAY_SIZE(a5psw->pcs)) {
1179			ret = -ENODEV;
1180			goto free_pcs;
1181		}
1182
1183		pcs = miic_create(a5psw->dev, pcs_node);
1184		if (IS_ERR(pcs)) {
1185			dev_err(a5psw->dev, "Failed to create PCS for port %d\n",
1186				reg);
1187			ret = PTR_ERR(pcs);
1188			goto free_pcs;
1189		}
1190
1191		a5psw->pcs[reg] = pcs;
1192		of_node_put(pcs_node);
1193	}
1194	of_node_put(ports);
1195
1196	return 0;
1197
1198free_pcs:
1199	of_node_put(pcs_node);
1200	of_node_put(port);
1201	of_node_put(ports);
1202	a5psw_pcs_free(a5psw);
1203
1204	return ret;
1205}
1206
1207static int a5psw_probe(struct platform_device *pdev)
1208{
1209	struct device *dev = &pdev->dev;
1210	struct device_node *mdio;
1211	struct dsa_switch *ds;
1212	struct a5psw *a5psw;
1213	int ret;
1214
1215	a5psw = devm_kzalloc(dev, sizeof(*a5psw), GFP_KERNEL);
1216	if (!a5psw)
1217		return -ENOMEM;
1218
1219	a5psw->dev = dev;
1220	mutex_init(&a5psw->lk_lock);
1221	spin_lock_init(&a5psw->reg_lock);
1222	a5psw->base = devm_platform_ioremap_resource(pdev, 0);
1223	if (IS_ERR(a5psw->base))
1224		return PTR_ERR(a5psw->base);
1225
1226	a5psw->bridged_ports = BIT(A5PSW_CPU_PORT);
1227
1228	ret = a5psw_pcs_get(a5psw);
1229	if (ret)
1230		return ret;
1231
1232	a5psw->hclk = devm_clk_get_enabled(dev, "hclk");
1233	if (IS_ERR(a5psw->hclk)) {
1234		dev_err(dev, "failed get hclk clock\n");
1235		ret = PTR_ERR(a5psw->hclk);
1236		goto free_pcs;
1237	}
1238
1239	a5psw->clk = devm_clk_get_enabled(dev, "clk");
1240	if (IS_ERR(a5psw->clk)) {
1241		dev_err(dev, "failed get clk_switch clock\n");
1242		ret = PTR_ERR(a5psw->clk);
1243		goto free_pcs;
1244	}
1245
1246	mdio = of_get_available_child_by_name(dev->of_node, "mdio");
1247	if (mdio) {
1248		ret = a5psw_probe_mdio(a5psw, mdio);
1249		of_node_put(mdio);
1250		if (ret) {
1251			dev_err(dev, "Failed to register MDIO: %d\n", ret);
1252			goto free_pcs;
1253		}
1254	}
1255
1256	ds = &a5psw->ds;
1257	ds->dev = dev;
1258	ds->num_ports = A5PSW_PORTS_NUM;
1259	ds->ops = &a5psw_switch_ops;
1260	ds->phylink_mac_ops = &a5psw_phylink_mac_ops;
1261	ds->priv = a5psw;
1262
1263	ret = dsa_register_switch(ds);
1264	if (ret) {
1265		dev_err(dev, "Failed to register DSA switch: %d\n", ret);
1266		goto free_pcs;
1267	}
1268
1269	return 0;
1270
1271free_pcs:
1272	a5psw_pcs_free(a5psw);
1273
1274	return ret;
1275}
1276
1277static void a5psw_remove(struct platform_device *pdev)
1278{
1279	struct a5psw *a5psw = platform_get_drvdata(pdev);
1280
1281	if (!a5psw)
1282		return;
1283
1284	dsa_unregister_switch(&a5psw->ds);
1285	a5psw_pcs_free(a5psw);
1286}
1287
1288static void a5psw_shutdown(struct platform_device *pdev)
1289{
1290	struct a5psw *a5psw = platform_get_drvdata(pdev);
1291
1292	if (!a5psw)
1293		return;
1294
1295	dsa_switch_shutdown(&a5psw->ds);
1296
1297	platform_set_drvdata(pdev, NULL);
1298}
1299
1300static const struct of_device_id a5psw_of_mtable[] = {
1301	{ .compatible = "renesas,rzn1-a5psw", },
1302	{ /* sentinel */ },
1303};
1304MODULE_DEVICE_TABLE(of, a5psw_of_mtable);
1305
1306static struct platform_driver a5psw_driver = {
1307	.driver = {
1308		.name	 = "rzn1_a5psw",
1309		.of_match_table = a5psw_of_mtable,
1310	},
1311	.probe = a5psw_probe,
1312	.remove = a5psw_remove,
1313	.shutdown = a5psw_shutdown,
1314};
1315module_platform_driver(a5psw_driver);
1316
1317MODULE_LICENSE("GPL");
1318MODULE_DESCRIPTION("Renesas RZ/N1 Advanced 5-port Switch driver");
1319MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");
~/ Read-only file preview.