162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci// Copyright (c) 2019 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci *                   +----------------------+
562306a36Sopenharmony_ci * GMAC1----RGMII----|--MAC0                |
662306a36Sopenharmony_ci *      \---MDIO1----|--REGs                |----MDIO3----\
762306a36Sopenharmony_ci *                   |                      |             |  +------+
862306a36Sopenharmony_ci *                   |                      |             +--|      |
962306a36Sopenharmony_ci *                   |                 MAC1-|----RMII--M-----| PHY0 |-o P0
1062306a36Sopenharmony_ci *                   |                      |          |  |  +------+
1162306a36Sopenharmony_ci *                   |                      |          |  +--|      |
1262306a36Sopenharmony_ci *                   |                 MAC2-|----RMII--------| PHY1 |-o P1
1362306a36Sopenharmony_ci *                   |                      |          |  |  +------+
1462306a36Sopenharmony_ci *                   |                      |          |  +--|      |
1562306a36Sopenharmony_ci *                   |                 MAC3-|----RMII--------| PHY2 |-o P2
1662306a36Sopenharmony_ci *                   |                      |          |  |  +------+
1762306a36Sopenharmony_ci *                   |                      |          |  +--|      |
1862306a36Sopenharmony_ci *                   |                 MAC4-|----RMII--------| PHY3 |-o P3
1962306a36Sopenharmony_ci *                   |                      |          |  |  +------+
2062306a36Sopenharmony_ci *                   |                      |          |  +--|      |
2162306a36Sopenharmony_ci *                   |                 MAC5-|--+-RMII--M-----|-PHY4-|-o P4
2262306a36Sopenharmony_ci *                   |                      |  |       |     +------+
2362306a36Sopenharmony_ci *                   +----------------------+  |       \--CFG_SW_PHY_SWAP
2462306a36Sopenharmony_ci * GMAC0---------------RMII--------------------/        \-CFG_SW_PHY_ADDR_SWAP
2562306a36Sopenharmony_ci *      \---MDIO0--NC
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * GMAC0 and MAC5 are connected together and use same PHY. Depending on
2862306a36Sopenharmony_ci * configuration it can be PHY4 (default) or PHY0. Only GMAC0 or MAC5 can be
2962306a36Sopenharmony_ci * used at same time. If GMAC0 is used (default) then MAC5 should be disabled.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * CFG_SW_PHY_SWAP - swap connections of PHY0 and PHY4. If this bit is not set
3262306a36Sopenharmony_ci * PHY4 is connected to GMAC0/MAC5 bundle and PHY0 is connected to MAC1. If this
3362306a36Sopenharmony_ci * bit is set, PHY4 is connected to MAC1 and PHY0 is connected to GMAC0/MAC5
3462306a36Sopenharmony_ci * bundle.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * CFG_SW_PHY_ADDR_SWAP - swap addresses of PHY0 and PHY4
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * CFG_SW_PHY_SWAP and CFG_SW_PHY_ADDR_SWAP are part of SoC specific register
3962306a36Sopenharmony_ci * set and not related to switch internal registers.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <linux/bitfield.h>
4362306a36Sopenharmony_ci#include <linux/module.h>
4462306a36Sopenharmony_ci#include <linux/of_irq.h>
4562306a36Sopenharmony_ci#include <linux/of_mdio.h>
4662306a36Sopenharmony_ci#include <linux/regmap.h>
4762306a36Sopenharmony_ci#include <linux/reset.h>
4862306a36Sopenharmony_ci#include <net/dsa.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define AR9331_SW_NAME				"ar9331_switch"
5162306a36Sopenharmony_ci#define AR9331_SW_PORTS				6
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* dummy reg to change page */
5462306a36Sopenharmony_ci#define AR9331_SW_REG_PAGE			0x40000
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Global Interrupt */
5762306a36Sopenharmony_ci#define AR9331_SW_REG_GINT			0x10
5862306a36Sopenharmony_ci#define AR9331_SW_REG_GINT_MASK			0x14
5962306a36Sopenharmony_ci#define AR9331_SW_GINT_PHY_INT			BIT(2)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define AR9331_SW_REG_FLOOD_MASK		0x2c
6262306a36Sopenharmony_ci#define AR9331_SW_FLOOD_MASK_BROAD_TO_CPU	BIT(26)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define AR9331_SW_REG_GLOBAL_CTRL		0x30
6562306a36Sopenharmony_ci#define AR9331_SW_GLOBAL_CTRL_MFS_M		GENMASK(13, 0)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define AR9331_SW_REG_MDIO_CTRL			0x98
6862306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_BUSY		BIT(31)
6962306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_MASTER_EN		BIT(30)
7062306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_CMD_READ		BIT(27)
7162306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_PHY_ADDR_M		GENMASK(25, 21)
7262306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_REG_ADDR_M		GENMASK(20, 16)
7362306a36Sopenharmony_ci#define AR9331_SW_MDIO_CTRL_DATA_M		GENMASK(16, 0)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define AR9331_SW_REG_PORT_STATUS(_port)	(0x100 + (_port) * 0x100)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* FLOW_LINK_EN - enable mac flow control config auto-neg with phy.
7862306a36Sopenharmony_ci * If not set, mac can be config by software.
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_FLOW_LINK_EN	BIT(12)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* LINK_EN - If set, MAC is configured from PHY link status.
8362306a36Sopenharmony_ci * If not set, MAC should be configured by software.
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_LINK_EN		BIT(9)
8662306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_DUPLEX_MODE	BIT(6)
8762306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_RX_FLOW_EN	BIT(5)
8862306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_TX_FLOW_EN	BIT(4)
8962306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_RXMAC		BIT(3)
9062306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_TXMAC		BIT(2)
9162306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_SPEED_M		GENMASK(1, 0)
9262306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_SPEED_1000	2
9362306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_SPEED_100		1
9462306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_SPEED_10		0
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_MAC_MASK \
9762306a36Sopenharmony_ci	(AR9331_SW_PORT_STATUS_TXMAC | AR9331_SW_PORT_STATUS_RXMAC)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define AR9331_SW_PORT_STATUS_LINK_MASK \
10062306a36Sopenharmony_ci	(AR9331_SW_PORT_STATUS_DUPLEX_MODE | \
10162306a36Sopenharmony_ci	 AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \
10262306a36Sopenharmony_ci	 AR9331_SW_PORT_STATUS_SPEED_M)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define AR9331_SW_REG_PORT_CTRL(_port)			(0x104 + (_port) * 0x100)
10562306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_HEAD_EN			BIT(11)
10662306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE			GENMASK(2, 0)
10762306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE_DISABLED		0
10862306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE_BLOCKING		1
10962306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE_LISTENING	2
11062306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE_LEARNING		3
11162306a36Sopenharmony_ci#define AR9331_SW_PORT_CTRL_PORT_STATE_FORWARD		4
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define AR9331_SW_REG_PORT_VLAN(_port)			(0x108 + (_port) * 0x100)
11462306a36Sopenharmony_ci#define AR9331_SW_PORT_VLAN_8021Q_MODE			GENMASK(31, 30)
11562306a36Sopenharmony_ci#define AR9331_SW_8021Q_MODE_SECURE			3
11662306a36Sopenharmony_ci#define AR9331_SW_8021Q_MODE_CHECK			2
11762306a36Sopenharmony_ci#define AR9331_SW_8021Q_MODE_FALLBACK			1
11862306a36Sopenharmony_ci#define AR9331_SW_8021Q_MODE_NONE			0
11962306a36Sopenharmony_ci#define AR9331_SW_PORT_VLAN_PORT_VID_MEMBER		GENMASK(25, 16)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* MIB registers */
12262306a36Sopenharmony_ci#define AR9331_MIB_COUNTER(x)			(0x20000 + ((x) * 0x100))
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* Phy bypass mode
12562306a36Sopenharmony_ci * ------------------------------------------------------------------------
12662306a36Sopenharmony_ci * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
12962306a36Sopenharmony_ci * atheros| start |   OP  | 2'b00 |PhyAdd[2:0]|  Reg Addr[4:0]    |  TA   |
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
13362306a36Sopenharmony_ci * real   |  Data                                                         |
13462306a36Sopenharmony_ci * atheros|  Data                                                         |
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * ------------------------------------------------------------------------
13762306a36Sopenharmony_ci * Page address mode
13862306a36Sopenharmony_ci * ------------------------------------------------------------------------
13962306a36Sopenharmony_ci * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
14062306a36Sopenharmony_ci * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
14162306a36Sopenharmony_ci * atheros| start |   OP  | 2'b11 |                          8'b0 |  TA   |
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
14462306a36Sopenharmony_ci * real   |  Data                                                         |
14562306a36Sopenharmony_ci * atheros|                       | Page [9:0]                            |
14662306a36Sopenharmony_ci */
14762306a36Sopenharmony_ci/* In case of Page Address mode, Bit[18:9] of 32 bit register address should be
14862306a36Sopenharmony_ci * written to bits[9:0] of mdio data register.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ci#define AR9331_SW_ADDR_PAGE			GENMASK(18, 9)
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* ------------------------------------------------------------------------
15362306a36Sopenharmony_ci * Normal register access mode
15462306a36Sopenharmony_ci * ------------------------------------------------------------------------
15562306a36Sopenharmony_ci * Bit:   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |
15662306a36Sopenharmony_ci * real   | start |   OP  | PhyAddr           |  Reg Addr         |  TA   |
15762306a36Sopenharmony_ci * atheros| start |   OP  | 2'b10 |  low_addr[7:0]                |  TA   |
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Bit:   |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 |
16062306a36Sopenharmony_ci * real   |  Data                                                         |
16162306a36Sopenharmony_ci * atheros|  Data                                                         |
16262306a36Sopenharmony_ci * ------------------------------------------------------------------------
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_ci#define AR9331_SW_LOW_ADDR_PHY			GENMASK(8, 6)
16562306a36Sopenharmony_ci#define AR9331_SW_LOW_ADDR_REG			GENMASK(5, 1)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define AR9331_SW_MDIO_PHY_MODE_M		GENMASK(4, 3)
16862306a36Sopenharmony_ci#define AR9331_SW_MDIO_PHY_MODE_PAGE		3
16962306a36Sopenharmony_ci#define AR9331_SW_MDIO_PHY_MODE_REG		2
17062306a36Sopenharmony_ci#define AR9331_SW_MDIO_PHY_MODE_BYPASS		0
17162306a36Sopenharmony_ci#define AR9331_SW_MDIO_PHY_ADDR_M		GENMASK(2, 0)
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Empirical determined values */
17462306a36Sopenharmony_ci#define AR9331_SW_MDIO_POLL_SLEEP_US		1
17562306a36Sopenharmony_ci#define AR9331_SW_MDIO_POLL_TIMEOUT_US		20
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* The interval should be small enough to avoid overflow of 32bit MIBs */
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * FIXME: until we can read MIBs from stats64 call directly (i.e. sleep
18062306a36Sopenharmony_ci * there), we have to poll stats more frequently then it is actually needed.
18162306a36Sopenharmony_ci * For overflow protection, normally, 100 sec interval should have been OK.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_ci#define STATS_INTERVAL_JIFFIES			(3 * HZ)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistruct ar9331_sw_stats_raw {
18662306a36Sopenharmony_ci	u32 rxbroad;			/* 0x00 */
18762306a36Sopenharmony_ci	u32 rxpause;			/* 0x04 */
18862306a36Sopenharmony_ci	u32 rxmulti;			/* 0x08 */
18962306a36Sopenharmony_ci	u32 rxfcserr;			/* 0x0c */
19062306a36Sopenharmony_ci	u32 rxalignerr;			/* 0x10 */
19162306a36Sopenharmony_ci	u32 rxrunt;			/* 0x14 */
19262306a36Sopenharmony_ci	u32 rxfragment;			/* 0x18 */
19362306a36Sopenharmony_ci	u32 rx64byte;			/* 0x1c */
19462306a36Sopenharmony_ci	u32 rx128byte;			/* 0x20 */
19562306a36Sopenharmony_ci	u32 rx256byte;			/* 0x24 */
19662306a36Sopenharmony_ci	u32 rx512byte;			/* 0x28 */
19762306a36Sopenharmony_ci	u32 rx1024byte;			/* 0x2c */
19862306a36Sopenharmony_ci	u32 rx1518byte;			/* 0x30 */
19962306a36Sopenharmony_ci	u32 rxmaxbyte;			/* 0x34 */
20062306a36Sopenharmony_ci	u32 rxtoolong;			/* 0x38 */
20162306a36Sopenharmony_ci	u32 rxgoodbyte;			/* 0x3c */
20262306a36Sopenharmony_ci	u32 rxgoodbyte_hi;
20362306a36Sopenharmony_ci	u32 rxbadbyte;			/* 0x44 */
20462306a36Sopenharmony_ci	u32 rxbadbyte_hi;
20562306a36Sopenharmony_ci	u32 rxoverflow;			/* 0x4c */
20662306a36Sopenharmony_ci	u32 filtered;			/* 0x50 */
20762306a36Sopenharmony_ci	u32 txbroad;			/* 0x54 */
20862306a36Sopenharmony_ci	u32 txpause;			/* 0x58 */
20962306a36Sopenharmony_ci	u32 txmulti;			/* 0x5c */
21062306a36Sopenharmony_ci	u32 txunderrun;			/* 0x60 */
21162306a36Sopenharmony_ci	u32 tx64byte;			/* 0x64 */
21262306a36Sopenharmony_ci	u32 tx128byte;			/* 0x68 */
21362306a36Sopenharmony_ci	u32 tx256byte;			/* 0x6c */
21462306a36Sopenharmony_ci	u32 tx512byte;			/* 0x70 */
21562306a36Sopenharmony_ci	u32 tx1024byte;			/* 0x74 */
21662306a36Sopenharmony_ci	u32 tx1518byte;			/* 0x78 */
21762306a36Sopenharmony_ci	u32 txmaxbyte;			/* 0x7c */
21862306a36Sopenharmony_ci	u32 txoversize;			/* 0x80 */
21962306a36Sopenharmony_ci	u32 txbyte;			/* 0x84 */
22062306a36Sopenharmony_ci	u32 txbyte_hi;
22162306a36Sopenharmony_ci	u32 txcollision;		/* 0x8c */
22262306a36Sopenharmony_ci	u32 txabortcol;			/* 0x90 */
22362306a36Sopenharmony_ci	u32 txmulticol;			/* 0x94 */
22462306a36Sopenharmony_ci	u32 txsinglecol;		/* 0x98 */
22562306a36Sopenharmony_ci	u32 txexcdefer;			/* 0x9c */
22662306a36Sopenharmony_ci	u32 txdefer;			/* 0xa0 */
22762306a36Sopenharmony_ci	u32 txlatecol;			/* 0xa4 */
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistruct ar9331_sw_port {
23162306a36Sopenharmony_ci	int idx;
23262306a36Sopenharmony_ci	struct delayed_work mib_read;
23362306a36Sopenharmony_ci	struct rtnl_link_stats64 stats;
23462306a36Sopenharmony_ci	struct ethtool_pause_stats pause_stats;
23562306a36Sopenharmony_ci	struct spinlock stats_lock;
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistruct ar9331_sw_priv {
23962306a36Sopenharmony_ci	struct device *dev;
24062306a36Sopenharmony_ci	struct dsa_switch ds;
24162306a36Sopenharmony_ci	struct dsa_switch_ops ops;
24262306a36Sopenharmony_ci	struct irq_domain *irqdomain;
24362306a36Sopenharmony_ci	u32 irq_mask;
24462306a36Sopenharmony_ci	struct mutex lock_irq;
24562306a36Sopenharmony_ci	struct mii_bus *mbus; /* mdio master */
24662306a36Sopenharmony_ci	struct mii_bus *sbus; /* mdio slave */
24762306a36Sopenharmony_ci	struct regmap *regmap;
24862306a36Sopenharmony_ci	struct reset_control *sw_reset;
24962306a36Sopenharmony_ci	struct ar9331_sw_port port[AR9331_SW_PORTS];
25062306a36Sopenharmony_ci};
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic struct ar9331_sw_priv *ar9331_sw_port_to_priv(struct ar9331_sw_port *port)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct ar9331_sw_port *p = port - port->idx;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return (struct ar9331_sw_priv *)((void *)p -
25762306a36Sopenharmony_ci					 offsetof(struct ar9331_sw_priv, port));
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/* Warning: switch reset will reset last AR9331_SW_MDIO_PHY_MODE_PAGE request
26162306a36Sopenharmony_ci * If some kind of optimization is used, the request should be repeated.
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_cistatic int ar9331_sw_reset(struct ar9331_sw_priv *priv)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	int ret;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	ret = reset_control_assert(priv->sw_reset);
26862306a36Sopenharmony_ci	if (ret)
26962306a36Sopenharmony_ci		goto error;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* AR9331 doc do not provide any information about proper reset
27262306a36Sopenharmony_ci	 * sequence. The AR8136 (the closes switch to the AR9331) doc says:
27362306a36Sopenharmony_ci	 * reset duration should be greater than 10ms. So, let's use this value
27462306a36Sopenharmony_ci	 * for now.
27562306a36Sopenharmony_ci	 */
27662306a36Sopenharmony_ci	usleep_range(10000, 15000);
27762306a36Sopenharmony_ci	ret = reset_control_deassert(priv->sw_reset);
27862306a36Sopenharmony_ci	if (ret)
27962306a36Sopenharmony_ci		goto error;
28062306a36Sopenharmony_ci	/* There is no information on how long should we wait after reset.
28162306a36Sopenharmony_ci	 * AR8136 has an EEPROM and there is an Interrupt for EEPROM load
28262306a36Sopenharmony_ci	 * status. AR9331 has no EEPROM support.
28362306a36Sopenharmony_ci	 * For now, do not wait. In case AR8136 will be needed, the after
28462306a36Sopenharmony_ci	 * reset delay can be added as well.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_cierror:
28962306a36Sopenharmony_ci	dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
29062306a36Sopenharmony_ci	return ret;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int ar9331_sw_mbus_write(struct mii_bus *mbus, int port, int regnum,
29462306a36Sopenharmony_ci				u16 data)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = mbus->priv;
29762306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
29862306a36Sopenharmony_ci	u32 val;
29962306a36Sopenharmony_ci	int ret;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_MDIO_CTRL,
30262306a36Sopenharmony_ci			   AR9331_SW_MDIO_CTRL_BUSY |
30362306a36Sopenharmony_ci			   AR9331_SW_MDIO_CTRL_MASTER_EN |
30462306a36Sopenharmony_ci			   FIELD_PREP(AR9331_SW_MDIO_CTRL_PHY_ADDR_M, port) |
30562306a36Sopenharmony_ci			   FIELD_PREP(AR9331_SW_MDIO_CTRL_REG_ADDR_M, regnum) |
30662306a36Sopenharmony_ci			   FIELD_PREP(AR9331_SW_MDIO_CTRL_DATA_M, data));
30762306a36Sopenharmony_ci	if (ret)
30862306a36Sopenharmony_ci		goto error;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(regmap, AR9331_SW_REG_MDIO_CTRL, val,
31162306a36Sopenharmony_ci				       !(val & AR9331_SW_MDIO_CTRL_BUSY),
31262306a36Sopenharmony_ci				       AR9331_SW_MDIO_POLL_SLEEP_US,
31362306a36Sopenharmony_ci				       AR9331_SW_MDIO_POLL_TIMEOUT_US);
31462306a36Sopenharmony_ci	if (ret)
31562306a36Sopenharmony_ci		goto error;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_cierror:
31962306a36Sopenharmony_ci	dev_err_ratelimited(priv->dev, "PHY write error: %i\n", ret);
32062306a36Sopenharmony_ci	return ret;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int ar9331_sw_mbus_read(struct mii_bus *mbus, int port, int regnum)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = mbus->priv;
32662306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
32762306a36Sopenharmony_ci	u32 val;
32862306a36Sopenharmony_ci	int ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_MDIO_CTRL,
33162306a36Sopenharmony_ci			   AR9331_SW_MDIO_CTRL_BUSY |
33262306a36Sopenharmony_ci			   AR9331_SW_MDIO_CTRL_MASTER_EN |
33362306a36Sopenharmony_ci			   AR9331_SW_MDIO_CTRL_CMD_READ |
33462306a36Sopenharmony_ci			   FIELD_PREP(AR9331_SW_MDIO_CTRL_PHY_ADDR_M, port) |
33562306a36Sopenharmony_ci			   FIELD_PREP(AR9331_SW_MDIO_CTRL_REG_ADDR_M, regnum));
33662306a36Sopenharmony_ci	if (ret)
33762306a36Sopenharmony_ci		goto error;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(regmap, AR9331_SW_REG_MDIO_CTRL, val,
34062306a36Sopenharmony_ci				       !(val & AR9331_SW_MDIO_CTRL_BUSY),
34162306a36Sopenharmony_ci				       AR9331_SW_MDIO_POLL_SLEEP_US,
34262306a36Sopenharmony_ci				       AR9331_SW_MDIO_POLL_TIMEOUT_US);
34362306a36Sopenharmony_ci	if (ret)
34462306a36Sopenharmony_ci		goto error;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	ret = regmap_read(regmap, AR9331_SW_REG_MDIO_CTRL, &val);
34762306a36Sopenharmony_ci	if (ret)
34862306a36Sopenharmony_ci		goto error;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return FIELD_GET(AR9331_SW_MDIO_CTRL_DATA_M, val);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cierror:
35362306a36Sopenharmony_ci	dev_err_ratelimited(priv->dev, "PHY read error: %i\n", ret);
35462306a36Sopenharmony_ci	return ret;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct device *dev = priv->dev;
36062306a36Sopenharmony_ci	struct mii_bus *mbus;
36162306a36Sopenharmony_ci	struct device_node *np, *mnp;
36262306a36Sopenharmony_ci	int ret;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	np = dev->of_node;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	mbus = devm_mdiobus_alloc(dev);
36762306a36Sopenharmony_ci	if (!mbus)
36862306a36Sopenharmony_ci		return -ENOMEM;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	mbus->name = np->full_name;
37162306a36Sopenharmony_ci	snprintf(mbus->id, MII_BUS_ID_SIZE, "%pOF", np);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	mbus->read = ar9331_sw_mbus_read;
37462306a36Sopenharmony_ci	mbus->write = ar9331_sw_mbus_write;
37562306a36Sopenharmony_ci	mbus->priv = priv;
37662306a36Sopenharmony_ci	mbus->parent = dev;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	mnp = of_get_child_by_name(np, "mdio");
37962306a36Sopenharmony_ci	if (!mnp)
38062306a36Sopenharmony_ci		return -ENODEV;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = devm_of_mdiobus_register(dev, mbus, mnp);
38362306a36Sopenharmony_ci	of_node_put(mnp);
38462306a36Sopenharmony_ci	if (ret)
38562306a36Sopenharmony_ci		return ret;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	priv->mbus = mbus;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int ar9331_sw_setup_port(struct dsa_switch *ds, int port)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
39562306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
39662306a36Sopenharmony_ci	u32 port_mask, port_ctrl, val;
39762306a36Sopenharmony_ci	int ret;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Generate default port settings */
40062306a36Sopenharmony_ci	port_ctrl = FIELD_PREP(AR9331_SW_PORT_CTRL_PORT_STATE,
40162306a36Sopenharmony_ci			       AR9331_SW_PORT_CTRL_PORT_STATE_FORWARD);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (dsa_is_cpu_port(ds, port)) {
40462306a36Sopenharmony_ci		/* CPU port should be allowed to communicate with all user
40562306a36Sopenharmony_ci		 * ports.
40662306a36Sopenharmony_ci		 */
40762306a36Sopenharmony_ci		port_mask = dsa_user_ports(ds);
40862306a36Sopenharmony_ci		/* Enable Atheros header on CPU port. This will allow us
40962306a36Sopenharmony_ci		 * communicate with each port separately
41062306a36Sopenharmony_ci		 */
41162306a36Sopenharmony_ci		port_ctrl |= AR9331_SW_PORT_CTRL_HEAD_EN;
41262306a36Sopenharmony_ci	} else if (dsa_is_user_port(ds, port)) {
41362306a36Sopenharmony_ci		/* User ports should communicate only with the CPU port.
41462306a36Sopenharmony_ci		 */
41562306a36Sopenharmony_ci		port_mask = BIT(dsa_upstream_port(ds, port));
41662306a36Sopenharmony_ci	} else {
41762306a36Sopenharmony_ci		/* Other ports do not need to communicate at all */
41862306a36Sopenharmony_ci		port_mask = 0;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	val = FIELD_PREP(AR9331_SW_PORT_VLAN_8021Q_MODE,
42262306a36Sopenharmony_ci			 AR9331_SW_8021Q_MODE_NONE) |
42362306a36Sopenharmony_ci		FIELD_PREP(AR9331_SW_PORT_VLAN_PORT_VID_MEMBER, port_mask);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_PORT_VLAN(port), val);
42662306a36Sopenharmony_ci	if (ret)
42762306a36Sopenharmony_ci		goto error;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_PORT_CTRL(port), port_ctrl);
43062306a36Sopenharmony_ci	if (ret)
43162306a36Sopenharmony_ci		goto error;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_cierror:
43562306a36Sopenharmony_ci	dev_err(priv->dev, "%s: error: %i\n", __func__, ret);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return ret;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int ar9331_sw_setup(struct dsa_switch *ds)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
44362306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
44462306a36Sopenharmony_ci	int ret, i;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ret = ar9331_sw_reset(priv);
44762306a36Sopenharmony_ci	if (ret)
44862306a36Sopenharmony_ci		return ret;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* Reset will set proper defaults. CPU - Port0 will be enabled and
45162306a36Sopenharmony_ci	 * configured. All other ports (ports 1 - 5) are disabled
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	ret = ar9331_sw_mbus_init(priv);
45462306a36Sopenharmony_ci	if (ret)
45562306a36Sopenharmony_ci		return ret;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/* Do not drop broadcast frames */
45862306a36Sopenharmony_ci	ret = regmap_write_bits(regmap, AR9331_SW_REG_FLOOD_MASK,
45962306a36Sopenharmony_ci				AR9331_SW_FLOOD_MASK_BROAD_TO_CPU,
46062306a36Sopenharmony_ci				AR9331_SW_FLOOD_MASK_BROAD_TO_CPU);
46162306a36Sopenharmony_ci	if (ret)
46262306a36Sopenharmony_ci		goto error;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Set max frame size to the maximum supported value */
46562306a36Sopenharmony_ci	ret = regmap_write_bits(regmap, AR9331_SW_REG_GLOBAL_CTRL,
46662306a36Sopenharmony_ci				AR9331_SW_GLOBAL_CTRL_MFS_M,
46762306a36Sopenharmony_ci				AR9331_SW_GLOBAL_CTRL_MFS_M);
46862306a36Sopenharmony_ci	if (ret)
46962306a36Sopenharmony_ci		goto error;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	for (i = 0; i < ds->num_ports; i++) {
47262306a36Sopenharmony_ci		ret = ar9331_sw_setup_port(ds, i);
47362306a36Sopenharmony_ci		if (ret)
47462306a36Sopenharmony_ci			goto error;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ds->configure_vlan_while_not_filtering = false;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return 0;
48062306a36Sopenharmony_cierror:
48162306a36Sopenharmony_ci	dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
48262306a36Sopenharmony_ci	return ret;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
48862306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
48962306a36Sopenharmony_ci	int ret;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_PORT_STATUS(port), 0);
49262306a36Sopenharmony_ci	if (ret)
49362306a36Sopenharmony_ci		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic enum dsa_tag_protocol ar9331_sw_get_tag_protocol(struct dsa_switch *ds,
49762306a36Sopenharmony_ci							int port,
49862306a36Sopenharmony_ci							enum dsa_tag_protocol m)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	return DSA_TAG_PROTO_AR9331;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic void ar9331_sw_phylink_get_caps(struct dsa_switch *ds, int port,
50462306a36Sopenharmony_ci				       struct phylink_config *config)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
50762306a36Sopenharmony_ci		MAC_10 | MAC_100;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	switch (port) {
51062306a36Sopenharmony_ci	case 0:
51162306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_GMII,
51262306a36Sopenharmony_ci			  config->supported_interfaces);
51362306a36Sopenharmony_ci		config->mac_capabilities |= MAC_1000;
51462306a36Sopenharmony_ci		break;
51562306a36Sopenharmony_ci	case 1:
51662306a36Sopenharmony_ci	case 2:
51762306a36Sopenharmony_ci	case 3:
51862306a36Sopenharmony_ci	case 4:
51962306a36Sopenharmony_ci	case 5:
52062306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
52162306a36Sopenharmony_ci			  config->supported_interfaces);
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void ar9331_sw_phylink_mac_config(struct dsa_switch *ds, int port,
52762306a36Sopenharmony_ci					 unsigned int mode,
52862306a36Sopenharmony_ci					 const struct phylink_link_state *state)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
53162306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
53262306a36Sopenharmony_ci	int ret;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
53562306a36Sopenharmony_ci				 AR9331_SW_PORT_STATUS_LINK_EN |
53662306a36Sopenharmony_ci				 AR9331_SW_PORT_STATUS_FLOW_LINK_EN, 0);
53762306a36Sopenharmony_ci	if (ret)
53862306a36Sopenharmony_ci		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port,
54262306a36Sopenharmony_ci					    unsigned int mode,
54362306a36Sopenharmony_ci					    phy_interface_t interface)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
54662306a36Sopenharmony_ci	struct ar9331_sw_port *p = &priv->port[port];
54762306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
54862306a36Sopenharmony_ci	int ret;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
55162306a36Sopenharmony_ci				 AR9331_SW_PORT_STATUS_MAC_MASK, 0);
55262306a36Sopenharmony_ci	if (ret)
55362306a36Sopenharmony_ci		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	cancel_delayed_work_sync(&p->mib_read);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port,
55962306a36Sopenharmony_ci					  unsigned int mode,
56062306a36Sopenharmony_ci					  phy_interface_t interface,
56162306a36Sopenharmony_ci					  struct phy_device *phydev,
56262306a36Sopenharmony_ci					  int speed, int duplex,
56362306a36Sopenharmony_ci					  bool tx_pause, bool rx_pause)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
56662306a36Sopenharmony_ci	struct ar9331_sw_port *p = &priv->port[port];
56762306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
56862306a36Sopenharmony_ci	u32 val;
56962306a36Sopenharmony_ci	int ret;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	schedule_delayed_work(&p->mib_read, 0);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	val = AR9331_SW_PORT_STATUS_MAC_MASK;
57462306a36Sopenharmony_ci	switch (speed) {
57562306a36Sopenharmony_ci	case SPEED_1000:
57662306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_SPEED_1000;
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci	case SPEED_100:
57962306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_SPEED_100;
58062306a36Sopenharmony_ci		break;
58162306a36Sopenharmony_ci	case SPEED_10:
58262306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_SPEED_10;
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci	default:
58562306a36Sopenharmony_ci		return;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (duplex)
58962306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_DUPLEX_MODE;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (tx_pause)
59262306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_TX_FLOW_EN;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (rx_pause)
59562306a36Sopenharmony_ci		val |= AR9331_SW_PORT_STATUS_RX_FLOW_EN;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port),
59862306a36Sopenharmony_ci				 AR9331_SW_PORT_STATUS_MAC_MASK |
59962306a36Sopenharmony_ci				 AR9331_SW_PORT_STATUS_LINK_MASK,
60062306a36Sopenharmony_ci				 val);
60162306a36Sopenharmony_ci	if (ret)
60262306a36Sopenharmony_ci		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void ar9331_read_stats(struct ar9331_sw_port *port)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ar9331_sw_port_to_priv(port);
60862306a36Sopenharmony_ci	struct ethtool_pause_stats *pstats = &port->pause_stats;
60962306a36Sopenharmony_ci	struct rtnl_link_stats64 *stats = &port->stats;
61062306a36Sopenharmony_ci	struct ar9331_sw_stats_raw raw;
61162306a36Sopenharmony_ci	int ret;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Do the slowest part first, to avoid needless locking for long time */
61462306a36Sopenharmony_ci	ret = regmap_bulk_read(priv->regmap, AR9331_MIB_COUNTER(port->idx),
61562306a36Sopenharmony_ci			       &raw, sizeof(raw) / sizeof(u32));
61662306a36Sopenharmony_ci	if (ret) {
61762306a36Sopenharmony_ci		dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
61862306a36Sopenharmony_ci		return;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	/* All MIB counters are cleared automatically on read */
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	spin_lock(&port->stats_lock);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	stats->rx_bytes += raw.rxgoodbyte;
62562306a36Sopenharmony_ci	stats->tx_bytes += raw.txbyte;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	stats->rx_packets += raw.rx64byte + raw.rx128byte + raw.rx256byte +
62862306a36Sopenharmony_ci		raw.rx512byte + raw.rx1024byte + raw.rx1518byte + raw.rxmaxbyte;
62962306a36Sopenharmony_ci	stats->tx_packets += raw.tx64byte + raw.tx128byte + raw.tx256byte +
63062306a36Sopenharmony_ci		raw.tx512byte + raw.tx1024byte + raw.tx1518byte + raw.txmaxbyte;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	stats->rx_length_errors += raw.rxrunt + raw.rxfragment + raw.rxtoolong;
63362306a36Sopenharmony_ci	stats->rx_crc_errors += raw.rxfcserr;
63462306a36Sopenharmony_ci	stats->rx_frame_errors += raw.rxalignerr;
63562306a36Sopenharmony_ci	stats->rx_missed_errors += raw.rxoverflow;
63662306a36Sopenharmony_ci	stats->rx_dropped += raw.filtered;
63762306a36Sopenharmony_ci	stats->rx_errors += raw.rxfcserr + raw.rxalignerr + raw.rxrunt +
63862306a36Sopenharmony_ci		raw.rxfragment + raw.rxoverflow + raw.rxtoolong;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	stats->tx_window_errors += raw.txlatecol;
64162306a36Sopenharmony_ci	stats->tx_fifo_errors += raw.txunderrun;
64262306a36Sopenharmony_ci	stats->tx_aborted_errors += raw.txabortcol;
64362306a36Sopenharmony_ci	stats->tx_errors += raw.txoversize + raw.txabortcol + raw.txunderrun +
64462306a36Sopenharmony_ci		raw.txlatecol;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	stats->multicast += raw.rxmulti;
64762306a36Sopenharmony_ci	stats->collisions += raw.txcollision;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	pstats->tx_pause_frames += raw.txpause;
65062306a36Sopenharmony_ci	pstats->rx_pause_frames += raw.rxpause;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	spin_unlock(&port->stats_lock);
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic void ar9331_do_stats_poll(struct work_struct *work)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	struct ar9331_sw_port *port = container_of(work, struct ar9331_sw_port,
65862306a36Sopenharmony_ci						   mib_read.work);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	ar9331_read_stats(port);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	schedule_delayed_work(&port->mib_read, STATS_INTERVAL_JIFFIES);
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic void ar9331_get_stats64(struct dsa_switch *ds, int port,
66662306a36Sopenharmony_ci			       struct rtnl_link_stats64 *s)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
66962306a36Sopenharmony_ci	struct ar9331_sw_port *p = &priv->port[port];
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	spin_lock(&p->stats_lock);
67262306a36Sopenharmony_ci	memcpy(s, &p->stats, sizeof(*s));
67362306a36Sopenharmony_ci	spin_unlock(&p->stats_lock);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic void ar9331_get_pause_stats(struct dsa_switch *ds, int port,
67762306a36Sopenharmony_ci				   struct ethtool_pause_stats *pause_stats)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ds->priv;
68062306a36Sopenharmony_ci	struct ar9331_sw_port *p = &priv->port[port];
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	spin_lock(&p->stats_lock);
68362306a36Sopenharmony_ci	memcpy(pause_stats, &p->pause_stats, sizeof(*pause_stats));
68462306a36Sopenharmony_ci	spin_unlock(&p->stats_lock);
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic const struct dsa_switch_ops ar9331_sw_ops = {
68862306a36Sopenharmony_ci	.get_tag_protocol	= ar9331_sw_get_tag_protocol,
68962306a36Sopenharmony_ci	.setup			= ar9331_sw_setup,
69062306a36Sopenharmony_ci	.port_disable		= ar9331_sw_port_disable,
69162306a36Sopenharmony_ci	.phylink_get_caps	= ar9331_sw_phylink_get_caps,
69262306a36Sopenharmony_ci	.phylink_mac_config	= ar9331_sw_phylink_mac_config,
69362306a36Sopenharmony_ci	.phylink_mac_link_down	= ar9331_sw_phylink_mac_link_down,
69462306a36Sopenharmony_ci	.phylink_mac_link_up	= ar9331_sw_phylink_mac_link_up,
69562306a36Sopenharmony_ci	.get_stats64		= ar9331_get_stats64,
69662306a36Sopenharmony_ci	.get_pause_stats	= ar9331_get_pause_stats,
69762306a36Sopenharmony_ci};
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic irqreturn_t ar9331_sw_irq(int irq, void *data)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = data;
70262306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
70362306a36Sopenharmony_ci	u32 stat;
70462306a36Sopenharmony_ci	int ret;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	ret = regmap_read(regmap, AR9331_SW_REG_GINT, &stat);
70762306a36Sopenharmony_ci	if (ret) {
70862306a36Sopenharmony_ci		dev_err(priv->dev, "can't read interrupt status\n");
70962306a36Sopenharmony_ci		return IRQ_NONE;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (!stat)
71362306a36Sopenharmony_ci		return IRQ_NONE;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (stat & AR9331_SW_GINT_PHY_INT) {
71662306a36Sopenharmony_ci		int child_irq;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		child_irq = irq_find_mapping(priv->irqdomain, 0);
71962306a36Sopenharmony_ci		handle_nested_irq(child_irq);
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	ret = regmap_write(regmap, AR9331_SW_REG_GINT, stat);
72362306a36Sopenharmony_ci	if (ret) {
72462306a36Sopenharmony_ci		dev_err(priv->dev, "can't write interrupt status\n");
72562306a36Sopenharmony_ci		return IRQ_NONE;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return IRQ_HANDLED;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void ar9331_sw_mask_irq(struct irq_data *d)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	priv->irq_mask = 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic void ar9331_sw_unmask_irq(struct irq_data *d)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	priv->irq_mask = AR9331_SW_GINT_PHY_INT;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic void ar9331_sw_irq_bus_lock(struct irq_data *d)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	mutex_lock(&priv->lock_irq);
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic void ar9331_sw_irq_bus_sync_unlock(struct irq_data *d)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = irq_data_get_irq_chip_data(d);
75562306a36Sopenharmony_ci	struct regmap *regmap = priv->regmap;
75662306a36Sopenharmony_ci	int ret;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	ret = regmap_update_bits(regmap, AR9331_SW_REG_GINT_MASK,
75962306a36Sopenharmony_ci				 AR9331_SW_GINT_PHY_INT, priv->irq_mask);
76062306a36Sopenharmony_ci	if (ret)
76162306a36Sopenharmony_ci		dev_err(priv->dev, "failed to change IRQ mask\n");
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	mutex_unlock(&priv->lock_irq);
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic struct irq_chip ar9331_sw_irq_chip = {
76762306a36Sopenharmony_ci	.name = AR9331_SW_NAME,
76862306a36Sopenharmony_ci	.irq_mask = ar9331_sw_mask_irq,
76962306a36Sopenharmony_ci	.irq_unmask = ar9331_sw_unmask_irq,
77062306a36Sopenharmony_ci	.irq_bus_lock = ar9331_sw_irq_bus_lock,
77162306a36Sopenharmony_ci	.irq_bus_sync_unlock = ar9331_sw_irq_bus_sync_unlock,
77262306a36Sopenharmony_ci};
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int ar9331_sw_irq_map(struct irq_domain *domain, unsigned int irq,
77562306a36Sopenharmony_ci			     irq_hw_number_t hwirq)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	irq_set_chip_data(irq, domain->host_data);
77862306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, &ar9331_sw_irq_chip, handle_simple_irq);
77962306a36Sopenharmony_ci	irq_set_nested_thread(irq, 1);
78062306a36Sopenharmony_ci	irq_set_noprobe(irq);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return 0;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic void ar9331_sw_irq_unmap(struct irq_domain *d, unsigned int irq)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	irq_set_nested_thread(irq, 0);
78862306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, NULL, NULL);
78962306a36Sopenharmony_ci	irq_set_chip_data(irq, NULL);
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic const struct irq_domain_ops ar9331_sw_irqdomain_ops = {
79362306a36Sopenharmony_ci	.map = ar9331_sw_irq_map,
79462306a36Sopenharmony_ci	.unmap = ar9331_sw_irq_unmap,
79562306a36Sopenharmony_ci	.xlate = irq_domain_xlate_onecell,
79662306a36Sopenharmony_ci};
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int ar9331_sw_irq_init(struct ar9331_sw_priv *priv)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct device_node *np = priv->dev->of_node;
80162306a36Sopenharmony_ci	struct device *dev = priv->dev;
80262306a36Sopenharmony_ci	int ret, irq;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	irq = of_irq_get(np, 0);
80562306a36Sopenharmony_ci	if (irq <= 0) {
80662306a36Sopenharmony_ci		dev_err(dev, "failed to get parent IRQ\n");
80762306a36Sopenharmony_ci		return irq ? irq : -EINVAL;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	mutex_init(&priv->lock_irq);
81162306a36Sopenharmony_ci	ret = devm_request_threaded_irq(dev, irq, NULL, ar9331_sw_irq,
81262306a36Sopenharmony_ci					IRQF_ONESHOT, AR9331_SW_NAME, priv);
81362306a36Sopenharmony_ci	if (ret) {
81462306a36Sopenharmony_ci		dev_err(dev, "unable to request irq: %d\n", ret);
81562306a36Sopenharmony_ci		return ret;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	priv->irqdomain = irq_domain_add_linear(np, 1, &ar9331_sw_irqdomain_ops,
81962306a36Sopenharmony_ci						priv);
82062306a36Sopenharmony_ci	if (!priv->irqdomain) {
82162306a36Sopenharmony_ci		dev_err(dev, "failed to create IRQ domain\n");
82262306a36Sopenharmony_ci		return -EINVAL;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	irq_set_parent(irq_create_mapping(priv->irqdomain, 0), irq);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return 0;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int __ar9331_mdio_write(struct mii_bus *sbus, u8 mode, u16 reg, u16 val)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	u8 r, p;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	p = FIELD_PREP(AR9331_SW_MDIO_PHY_MODE_M, mode) |
83562306a36Sopenharmony_ci		FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
83662306a36Sopenharmony_ci	r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return __mdiobus_write(sbus, p, r, val);
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic int __ar9331_mdio_read(struct mii_bus *sbus, u16 reg)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	u8 r, p;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	p = FIELD_PREP(AR9331_SW_MDIO_PHY_MODE_M, AR9331_SW_MDIO_PHY_MODE_REG) |
84662306a36Sopenharmony_ci		FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
84762306a36Sopenharmony_ci	r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	return __mdiobus_read(sbus, p, r);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic int ar9331_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
85362306a36Sopenharmony_ci			    void *val_buf, size_t val_len)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = ctx;
85662306a36Sopenharmony_ci	struct mii_bus *sbus = priv->sbus;
85762306a36Sopenharmony_ci	u32 reg = *(u32 *)reg_buf;
85862306a36Sopenharmony_ci	int ret;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (reg == AR9331_SW_REG_PAGE) {
86162306a36Sopenharmony_ci		/* We cannot read the page selector register from hardware and
86262306a36Sopenharmony_ci		 * we cache its value in regmap. Return all bits set here,
86362306a36Sopenharmony_ci		 * that regmap will always write the page on first use.
86462306a36Sopenharmony_ci		 */
86562306a36Sopenharmony_ci		*(u32 *)val_buf = GENMASK(9, 0);
86662306a36Sopenharmony_ci		return 0;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	mutex_lock_nested(&sbus->mdio_lock, MDIO_MUTEX_NESTED);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	ret = __ar9331_mdio_read(sbus, reg);
87262306a36Sopenharmony_ci	if (ret < 0)
87362306a36Sopenharmony_ci		goto error;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	*(u32 *)val_buf = ret;
87662306a36Sopenharmony_ci	ret = __ar9331_mdio_read(sbus, reg + 2);
87762306a36Sopenharmony_ci	if (ret < 0)
87862306a36Sopenharmony_ci		goto error;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	*(u32 *)val_buf |= ret << 16;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	mutex_unlock(&sbus->mdio_lock);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	return 0;
88562306a36Sopenharmony_cierror:
88662306a36Sopenharmony_ci	mutex_unlock(&sbus->mdio_lock);
88762306a36Sopenharmony_ci	dev_err_ratelimited(&sbus->dev, "Bus error. Failed to read register.\n");
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return ret;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic int ar9331_mdio_write(void *ctx, u32 reg, u32 val)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ctx;
89562306a36Sopenharmony_ci	struct mii_bus *sbus = priv->sbus;
89662306a36Sopenharmony_ci	int ret;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	mutex_lock_nested(&sbus->mdio_lock, MDIO_MUTEX_NESTED);
89962306a36Sopenharmony_ci	if (reg == AR9331_SW_REG_PAGE) {
90062306a36Sopenharmony_ci		ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_PAGE,
90162306a36Sopenharmony_ci					  0, val);
90262306a36Sopenharmony_ci		if (ret < 0)
90362306a36Sopenharmony_ci			goto error;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		mutex_unlock(&sbus->mdio_lock);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		return 0;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* In case of this switch we work with 32bit registers on top of 16bit
91162306a36Sopenharmony_ci	 * bus. Some registers (for example access to forwarding database) have
91262306a36Sopenharmony_ci	 * trigger bit on the first 16bit half of request, the result and
91362306a36Sopenharmony_ci	 * configuration of request in the second half.
91462306a36Sopenharmony_ci	 * To make it work properly, we should do the second part of transfer
91562306a36Sopenharmony_ci	 * before the first one is done.
91662306a36Sopenharmony_ci	 */
91762306a36Sopenharmony_ci	ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_REG, reg + 2,
91862306a36Sopenharmony_ci				  val >> 16);
91962306a36Sopenharmony_ci	if (ret < 0)
92062306a36Sopenharmony_ci		goto error;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_REG, reg, val);
92362306a36Sopenharmony_ci	if (ret < 0)
92462306a36Sopenharmony_ci		goto error;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	mutex_unlock(&sbus->mdio_lock);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return 0;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cierror:
93162306a36Sopenharmony_ci	mutex_unlock(&sbus->mdio_lock);
93262306a36Sopenharmony_ci	dev_err_ratelimited(&sbus->dev, "Bus error. Failed to write register.\n");
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	return ret;
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic int ar9331_sw_bus_write(void *context, const void *data, size_t count)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	u32 reg = *(u32 *)data;
94062306a36Sopenharmony_ci	u32 val = *((u32 *)data + 1);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return ar9331_mdio_write(context, reg, val);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic const struct regmap_range ar9331_valid_regs[] = {
94662306a36Sopenharmony_ci	regmap_reg_range(0x0, 0x0),
94762306a36Sopenharmony_ci	regmap_reg_range(0x10, 0x14),
94862306a36Sopenharmony_ci	regmap_reg_range(0x20, 0x24),
94962306a36Sopenharmony_ci	regmap_reg_range(0x2c, 0x30),
95062306a36Sopenharmony_ci	regmap_reg_range(0x40, 0x44),
95162306a36Sopenharmony_ci	regmap_reg_range(0x50, 0x78),
95262306a36Sopenharmony_ci	regmap_reg_range(0x80, 0x98),
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	regmap_reg_range(0x100, 0x120),
95562306a36Sopenharmony_ci	regmap_reg_range(0x200, 0x220),
95662306a36Sopenharmony_ci	regmap_reg_range(0x300, 0x320),
95762306a36Sopenharmony_ci	regmap_reg_range(0x400, 0x420),
95862306a36Sopenharmony_ci	regmap_reg_range(0x500, 0x520),
95962306a36Sopenharmony_ci	regmap_reg_range(0x600, 0x620),
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	regmap_reg_range(0x20000, 0x200a4),
96262306a36Sopenharmony_ci	regmap_reg_range(0x20100, 0x201a4),
96362306a36Sopenharmony_ci	regmap_reg_range(0x20200, 0x202a4),
96462306a36Sopenharmony_ci	regmap_reg_range(0x20300, 0x203a4),
96562306a36Sopenharmony_ci	regmap_reg_range(0x20400, 0x204a4),
96662306a36Sopenharmony_ci	regmap_reg_range(0x20500, 0x205a4),
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* dummy page selector reg */
96962306a36Sopenharmony_ci	regmap_reg_range(AR9331_SW_REG_PAGE, AR9331_SW_REG_PAGE),
97062306a36Sopenharmony_ci};
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic const struct regmap_range ar9331_nonvolatile_regs[] = {
97362306a36Sopenharmony_ci	regmap_reg_range(AR9331_SW_REG_PAGE, AR9331_SW_REG_PAGE),
97462306a36Sopenharmony_ci};
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic const struct regmap_range_cfg ar9331_regmap_range[] = {
97762306a36Sopenharmony_ci	{
97862306a36Sopenharmony_ci		.selector_reg = AR9331_SW_REG_PAGE,
97962306a36Sopenharmony_ci		.selector_mask = GENMASK(9, 0),
98062306a36Sopenharmony_ci		.selector_shift = 0,
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		.window_start = 0,
98362306a36Sopenharmony_ci		.window_len = 512,
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		.range_min = 0,
98662306a36Sopenharmony_ci		.range_max = AR9331_SW_REG_PAGE - 4,
98762306a36Sopenharmony_ci	},
98862306a36Sopenharmony_ci};
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic const struct regmap_access_table ar9331_register_set = {
99162306a36Sopenharmony_ci	.yes_ranges = ar9331_valid_regs,
99262306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(ar9331_valid_regs),
99362306a36Sopenharmony_ci};
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic const struct regmap_access_table ar9331_volatile_set = {
99662306a36Sopenharmony_ci	.no_ranges = ar9331_nonvolatile_regs,
99762306a36Sopenharmony_ci	.n_no_ranges = ARRAY_SIZE(ar9331_nonvolatile_regs),
99862306a36Sopenharmony_ci};
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic const struct regmap_config ar9331_mdio_regmap_config = {
100162306a36Sopenharmony_ci	.reg_bits = 32,
100262306a36Sopenharmony_ci	.val_bits = 32,
100362306a36Sopenharmony_ci	.reg_stride = 4,
100462306a36Sopenharmony_ci	.max_register = AR9331_SW_REG_PAGE,
100562306a36Sopenharmony_ci	.use_single_read = true,
100662306a36Sopenharmony_ci	.use_single_write = true,
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	.ranges = ar9331_regmap_range,
100962306a36Sopenharmony_ci	.num_ranges = ARRAY_SIZE(ar9331_regmap_range),
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	.volatile_table = &ar9331_volatile_set,
101262306a36Sopenharmony_ci	.wr_table = &ar9331_register_set,
101362306a36Sopenharmony_ci	.rd_table = &ar9331_register_set,
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	.cache_type = REGCACHE_MAPLE,
101662306a36Sopenharmony_ci};
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic struct regmap_bus ar9331_sw_bus = {
101962306a36Sopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
102062306a36Sopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
102162306a36Sopenharmony_ci	.read = ar9331_mdio_read,
102262306a36Sopenharmony_ci	.write = ar9331_sw_bus_write,
102362306a36Sopenharmony_ci};
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic int ar9331_sw_probe(struct mdio_device *mdiodev)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct ar9331_sw_priv *priv;
102862306a36Sopenharmony_ci	struct dsa_switch *ds;
102962306a36Sopenharmony_ci	int ret, i;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
103262306a36Sopenharmony_ci	if (!priv)
103362306a36Sopenharmony_ci		return -ENOMEM;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	priv->regmap = devm_regmap_init(&mdiodev->dev, &ar9331_sw_bus, priv,
103662306a36Sopenharmony_ci					&ar9331_mdio_regmap_config);
103762306a36Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
103862306a36Sopenharmony_ci		ret = PTR_ERR(priv->regmap);
103962306a36Sopenharmony_ci		dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret);
104062306a36Sopenharmony_ci		return ret;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	priv->sw_reset = devm_reset_control_get(&mdiodev->dev, "switch");
104462306a36Sopenharmony_ci	if (IS_ERR(priv->sw_reset)) {
104562306a36Sopenharmony_ci		dev_err(&mdiodev->dev, "missing switch reset\n");
104662306a36Sopenharmony_ci		return PTR_ERR(priv->sw_reset);
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	priv->sbus = mdiodev->bus;
105062306a36Sopenharmony_ci	priv->dev = &mdiodev->dev;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	ret = ar9331_sw_irq_init(priv);
105362306a36Sopenharmony_ci	if (ret)
105462306a36Sopenharmony_ci		return ret;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	ds = &priv->ds;
105762306a36Sopenharmony_ci	ds->dev = &mdiodev->dev;
105862306a36Sopenharmony_ci	ds->num_ports = AR9331_SW_PORTS;
105962306a36Sopenharmony_ci	ds->priv = priv;
106062306a36Sopenharmony_ci	priv->ops = ar9331_sw_ops;
106162306a36Sopenharmony_ci	ds->ops = &priv->ops;
106262306a36Sopenharmony_ci	dev_set_drvdata(&mdiodev->dev, priv);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->port); i++) {
106562306a36Sopenharmony_ci		struct ar9331_sw_port *port = &priv->port[i];
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		port->idx = i;
106862306a36Sopenharmony_ci		spin_lock_init(&port->stats_lock);
106962306a36Sopenharmony_ci		INIT_DELAYED_WORK(&port->mib_read, ar9331_do_stats_poll);
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	ret = dsa_register_switch(ds);
107362306a36Sopenharmony_ci	if (ret)
107462306a36Sopenharmony_ci		goto err_remove_irq;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cierr_remove_irq:
107962306a36Sopenharmony_ci	irq_domain_remove(priv->irqdomain);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return ret;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void ar9331_sw_remove(struct mdio_device *mdiodev)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev);
108762306a36Sopenharmony_ci	unsigned int i;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!priv)
109062306a36Sopenharmony_ci		return;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->port); i++) {
109362306a36Sopenharmony_ci		struct ar9331_sw_port *port = &priv->port[i];
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		cancel_delayed_work_sync(&port->mib_read);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	irq_domain_remove(priv->irqdomain);
109962306a36Sopenharmony_ci	dsa_unregister_switch(&priv->ds);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	reset_control_assert(priv->sw_reset);
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistatic void ar9331_sw_shutdown(struct mdio_device *mdiodev)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	if (!priv)
110962306a36Sopenharmony_ci		return;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	dsa_switch_shutdown(&priv->ds);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	dev_set_drvdata(&mdiodev->dev, NULL);
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic const struct of_device_id ar9331_sw_of_match[] = {
111762306a36Sopenharmony_ci	{ .compatible = "qca,ar9331-switch" },
111862306a36Sopenharmony_ci	{ },
111962306a36Sopenharmony_ci};
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistatic struct mdio_driver ar9331_sw_mdio_driver = {
112262306a36Sopenharmony_ci	.probe = ar9331_sw_probe,
112362306a36Sopenharmony_ci	.remove = ar9331_sw_remove,
112462306a36Sopenharmony_ci	.shutdown = ar9331_sw_shutdown,
112562306a36Sopenharmony_ci	.mdiodrv.driver = {
112662306a36Sopenharmony_ci		.name = AR9331_SW_NAME,
112762306a36Sopenharmony_ci		.of_match_table = ar9331_sw_of_match,
112862306a36Sopenharmony_ci	},
112962306a36Sopenharmony_ci};
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cimdio_module_driver(ar9331_sw_mdio_driver);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ciMODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
113462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Atheros AR9331 switch");
113562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1136