162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sni_ave.c - Socionext UniPhier AVE ethernet driver
462306a36Sopenharmony_ci * Copyright 2014 Panasonic Corporation
562306a36Sopenharmony_ci * Copyright 2015-2017 Socionext Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitops.h>
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/etherdevice.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1562306a36Sopenharmony_ci#include <linux/mii.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/netdevice.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/of_net.h>
2062306a36Sopenharmony_ci#include <linux/of_mdio.h>
2162306a36Sopenharmony_ci#include <linux/phy.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/regmap.h>
2462306a36Sopenharmony_ci#include <linux/reset.h>
2562306a36Sopenharmony_ci#include <linux/types.h>
2662306a36Sopenharmony_ci#include <linux/u64_stats_sync.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* General Register Group */
2962306a36Sopenharmony_ci#define AVE_IDR			0x000	/* ID */
3062306a36Sopenharmony_ci#define AVE_VR			0x004	/* Version */
3162306a36Sopenharmony_ci#define AVE_GRR			0x008	/* Global Reset */
3262306a36Sopenharmony_ci#define AVE_CFGR		0x00c	/* Configuration */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Interrupt Register Group */
3562306a36Sopenharmony_ci#define AVE_GIMR		0x100	/* Global Interrupt Mask */
3662306a36Sopenharmony_ci#define AVE_GISR		0x104	/* Global Interrupt Status */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* MAC Register Group */
3962306a36Sopenharmony_ci#define AVE_TXCR		0x200	/* TX Setup */
4062306a36Sopenharmony_ci#define AVE_RXCR		0x204	/* RX Setup */
4162306a36Sopenharmony_ci#define AVE_RXMAC1R		0x208	/* MAC address (lower) */
4262306a36Sopenharmony_ci#define AVE_RXMAC2R		0x20c	/* MAC address (upper) */
4362306a36Sopenharmony_ci#define AVE_MDIOCTR		0x214	/* MDIO Control */
4462306a36Sopenharmony_ci#define AVE_MDIOAR		0x218	/* MDIO Address */
4562306a36Sopenharmony_ci#define AVE_MDIOWDR		0x21c	/* MDIO Data */
4662306a36Sopenharmony_ci#define AVE_MDIOSR		0x220	/* MDIO Status */
4762306a36Sopenharmony_ci#define AVE_MDIORDR		0x224	/* MDIO Rd Data */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* Descriptor Control Register Group */
5062306a36Sopenharmony_ci#define AVE_DESCC		0x300	/* Descriptor Control */
5162306a36Sopenharmony_ci#define AVE_TXDC		0x304	/* TX Descriptor Configuration */
5262306a36Sopenharmony_ci#define AVE_RXDC0		0x308	/* RX Descriptor Ring0 Configuration */
5362306a36Sopenharmony_ci#define AVE_IIRQC		0x34c	/* Interval IRQ Control */
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Packet Filter Register Group */
5662306a36Sopenharmony_ci#define AVE_PKTF_BASE		0x800	/* PF Base Address */
5762306a36Sopenharmony_ci#define AVE_PFMBYTE_BASE	0xd00	/* PF Mask Byte Base Address */
5862306a36Sopenharmony_ci#define AVE_PFMBIT_BASE		0xe00	/* PF Mask Bit Base Address */
5962306a36Sopenharmony_ci#define AVE_PFSEL_BASE		0xf00	/* PF Selector Base Address */
6062306a36Sopenharmony_ci#define AVE_PFEN		0xffc	/* Packet Filter Enable */
6162306a36Sopenharmony_ci#define AVE_PKTF(ent)		(AVE_PKTF_BASE + (ent) * 0x40)
6262306a36Sopenharmony_ci#define AVE_PFMBYTE(ent)	(AVE_PFMBYTE_BASE + (ent) * 8)
6362306a36Sopenharmony_ci#define AVE_PFMBIT(ent)		(AVE_PFMBIT_BASE + (ent) * 4)
6462306a36Sopenharmony_ci#define AVE_PFSEL(ent)		(AVE_PFSEL_BASE + (ent) * 4)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* 64bit descriptor memory */
6762306a36Sopenharmony_ci#define AVE_DESC_SIZE_64	12	/* Descriptor Size */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define AVE_TXDM_64		0x1000	/* Tx Descriptor Memory */
7062306a36Sopenharmony_ci#define AVE_RXDM_64		0x1c00	/* Rx Descriptor Memory */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define AVE_TXDM_SIZE_64	0x0ba0	/* Tx Descriptor Memory Size 3KB */
7362306a36Sopenharmony_ci#define AVE_RXDM_SIZE_64	0x6000	/* Rx Descriptor Memory Size 24KB */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* 32bit descriptor memory */
7662306a36Sopenharmony_ci#define AVE_DESC_SIZE_32	8	/* Descriptor Size */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define AVE_TXDM_32		0x1000	/* Tx Descriptor Memory */
7962306a36Sopenharmony_ci#define AVE_RXDM_32		0x1800	/* Rx Descriptor Memory */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define AVE_TXDM_SIZE_32	0x07c0	/* Tx Descriptor Memory Size 2KB */
8262306a36Sopenharmony_ci#define AVE_RXDM_SIZE_32	0x4000	/* Rx Descriptor Memory Size 16KB */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* RMII Bridge Register Group */
8562306a36Sopenharmony_ci#define AVE_RSTCTRL		0x8028	/* Reset control */
8662306a36Sopenharmony_ci#define AVE_RSTCTRL_RMIIRST	BIT(16)
8762306a36Sopenharmony_ci#define AVE_LINKSEL		0x8034	/* Link speed setting */
8862306a36Sopenharmony_ci#define AVE_LINKSEL_100M	BIT(0)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* AVE_GRR */
9162306a36Sopenharmony_ci#define AVE_GRR_RXFFR		BIT(5)	/* Reset RxFIFO */
9262306a36Sopenharmony_ci#define AVE_GRR_PHYRST		BIT(4)	/* Reset external PHY */
9362306a36Sopenharmony_ci#define AVE_GRR_GRST		BIT(0)	/* Reset all MAC */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* AVE_CFGR */
9662306a36Sopenharmony_ci#define AVE_CFGR_FLE		BIT(31)	/* Filter Function */
9762306a36Sopenharmony_ci#define AVE_CFGR_CHE		BIT(30)	/* Checksum Function */
9862306a36Sopenharmony_ci#define AVE_CFGR_MII		BIT(27)	/* Func mode (1:MII/RMII, 0:RGMII) */
9962306a36Sopenharmony_ci#define AVE_CFGR_IPFCEN		BIT(24)	/* IP fragment sum Enable */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* AVE_GISR (common with GIMR) */
10262306a36Sopenharmony_ci#define AVE_GI_PHY		BIT(24)	/* PHY interrupt */
10362306a36Sopenharmony_ci#define AVE_GI_TX		BIT(16)	/* Tx complete */
10462306a36Sopenharmony_ci#define AVE_GI_RXERR		BIT(8)	/* Receive frame more than max size */
10562306a36Sopenharmony_ci#define AVE_GI_RXOVF		BIT(7)	/* Overflow at the RxFIFO */
10662306a36Sopenharmony_ci#define AVE_GI_RXDROP		BIT(6)	/* Drop packet */
10762306a36Sopenharmony_ci#define AVE_GI_RXIINT		BIT(5)	/* Interval interrupt */
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* AVE_TXCR */
11062306a36Sopenharmony_ci#define AVE_TXCR_FLOCTR		BIT(18)	/* Flow control */
11162306a36Sopenharmony_ci#define AVE_TXCR_TXSPD_1G	BIT(17)
11262306a36Sopenharmony_ci#define AVE_TXCR_TXSPD_100	BIT(16)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* AVE_RXCR */
11562306a36Sopenharmony_ci#define AVE_RXCR_RXEN		BIT(30)	/* Rx enable */
11662306a36Sopenharmony_ci#define AVE_RXCR_FDUPEN		BIT(22)	/* Interface mode */
11762306a36Sopenharmony_ci#define AVE_RXCR_FLOCTR		BIT(21)	/* Flow control */
11862306a36Sopenharmony_ci#define AVE_RXCR_AFEN		BIT(19)	/* MAC address filter */
11962306a36Sopenharmony_ci#define AVE_RXCR_DRPEN		BIT(18)	/* Drop pause frame */
12062306a36Sopenharmony_ci#define AVE_RXCR_MPSIZ_MASK	GENMASK(10, 0)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* AVE_MDIOCTR */
12362306a36Sopenharmony_ci#define AVE_MDIOCTR_RREQ	BIT(3)	/* Read request */
12462306a36Sopenharmony_ci#define AVE_MDIOCTR_WREQ	BIT(2)	/* Write request */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* AVE_MDIOSR */
12762306a36Sopenharmony_ci#define AVE_MDIOSR_STS		BIT(0)	/* access status */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* AVE_DESCC */
13062306a36Sopenharmony_ci#define AVE_DESCC_STATUS_MASK	GENMASK(31, 16)
13162306a36Sopenharmony_ci#define AVE_DESCC_RD0		BIT(8)	/* Enable Rx descriptor Ring0 */
13262306a36Sopenharmony_ci#define AVE_DESCC_RDSTP		BIT(4)	/* Pause Rx descriptor */
13362306a36Sopenharmony_ci#define AVE_DESCC_TD		BIT(0)	/* Enable Tx descriptor */
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* AVE_TXDC */
13662306a36Sopenharmony_ci#define AVE_TXDC_SIZE		GENMASK(27, 16)	/* Size of Tx descriptor */
13762306a36Sopenharmony_ci#define AVE_TXDC_ADDR		GENMASK(11, 0)	/* Start address */
13862306a36Sopenharmony_ci#define AVE_TXDC_ADDR_START	0
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* AVE_RXDC0 */
14162306a36Sopenharmony_ci#define AVE_RXDC0_SIZE		GENMASK(30, 16)	/* Size of Rx descriptor */
14262306a36Sopenharmony_ci#define AVE_RXDC0_ADDR		GENMASK(14, 0)	/* Start address */
14362306a36Sopenharmony_ci#define AVE_RXDC0_ADDR_START	0
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* AVE_IIRQC */
14662306a36Sopenharmony_ci#define AVE_IIRQC_EN0		BIT(27)	/* Enable interval interrupt Ring0 */
14762306a36Sopenharmony_ci#define AVE_IIRQC_BSCK		GENMASK(15, 0)	/* Interval count unit */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* Command status for descriptor */
15062306a36Sopenharmony_ci#define AVE_STS_OWN		BIT(31)	/* Descriptor ownership */
15162306a36Sopenharmony_ci#define AVE_STS_INTR		BIT(29)	/* Request for interrupt */
15262306a36Sopenharmony_ci#define AVE_STS_OK		BIT(27)	/* Normal transmit */
15362306a36Sopenharmony_ci/* TX */
15462306a36Sopenharmony_ci#define AVE_STS_NOCSUM		BIT(28)	/* No use HW checksum */
15562306a36Sopenharmony_ci#define AVE_STS_1ST		BIT(26)	/* Head of buffer chain */
15662306a36Sopenharmony_ci#define AVE_STS_LAST		BIT(25)	/* Tail of buffer chain */
15762306a36Sopenharmony_ci#define AVE_STS_OWC		BIT(21)	/* Out of window,Late Collision */
15862306a36Sopenharmony_ci#define AVE_STS_EC		BIT(20)	/* Excess collision occurred */
15962306a36Sopenharmony_ci#define AVE_STS_PKTLEN_TX_MASK	GENMASK(15, 0)
16062306a36Sopenharmony_ci/* RX */
16162306a36Sopenharmony_ci#define AVE_STS_CSSV		BIT(21)	/* Checksum check performed */
16262306a36Sopenharmony_ci#define AVE_STS_CSER		BIT(20)	/* Checksum error detected */
16362306a36Sopenharmony_ci#define AVE_STS_PKTLEN_RX_MASK	GENMASK(10, 0)
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* Packet filter */
16662306a36Sopenharmony_ci#define AVE_PFMBYTE_MASK0	(GENMASK(31, 8) | GENMASK(5, 0))
16762306a36Sopenharmony_ci#define AVE_PFMBYTE_MASK1	GENMASK(25, 0)
16862306a36Sopenharmony_ci#define AVE_PFMBIT_MASK		GENMASK(15, 0)
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define AVE_PF_SIZE		17	/* Number of all packet filter */
17162306a36Sopenharmony_ci#define AVE_PF_MULTICAST_SIZE	7	/* Number of multicast filter */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define AVE_PFNUM_FILTER	0	/* No.0 */
17462306a36Sopenharmony_ci#define AVE_PFNUM_UNICAST	1	/* No.1 */
17562306a36Sopenharmony_ci#define AVE_PFNUM_BROADCAST	2	/* No.2 */
17662306a36Sopenharmony_ci#define AVE_PFNUM_MULTICAST	11	/* No.11-17 */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* NETIF Message control */
17962306a36Sopenharmony_ci#define AVE_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV    |	\
18062306a36Sopenharmony_ci				 NETIF_MSG_PROBE  |	\
18162306a36Sopenharmony_ci				 NETIF_MSG_LINK   |	\
18262306a36Sopenharmony_ci				 NETIF_MSG_TIMER  |	\
18362306a36Sopenharmony_ci				 NETIF_MSG_IFDOWN |	\
18462306a36Sopenharmony_ci				 NETIF_MSG_IFUP   |	\
18562306a36Sopenharmony_ci				 NETIF_MSG_RX_ERR |	\
18662306a36Sopenharmony_ci				 NETIF_MSG_TX_ERR)
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* Parameter for descriptor */
18962306a36Sopenharmony_ci#define AVE_NR_TXDESC		64	/* Tx descriptor */
19062306a36Sopenharmony_ci#define AVE_NR_RXDESC		256	/* Rx descriptor */
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#define AVE_DESC_OFS_CMDSTS	0
19362306a36Sopenharmony_ci#define AVE_DESC_OFS_ADDRL	4
19462306a36Sopenharmony_ci#define AVE_DESC_OFS_ADDRU	8
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* Parameter for ethernet frame */
19762306a36Sopenharmony_ci#define AVE_MAX_ETHFRAME	1518
19862306a36Sopenharmony_ci#define AVE_FRAME_HEADROOM	2
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci/* Parameter for interrupt */
20162306a36Sopenharmony_ci#define AVE_INTM_COUNT		20
20262306a36Sopenharmony_ci#define AVE_FORCE_TXINTCNT	1
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* SG */
20562306a36Sopenharmony_ci#define SG_ETPINMODE		0x540
20662306a36Sopenharmony_ci#define SG_ETPINMODE_EXTPHY	BIT(1)	/* for LD11 */
20762306a36Sopenharmony_ci#define SG_ETPINMODE_RMII(ins)	BIT(ins)
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define IS_DESC_64BIT(p)	((p)->data->is_desc_64bit)
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci#define AVE_MAX_CLKS		4
21262306a36Sopenharmony_ci#define AVE_MAX_RSTS		2
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cienum desc_id {
21562306a36Sopenharmony_ci	AVE_DESCID_RX,
21662306a36Sopenharmony_ci	AVE_DESCID_TX,
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cienum desc_state {
22062306a36Sopenharmony_ci	AVE_DESC_RX_PERMIT,
22162306a36Sopenharmony_ci	AVE_DESC_RX_SUSPEND,
22262306a36Sopenharmony_ci	AVE_DESC_START,
22362306a36Sopenharmony_ci	AVE_DESC_STOP,
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct ave_desc {
22762306a36Sopenharmony_ci	struct sk_buff	*skbs;
22862306a36Sopenharmony_ci	dma_addr_t	skbs_dma;
22962306a36Sopenharmony_ci	size_t		skbs_dmalen;
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistruct ave_desc_info {
23362306a36Sopenharmony_ci	u32	ndesc;		/* number of descriptor */
23462306a36Sopenharmony_ci	u32	daddr;		/* start address of descriptor */
23562306a36Sopenharmony_ci	u32	proc_idx;	/* index of processing packet */
23662306a36Sopenharmony_ci	u32	done_idx;	/* index of processed packet */
23762306a36Sopenharmony_ci	struct ave_desc *desc;	/* skb info related descriptor */
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistruct ave_stats {
24162306a36Sopenharmony_ci	struct	u64_stats_sync	syncp;
24262306a36Sopenharmony_ci	u64	packets;
24362306a36Sopenharmony_ci	u64	bytes;
24462306a36Sopenharmony_ci	u64	errors;
24562306a36Sopenharmony_ci	u64	dropped;
24662306a36Sopenharmony_ci	u64	collisions;
24762306a36Sopenharmony_ci	u64	fifo_errors;
24862306a36Sopenharmony_ci};
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistruct ave_private {
25162306a36Sopenharmony_ci	void __iomem            *base;
25262306a36Sopenharmony_ci	int                     irq;
25362306a36Sopenharmony_ci	int			phy_id;
25462306a36Sopenharmony_ci	unsigned int		desc_size;
25562306a36Sopenharmony_ci	u32			msg_enable;
25662306a36Sopenharmony_ci	int			nclks;
25762306a36Sopenharmony_ci	struct clk		*clk[AVE_MAX_CLKS];
25862306a36Sopenharmony_ci	int			nrsts;
25962306a36Sopenharmony_ci	struct reset_control	*rst[AVE_MAX_RSTS];
26062306a36Sopenharmony_ci	phy_interface_t		phy_mode;
26162306a36Sopenharmony_ci	struct phy_device	*phydev;
26262306a36Sopenharmony_ci	struct mii_bus		*mdio;
26362306a36Sopenharmony_ci	struct regmap		*regmap;
26462306a36Sopenharmony_ci	unsigned int		pinmode_mask;
26562306a36Sopenharmony_ci	unsigned int		pinmode_val;
26662306a36Sopenharmony_ci	u32			wolopts;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* stats */
26962306a36Sopenharmony_ci	struct ave_stats	stats_rx;
27062306a36Sopenharmony_ci	struct ave_stats	stats_tx;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* NAPI support */
27362306a36Sopenharmony_ci	struct net_device	*ndev;
27462306a36Sopenharmony_ci	struct napi_struct	napi_rx;
27562306a36Sopenharmony_ci	struct napi_struct	napi_tx;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* descriptor */
27862306a36Sopenharmony_ci	struct ave_desc_info	rx;
27962306a36Sopenharmony_ci	struct ave_desc_info	tx;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* flow control */
28262306a36Sopenharmony_ci	int pause_auto;
28362306a36Sopenharmony_ci	int pause_rx;
28462306a36Sopenharmony_ci	int pause_tx;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	const struct ave_soc_data *data;
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistruct ave_soc_data {
29062306a36Sopenharmony_ci	bool	is_desc_64bit;
29162306a36Sopenharmony_ci	const char	*clock_names[AVE_MAX_CLKS];
29262306a36Sopenharmony_ci	const char	*reset_names[AVE_MAX_RSTS];
29362306a36Sopenharmony_ci	int	(*get_pinmode)(struct ave_private *priv,
29462306a36Sopenharmony_ci			       phy_interface_t phy_mode, u32 arg);
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic u32 ave_desc_read(struct net_device *ndev, enum desc_id id, int entry,
29862306a36Sopenharmony_ci			 int offset)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
30162306a36Sopenharmony_ci	u32 addr;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	addr = ((id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr)
30462306a36Sopenharmony_ci		+ entry * priv->desc_size + offset;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return readl(priv->base + addr);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic u32 ave_desc_read_cmdsts(struct net_device *ndev, enum desc_id id,
31062306a36Sopenharmony_ci				int entry)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	return ave_desc_read(ndev, id, entry, AVE_DESC_OFS_CMDSTS);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic void ave_desc_write(struct net_device *ndev, enum desc_id id,
31662306a36Sopenharmony_ci			   int entry, int offset, u32 val)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
31962306a36Sopenharmony_ci	u32 addr;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	addr = ((id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr)
32262306a36Sopenharmony_ci		+ entry * priv->desc_size + offset;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	writel(val, priv->base + addr);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void ave_desc_write_cmdsts(struct net_device *ndev, enum desc_id id,
32862306a36Sopenharmony_ci				  int entry, u32 val)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	ave_desc_write(ndev, id, entry, AVE_DESC_OFS_CMDSTS, val);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic void ave_desc_write_addr(struct net_device *ndev, enum desc_id id,
33462306a36Sopenharmony_ci				int entry, dma_addr_t paddr)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	ave_desc_write(ndev, id, entry, AVE_DESC_OFS_ADDRL,
33962306a36Sopenharmony_ci		       lower_32_bits(paddr));
34062306a36Sopenharmony_ci	if (IS_DESC_64BIT(priv))
34162306a36Sopenharmony_ci		ave_desc_write(ndev, id,
34262306a36Sopenharmony_ci			       entry, AVE_DESC_OFS_ADDRU,
34362306a36Sopenharmony_ci			       upper_32_bits(paddr));
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic u32 ave_irq_disable_all(struct net_device *ndev)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
34962306a36Sopenharmony_ci	u32 ret;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ret = readl(priv->base + AVE_GIMR);
35262306a36Sopenharmony_ci	writel(0, priv->base + AVE_GIMR);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return ret;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic void ave_irq_restore(struct net_device *ndev, u32 val)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	writel(val, priv->base + AVE_GIMR);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void ave_irq_enable(struct net_device *ndev, u32 bitflag)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	writel(readl(priv->base + AVE_GIMR) | bitflag, priv->base + AVE_GIMR);
36962306a36Sopenharmony_ci	writel(bitflag, priv->base + AVE_GISR);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void ave_hw_write_macaddr(struct net_device *ndev,
37362306a36Sopenharmony_ci				 const unsigned char *mac_addr,
37462306a36Sopenharmony_ci				 int reg1, int reg2)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	writel(mac_addr[0] | mac_addr[1] << 8 |
37962306a36Sopenharmony_ci	       mac_addr[2] << 16 | mac_addr[3] << 24, priv->base + reg1);
38062306a36Sopenharmony_ci	writel(mac_addr[4] | mac_addr[5] << 8, priv->base + reg2);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic void ave_hw_read_version(struct net_device *ndev, char *buf, int len)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
38662306a36Sopenharmony_ci	u32 major, minor, vr;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	vr = readl(priv->base + AVE_VR);
38962306a36Sopenharmony_ci	major = (vr & GENMASK(15, 8)) >> 8;
39062306a36Sopenharmony_ci	minor = (vr & GENMASK(7, 0));
39162306a36Sopenharmony_ci	snprintf(buf, len, "v%u.%u", major, minor);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void ave_ethtool_get_drvinfo(struct net_device *ndev,
39562306a36Sopenharmony_ci				    struct ethtool_drvinfo *info)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct device *dev = ndev->dev.parent;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	strscpy(info->driver, dev->driver->name, sizeof(info->driver));
40062306a36Sopenharmony_ci	strscpy(info->bus_info, dev_name(dev), sizeof(info->bus_info));
40162306a36Sopenharmony_ci	ave_hw_read_version(ndev, info->fw_version, sizeof(info->fw_version));
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic u32 ave_ethtool_get_msglevel(struct net_device *ndev)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return priv->msg_enable;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic void ave_ethtool_set_msglevel(struct net_device *ndev, u32 val)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	priv->msg_enable = val;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic void ave_ethtool_get_wol(struct net_device *ndev,
41962306a36Sopenharmony_ci				struct ethtool_wolinfo *wol)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	wol->supported = 0;
42262306a36Sopenharmony_ci	wol->wolopts   = 0;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (ndev->phydev)
42562306a36Sopenharmony_ci		phy_ethtool_get_wol(ndev->phydev, wol);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int __ave_ethtool_set_wol(struct net_device *ndev,
42962306a36Sopenharmony_ci				 struct ethtool_wolinfo *wol)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	if (!ndev->phydev ||
43262306a36Sopenharmony_ci	    (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)))
43362306a36Sopenharmony_ci		return -EOPNOTSUPP;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return phy_ethtool_set_wol(ndev->phydev, wol);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic int ave_ethtool_set_wol(struct net_device *ndev,
43962306a36Sopenharmony_ci			       struct ethtool_wolinfo *wol)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	int ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ret = __ave_ethtool_set_wol(ndev, wol);
44462306a36Sopenharmony_ci	if (!ret)
44562306a36Sopenharmony_ci		device_set_wakeup_enable(&ndev->dev, !!wol->wolopts);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	return ret;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void ave_ethtool_get_pauseparam(struct net_device *ndev,
45162306a36Sopenharmony_ci				       struct ethtool_pauseparam *pause)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	pause->autoneg  = priv->pause_auto;
45662306a36Sopenharmony_ci	pause->rx_pause = priv->pause_rx;
45762306a36Sopenharmony_ci	pause->tx_pause = priv->pause_tx;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int ave_ethtool_set_pauseparam(struct net_device *ndev,
46162306a36Sopenharmony_ci				      struct ethtool_pauseparam *pause)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
46462306a36Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (!phydev)
46762306a36Sopenharmony_ci		return -EINVAL;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	priv->pause_auto = pause->autoneg;
47062306a36Sopenharmony_ci	priv->pause_rx   = pause->rx_pause;
47162306a36Sopenharmony_ci	priv->pause_tx   = pause->tx_pause;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic const struct ethtool_ops ave_ethtool_ops = {
47962306a36Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
48062306a36Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
48162306a36Sopenharmony_ci	.get_drvinfo		= ave_ethtool_get_drvinfo,
48262306a36Sopenharmony_ci	.nway_reset		= phy_ethtool_nway_reset,
48362306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
48462306a36Sopenharmony_ci	.get_msglevel		= ave_ethtool_get_msglevel,
48562306a36Sopenharmony_ci	.set_msglevel		= ave_ethtool_set_msglevel,
48662306a36Sopenharmony_ci	.get_wol		= ave_ethtool_get_wol,
48762306a36Sopenharmony_ci	.set_wol		= ave_ethtool_set_wol,
48862306a36Sopenharmony_ci	.get_pauseparam         = ave_ethtool_get_pauseparam,
48962306a36Sopenharmony_ci	.set_pauseparam         = ave_ethtool_set_pauseparam,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int ave_mdiobus_read(struct mii_bus *bus, int phyid, int regnum)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct net_device *ndev = bus->priv;
49562306a36Sopenharmony_ci	struct ave_private *priv;
49662306a36Sopenharmony_ci	u32 mdioctl, mdiosr;
49762306a36Sopenharmony_ci	int ret;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	priv = netdev_priv(ndev);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* write address */
50262306a36Sopenharmony_ci	writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* read request */
50562306a36Sopenharmony_ci	mdioctl = readl(priv->base + AVE_MDIOCTR);
50662306a36Sopenharmony_ci	writel((mdioctl | AVE_MDIOCTR_RREQ) & ~AVE_MDIOCTR_WREQ,
50762306a36Sopenharmony_ci	       priv->base + AVE_MDIOCTR);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
51062306a36Sopenharmony_ci				 !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
51162306a36Sopenharmony_ci	if (ret) {
51262306a36Sopenharmony_ci		netdev_err(ndev, "failed to read (phy:%d reg:%x)\n",
51362306a36Sopenharmony_ci			   phyid, regnum);
51462306a36Sopenharmony_ci		return ret;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return readl(priv->base + AVE_MDIORDR) & GENMASK(15, 0);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int ave_mdiobus_write(struct mii_bus *bus, int phyid, int regnum,
52162306a36Sopenharmony_ci			     u16 val)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct net_device *ndev = bus->priv;
52462306a36Sopenharmony_ci	struct ave_private *priv;
52562306a36Sopenharmony_ci	u32 mdioctl, mdiosr;
52662306a36Sopenharmony_ci	int ret;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	priv = netdev_priv(ndev);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* write address */
53162306a36Sopenharmony_ci	writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* write data */
53462306a36Sopenharmony_ci	writel(val, priv->base + AVE_MDIOWDR);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* write request */
53762306a36Sopenharmony_ci	mdioctl = readl(priv->base + AVE_MDIOCTR);
53862306a36Sopenharmony_ci	writel((mdioctl | AVE_MDIOCTR_WREQ) & ~AVE_MDIOCTR_RREQ,
53962306a36Sopenharmony_ci	       priv->base + AVE_MDIOCTR);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
54262306a36Sopenharmony_ci				 !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
54362306a36Sopenharmony_ci	if (ret)
54462306a36Sopenharmony_ci		netdev_err(ndev, "failed to write (phy:%d reg:%x)\n",
54562306a36Sopenharmony_ci			   phyid, regnum);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return ret;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic int ave_dma_map(struct net_device *ndev, struct ave_desc *desc,
55162306a36Sopenharmony_ci		       void *ptr, size_t len, enum dma_data_direction dir,
55262306a36Sopenharmony_ci		       dma_addr_t *paddr)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	dma_addr_t map_addr;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	map_addr = dma_map_single(ndev->dev.parent, ptr, len, dir);
55762306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(ndev->dev.parent, map_addr)))
55862306a36Sopenharmony_ci		return -ENOMEM;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	desc->skbs_dma = map_addr;
56162306a36Sopenharmony_ci	desc->skbs_dmalen = len;
56262306a36Sopenharmony_ci	*paddr = map_addr;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	return 0;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic void ave_dma_unmap(struct net_device *ndev, struct ave_desc *desc,
56862306a36Sopenharmony_ci			  enum dma_data_direction dir)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	if (!desc->skbs_dma)
57162306a36Sopenharmony_ci		return;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	dma_unmap_single(ndev->dev.parent,
57462306a36Sopenharmony_ci			 desc->skbs_dma, desc->skbs_dmalen, dir);
57562306a36Sopenharmony_ci	desc->skbs_dma = 0;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci/* Prepare Rx descriptor and memory */
57962306a36Sopenharmony_cistatic int ave_rxdesc_prepare(struct net_device *ndev, int entry)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
58262306a36Sopenharmony_ci	struct sk_buff *skb;
58362306a36Sopenharmony_ci	dma_addr_t paddr;
58462306a36Sopenharmony_ci	int ret;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	skb = priv->rx.desc[entry].skbs;
58762306a36Sopenharmony_ci	if (!skb) {
58862306a36Sopenharmony_ci		skb = netdev_alloc_skb(ndev, AVE_MAX_ETHFRAME);
58962306a36Sopenharmony_ci		if (!skb) {
59062306a36Sopenharmony_ci			netdev_err(ndev, "can't allocate skb for Rx\n");
59162306a36Sopenharmony_ci			return -ENOMEM;
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci		skb->data += AVE_FRAME_HEADROOM;
59462306a36Sopenharmony_ci		skb->tail += AVE_FRAME_HEADROOM;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* set disable to cmdsts */
59862306a36Sopenharmony_ci	ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
59962306a36Sopenharmony_ci			      AVE_STS_INTR | AVE_STS_OWN);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* map Rx buffer
60262306a36Sopenharmony_ci	 * Rx buffer set to the Rx descriptor has two restrictions:
60362306a36Sopenharmony_ci	 * - Rx buffer address is 4 byte aligned.
60462306a36Sopenharmony_ci	 * - Rx buffer begins with 2 byte headroom, and data will be put from
60562306a36Sopenharmony_ci	 *   (buffer + 2).
60662306a36Sopenharmony_ci	 * To satisfy this, specify the address to put back the buffer
60762306a36Sopenharmony_ci	 * pointer advanced by AVE_FRAME_HEADROOM, and expand the map size
60862306a36Sopenharmony_ci	 * by AVE_FRAME_HEADROOM.
60962306a36Sopenharmony_ci	 */
61062306a36Sopenharmony_ci	ret = ave_dma_map(ndev, &priv->rx.desc[entry],
61162306a36Sopenharmony_ci			  skb->data - AVE_FRAME_HEADROOM,
61262306a36Sopenharmony_ci			  AVE_MAX_ETHFRAME + AVE_FRAME_HEADROOM,
61362306a36Sopenharmony_ci			  DMA_FROM_DEVICE, &paddr);
61462306a36Sopenharmony_ci	if (ret) {
61562306a36Sopenharmony_ci		netdev_err(ndev, "can't map skb for Rx\n");
61662306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
61762306a36Sopenharmony_ci		return ret;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci	priv->rx.desc[entry].skbs = skb;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* set buffer pointer */
62262306a36Sopenharmony_ci	ave_desc_write_addr(ndev, AVE_DESCID_RX, entry, paddr);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* set enable to cmdsts */
62562306a36Sopenharmony_ci	ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
62662306a36Sopenharmony_ci			      AVE_STS_INTR | AVE_MAX_ETHFRAME);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return ret;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/* Switch state of descriptor */
63262306a36Sopenharmony_cistatic int ave_desc_switch(struct net_device *ndev, enum desc_state state)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
63562306a36Sopenharmony_ci	int ret = 0;
63662306a36Sopenharmony_ci	u32 val;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	switch (state) {
63962306a36Sopenharmony_ci	case AVE_DESC_START:
64062306a36Sopenharmony_ci		writel(AVE_DESCC_TD | AVE_DESCC_RD0, priv->base + AVE_DESCC);
64162306a36Sopenharmony_ci		break;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	case AVE_DESC_STOP:
64462306a36Sopenharmony_ci		writel(0, priv->base + AVE_DESCC);
64562306a36Sopenharmony_ci		if (readl_poll_timeout(priv->base + AVE_DESCC, val, !val,
64662306a36Sopenharmony_ci				       150, 15000)) {
64762306a36Sopenharmony_ci			netdev_err(ndev, "can't stop descriptor\n");
64862306a36Sopenharmony_ci			ret = -EBUSY;
64962306a36Sopenharmony_ci		}
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	case AVE_DESC_RX_SUSPEND:
65362306a36Sopenharmony_ci		val = readl(priv->base + AVE_DESCC);
65462306a36Sopenharmony_ci		val |= AVE_DESCC_RDSTP;
65562306a36Sopenharmony_ci		val &= ~AVE_DESCC_STATUS_MASK;
65662306a36Sopenharmony_ci		writel(val, priv->base + AVE_DESCC);
65762306a36Sopenharmony_ci		if (readl_poll_timeout(priv->base + AVE_DESCC, val,
65862306a36Sopenharmony_ci				       val & (AVE_DESCC_RDSTP << 16),
65962306a36Sopenharmony_ci				       150, 150000)) {
66062306a36Sopenharmony_ci			netdev_err(ndev, "can't suspend descriptor\n");
66162306a36Sopenharmony_ci			ret = -EBUSY;
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci		break;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	case AVE_DESC_RX_PERMIT:
66662306a36Sopenharmony_ci		val = readl(priv->base + AVE_DESCC);
66762306a36Sopenharmony_ci		val &= ~AVE_DESCC_RDSTP;
66862306a36Sopenharmony_ci		val &= ~AVE_DESCC_STATUS_MASK;
66962306a36Sopenharmony_ci		writel(val, priv->base + AVE_DESCC);
67062306a36Sopenharmony_ci		break;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	default:
67362306a36Sopenharmony_ci		ret = -EINVAL;
67462306a36Sopenharmony_ci		break;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return ret;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int ave_tx_complete(struct net_device *ndev)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
68362306a36Sopenharmony_ci	u32 proc_idx, done_idx, ndesc, cmdsts;
68462306a36Sopenharmony_ci	unsigned int nr_freebuf = 0;
68562306a36Sopenharmony_ci	unsigned int tx_packets = 0;
68662306a36Sopenharmony_ci	unsigned int tx_bytes = 0;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	proc_idx = priv->tx.proc_idx;
68962306a36Sopenharmony_ci	done_idx = priv->tx.done_idx;
69062306a36Sopenharmony_ci	ndesc    = priv->tx.ndesc;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* free pre-stored skb from done_idx to proc_idx */
69362306a36Sopenharmony_ci	while (proc_idx != done_idx) {
69462306a36Sopenharmony_ci		cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_TX, done_idx);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		/* do nothing if owner is HW (==1 for Tx) */
69762306a36Sopenharmony_ci		if (cmdsts & AVE_STS_OWN)
69862306a36Sopenharmony_ci			break;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		/* check Tx status and updates statistics */
70162306a36Sopenharmony_ci		if (cmdsts & AVE_STS_OK) {
70262306a36Sopenharmony_ci			tx_bytes += cmdsts & AVE_STS_PKTLEN_TX_MASK;
70362306a36Sopenharmony_ci			/* success */
70462306a36Sopenharmony_ci			if (cmdsts & AVE_STS_LAST)
70562306a36Sopenharmony_ci				tx_packets++;
70662306a36Sopenharmony_ci		} else {
70762306a36Sopenharmony_ci			/* error */
70862306a36Sopenharmony_ci			if (cmdsts & AVE_STS_LAST) {
70962306a36Sopenharmony_ci				priv->stats_tx.errors++;
71062306a36Sopenharmony_ci				if (cmdsts & (AVE_STS_OWC | AVE_STS_EC))
71162306a36Sopenharmony_ci					priv->stats_tx.collisions++;
71262306a36Sopenharmony_ci			}
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		/* release skb */
71662306a36Sopenharmony_ci		if (priv->tx.desc[done_idx].skbs) {
71762306a36Sopenharmony_ci			ave_dma_unmap(ndev, &priv->tx.desc[done_idx],
71862306a36Sopenharmony_ci				      DMA_TO_DEVICE);
71962306a36Sopenharmony_ci			dev_consume_skb_any(priv->tx.desc[done_idx].skbs);
72062306a36Sopenharmony_ci			priv->tx.desc[done_idx].skbs = NULL;
72162306a36Sopenharmony_ci			nr_freebuf++;
72262306a36Sopenharmony_ci		}
72362306a36Sopenharmony_ci		done_idx = (done_idx + 1) % ndesc;
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	priv->tx.done_idx = done_idx;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* update stats */
72962306a36Sopenharmony_ci	u64_stats_update_begin(&priv->stats_tx.syncp);
73062306a36Sopenharmony_ci	priv->stats_tx.packets += tx_packets;
73162306a36Sopenharmony_ci	priv->stats_tx.bytes   += tx_bytes;
73262306a36Sopenharmony_ci	u64_stats_update_end(&priv->stats_tx.syncp);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* wake queue for freeing buffer */
73562306a36Sopenharmony_ci	if (unlikely(netif_queue_stopped(ndev)) && nr_freebuf)
73662306a36Sopenharmony_ci		netif_wake_queue(ndev);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return nr_freebuf;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int ave_rx_receive(struct net_device *ndev, int num)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
74462306a36Sopenharmony_ci	unsigned int rx_packets = 0;
74562306a36Sopenharmony_ci	unsigned int rx_bytes = 0;
74662306a36Sopenharmony_ci	u32 proc_idx, done_idx;
74762306a36Sopenharmony_ci	struct sk_buff *skb;
74862306a36Sopenharmony_ci	unsigned int pktlen;
74962306a36Sopenharmony_ci	int restpkt, npkts;
75062306a36Sopenharmony_ci	u32 ndesc, cmdsts;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	proc_idx = priv->rx.proc_idx;
75362306a36Sopenharmony_ci	done_idx = priv->rx.done_idx;
75462306a36Sopenharmony_ci	ndesc    = priv->rx.ndesc;
75562306a36Sopenharmony_ci	restpkt  = ((proc_idx + ndesc - 1) - done_idx) % ndesc;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	for (npkts = 0; npkts < num; npkts++) {
75862306a36Sopenharmony_ci		/* we can't receive more packet, so fill desc quickly */
75962306a36Sopenharmony_ci		if (--restpkt < 0)
76062306a36Sopenharmony_ci			break;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_RX, proc_idx);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		/* do nothing if owner is HW (==0 for Rx) */
76562306a36Sopenharmony_ci		if (!(cmdsts & AVE_STS_OWN))
76662306a36Sopenharmony_ci			break;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		if (!(cmdsts & AVE_STS_OK)) {
76962306a36Sopenharmony_ci			priv->stats_rx.errors++;
77062306a36Sopenharmony_ci			proc_idx = (proc_idx + 1) % ndesc;
77162306a36Sopenharmony_ci			continue;
77262306a36Sopenharmony_ci		}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci		pktlen = cmdsts & AVE_STS_PKTLEN_RX_MASK;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		/* get skbuff for rx */
77762306a36Sopenharmony_ci		skb = priv->rx.desc[proc_idx].skbs;
77862306a36Sopenharmony_ci		priv->rx.desc[proc_idx].skbs = NULL;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		ave_dma_unmap(ndev, &priv->rx.desc[proc_idx], DMA_FROM_DEVICE);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		skb->dev = ndev;
78362306a36Sopenharmony_ci		skb_put(skb, pktlen);
78462306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, ndev);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		if ((cmdsts & AVE_STS_CSSV) && (!(cmdsts & AVE_STS_CSER)))
78762306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		rx_packets++;
79062306a36Sopenharmony_ci		rx_bytes += pktlen;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		netif_receive_skb(skb);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		proc_idx = (proc_idx + 1) % ndesc;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	priv->rx.proc_idx = proc_idx;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	/* update stats */
80062306a36Sopenharmony_ci	u64_stats_update_begin(&priv->stats_rx.syncp);
80162306a36Sopenharmony_ci	priv->stats_rx.packets += rx_packets;
80262306a36Sopenharmony_ci	priv->stats_rx.bytes   += rx_bytes;
80362306a36Sopenharmony_ci	u64_stats_update_end(&priv->stats_rx.syncp);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* refill the Rx buffers */
80662306a36Sopenharmony_ci	while (proc_idx != done_idx) {
80762306a36Sopenharmony_ci		if (ave_rxdesc_prepare(ndev, done_idx))
80862306a36Sopenharmony_ci			break;
80962306a36Sopenharmony_ci		done_idx = (done_idx + 1) % ndesc;
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	priv->rx.done_idx = done_idx;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return npkts;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int ave_napi_poll_rx(struct napi_struct *napi, int budget)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct ave_private *priv;
82062306a36Sopenharmony_ci	struct net_device *ndev;
82162306a36Sopenharmony_ci	int num;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	priv = container_of(napi, struct ave_private, napi_rx);
82462306a36Sopenharmony_ci	ndev = priv->ndev;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	num = ave_rx_receive(ndev, budget);
82762306a36Sopenharmony_ci	if (num < budget) {
82862306a36Sopenharmony_ci		napi_complete_done(napi, num);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		/* enable Rx interrupt when NAPI finishes */
83162306a36Sopenharmony_ci		ave_irq_enable(ndev, AVE_GI_RXIINT);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return num;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic int ave_napi_poll_tx(struct napi_struct *napi, int budget)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct ave_private *priv;
84062306a36Sopenharmony_ci	struct net_device *ndev;
84162306a36Sopenharmony_ci	int num;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	priv = container_of(napi, struct ave_private, napi_tx);
84462306a36Sopenharmony_ci	ndev = priv->ndev;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	num = ave_tx_complete(ndev);
84762306a36Sopenharmony_ci	napi_complete(napi);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* enable Tx interrupt when NAPI finishes */
85062306a36Sopenharmony_ci	ave_irq_enable(ndev, AVE_GI_TX);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return num;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic void ave_global_reset(struct net_device *ndev)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
85862306a36Sopenharmony_ci	u32 val;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/* set config register */
86162306a36Sopenharmony_ci	val = AVE_CFGR_FLE | AVE_CFGR_IPFCEN | AVE_CFGR_CHE;
86262306a36Sopenharmony_ci	if (!phy_interface_mode_is_rgmii(priv->phy_mode))
86362306a36Sopenharmony_ci		val |= AVE_CFGR_MII;
86462306a36Sopenharmony_ci	writel(val, priv->base + AVE_CFGR);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* reset RMII register */
86762306a36Sopenharmony_ci	val = readl(priv->base + AVE_RSTCTRL);
86862306a36Sopenharmony_ci	val &= ~AVE_RSTCTRL_RMIIRST;
86962306a36Sopenharmony_ci	writel(val, priv->base + AVE_RSTCTRL);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* assert reset */
87262306a36Sopenharmony_ci	writel(AVE_GRR_GRST | AVE_GRR_PHYRST, priv->base + AVE_GRR);
87362306a36Sopenharmony_ci	msleep(20);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/* 1st, negate PHY reset only */
87662306a36Sopenharmony_ci	writel(AVE_GRR_GRST, priv->base + AVE_GRR);
87762306a36Sopenharmony_ci	msleep(40);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* negate reset */
88062306a36Sopenharmony_ci	writel(0, priv->base + AVE_GRR);
88162306a36Sopenharmony_ci	msleep(40);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* negate RMII register */
88462306a36Sopenharmony_ci	val = readl(priv->base + AVE_RSTCTRL);
88562306a36Sopenharmony_ci	val |= AVE_RSTCTRL_RMIIRST;
88662306a36Sopenharmony_ci	writel(val, priv->base + AVE_RSTCTRL);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	ave_irq_disable_all(ndev);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic void ave_rxfifo_reset(struct net_device *ndev)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
89462306a36Sopenharmony_ci	u32 rxcr_org;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* save and disable MAC receive op */
89762306a36Sopenharmony_ci	rxcr_org = readl(priv->base + AVE_RXCR);
89862306a36Sopenharmony_ci	writel(rxcr_org & (~AVE_RXCR_RXEN), priv->base + AVE_RXCR);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	/* suspend Rx descriptor */
90162306a36Sopenharmony_ci	ave_desc_switch(ndev, AVE_DESC_RX_SUSPEND);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/* receive all packets before descriptor starts */
90462306a36Sopenharmony_ci	ave_rx_receive(ndev, priv->rx.ndesc);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	/* assert reset */
90762306a36Sopenharmony_ci	writel(AVE_GRR_RXFFR, priv->base + AVE_GRR);
90862306a36Sopenharmony_ci	udelay(50);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* negate reset */
91162306a36Sopenharmony_ci	writel(0, priv->base + AVE_GRR);
91262306a36Sopenharmony_ci	udelay(20);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* negate interrupt status */
91562306a36Sopenharmony_ci	writel(AVE_GI_RXOVF, priv->base + AVE_GISR);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	/* permit descriptor */
91862306a36Sopenharmony_ci	ave_desc_switch(ndev, AVE_DESC_RX_PERMIT);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* restore MAC reccieve op */
92162306a36Sopenharmony_ci	writel(rxcr_org, priv->base + AVE_RXCR);
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic irqreturn_t ave_irq_handler(int irq, void *netdev)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct net_device *ndev = (struct net_device *)netdev;
92762306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
92862306a36Sopenharmony_ci	u32 gimr_val, gisr_val;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	gimr_val = ave_irq_disable_all(ndev);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	/* get interrupt status */
93362306a36Sopenharmony_ci	gisr_val = readl(priv->base + AVE_GISR);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* PHY */
93662306a36Sopenharmony_ci	if (gisr_val & AVE_GI_PHY)
93762306a36Sopenharmony_ci		writel(AVE_GI_PHY, priv->base + AVE_GISR);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* check exceeding packet */
94062306a36Sopenharmony_ci	if (gisr_val & AVE_GI_RXERR) {
94162306a36Sopenharmony_ci		writel(AVE_GI_RXERR, priv->base + AVE_GISR);
94262306a36Sopenharmony_ci		netdev_err(ndev, "receive a packet exceeding frame buffer\n");
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	gisr_val &= gimr_val;
94662306a36Sopenharmony_ci	if (!gisr_val)
94762306a36Sopenharmony_ci		goto exit_isr;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* RxFIFO overflow */
95062306a36Sopenharmony_ci	if (gisr_val & AVE_GI_RXOVF) {
95162306a36Sopenharmony_ci		priv->stats_rx.fifo_errors++;
95262306a36Sopenharmony_ci		ave_rxfifo_reset(ndev);
95362306a36Sopenharmony_ci		goto exit_isr;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/* Rx drop */
95762306a36Sopenharmony_ci	if (gisr_val & AVE_GI_RXDROP) {
95862306a36Sopenharmony_ci		priv->stats_rx.dropped++;
95962306a36Sopenharmony_ci		writel(AVE_GI_RXDROP, priv->base + AVE_GISR);
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	/* Rx interval */
96362306a36Sopenharmony_ci	if (gisr_val & AVE_GI_RXIINT) {
96462306a36Sopenharmony_ci		napi_schedule(&priv->napi_rx);
96562306a36Sopenharmony_ci		/* still force to disable Rx interrupt until NAPI finishes */
96662306a36Sopenharmony_ci		gimr_val &= ~AVE_GI_RXIINT;
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* Tx completed */
97062306a36Sopenharmony_ci	if (gisr_val & AVE_GI_TX) {
97162306a36Sopenharmony_ci		napi_schedule(&priv->napi_tx);
97262306a36Sopenharmony_ci		/* still force to disable Tx interrupt until NAPI finishes */
97362306a36Sopenharmony_ci		gimr_val &= ~AVE_GI_TX;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ciexit_isr:
97762306a36Sopenharmony_ci	ave_irq_restore(ndev, gimr_val);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	return IRQ_HANDLED;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic int ave_pfsel_start(struct net_device *ndev, unsigned int entry)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
98562306a36Sopenharmony_ci	u32 val;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	if (WARN_ON(entry > AVE_PF_SIZE))
98862306a36Sopenharmony_ci		return -EINVAL;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	val = readl(priv->base + AVE_PFEN);
99162306a36Sopenharmony_ci	writel(val | BIT(entry), priv->base + AVE_PFEN);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	return 0;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistatic int ave_pfsel_stop(struct net_device *ndev, unsigned int entry)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
99962306a36Sopenharmony_ci	u32 val;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (WARN_ON(entry > AVE_PF_SIZE))
100262306a36Sopenharmony_ci		return -EINVAL;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	val = readl(priv->base + AVE_PFEN);
100562306a36Sopenharmony_ci	writel(val & ~BIT(entry), priv->base + AVE_PFEN);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	return 0;
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cistatic int ave_pfsel_set_macaddr(struct net_device *ndev,
101162306a36Sopenharmony_ci				 unsigned int entry,
101262306a36Sopenharmony_ci				 const unsigned char *mac_addr,
101362306a36Sopenharmony_ci				 unsigned int set_size)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (WARN_ON(entry > AVE_PF_SIZE))
101862306a36Sopenharmony_ci		return -EINVAL;
101962306a36Sopenharmony_ci	if (WARN_ON(set_size > 6))
102062306a36Sopenharmony_ci		return -EINVAL;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	ave_pfsel_stop(ndev, entry);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* set MAC address for the filter */
102562306a36Sopenharmony_ci	ave_hw_write_macaddr(ndev, mac_addr,
102662306a36Sopenharmony_ci			     AVE_PKTF(entry), AVE_PKTF(entry) + 4);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* set byte mask */
102962306a36Sopenharmony_ci	writel(GENMASK(31, set_size) & AVE_PFMBYTE_MASK0,
103062306a36Sopenharmony_ci	       priv->base + AVE_PFMBYTE(entry));
103162306a36Sopenharmony_ci	writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/* set bit mask filter */
103462306a36Sopenharmony_ci	writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	/* set selector to ring 0 */
103762306a36Sopenharmony_ci	writel(0, priv->base + AVE_PFSEL(entry));
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/* restart filter */
104062306a36Sopenharmony_ci	ave_pfsel_start(ndev, entry);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return 0;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic void ave_pfsel_set_promisc(struct net_device *ndev,
104662306a36Sopenharmony_ci				  unsigned int entry, u32 rxring)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	if (WARN_ON(entry > AVE_PF_SIZE))
105162306a36Sopenharmony_ci		return;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	ave_pfsel_stop(ndev, entry);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* set byte mask */
105662306a36Sopenharmony_ci	writel(AVE_PFMBYTE_MASK0, priv->base + AVE_PFMBYTE(entry));
105762306a36Sopenharmony_ci	writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* set bit mask filter */
106062306a36Sopenharmony_ci	writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* set selector to rxring */
106362306a36Sopenharmony_ci	writel(rxring, priv->base + AVE_PFSEL(entry));
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	ave_pfsel_start(ndev, entry);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic void ave_pfsel_init(struct net_device *ndev)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	unsigned char bcast_mac[ETH_ALEN];
107162306a36Sopenharmony_ci	int i;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	eth_broadcast_addr(bcast_mac);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	for (i = 0; i < AVE_PF_SIZE; i++)
107662306a36Sopenharmony_ci		ave_pfsel_stop(ndev, i);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	/* promiscious entry, select ring 0 */
107962306a36Sopenharmony_ci	ave_pfsel_set_promisc(ndev, AVE_PFNUM_FILTER, 0);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	/* unicast entry */
108262306a36Sopenharmony_ci	ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	/* broadcast entry */
108562306a36Sopenharmony_ci	ave_pfsel_set_macaddr(ndev, AVE_PFNUM_BROADCAST, bcast_mac, 6);
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic void ave_phy_adjust_link(struct net_device *ndev)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
109162306a36Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
109262306a36Sopenharmony_ci	u32 val, txcr, rxcr, rxcr_org;
109362306a36Sopenharmony_ci	u16 rmt_adv = 0, lcl_adv = 0;
109462306a36Sopenharmony_ci	u8 cap;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/* set RGMII speed */
109762306a36Sopenharmony_ci	val = readl(priv->base + AVE_TXCR);
109862306a36Sopenharmony_ci	val &= ~(AVE_TXCR_TXSPD_100 | AVE_TXCR_TXSPD_1G);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (phy_interface_is_rgmii(phydev) && phydev->speed == SPEED_1000)
110162306a36Sopenharmony_ci		val |= AVE_TXCR_TXSPD_1G;
110262306a36Sopenharmony_ci	else if (phydev->speed == SPEED_100)
110362306a36Sopenharmony_ci		val |= AVE_TXCR_TXSPD_100;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	writel(val, priv->base + AVE_TXCR);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* set RMII speed (100M/10M only) */
110862306a36Sopenharmony_ci	if (!phy_interface_is_rgmii(phydev)) {
110962306a36Sopenharmony_ci		val = readl(priv->base + AVE_LINKSEL);
111062306a36Sopenharmony_ci		if (phydev->speed == SPEED_10)
111162306a36Sopenharmony_ci			val &= ~AVE_LINKSEL_100M;
111262306a36Sopenharmony_ci		else
111362306a36Sopenharmony_ci			val |= AVE_LINKSEL_100M;
111462306a36Sopenharmony_ci		writel(val, priv->base + AVE_LINKSEL);
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	/* check current RXCR/TXCR */
111862306a36Sopenharmony_ci	rxcr = readl(priv->base + AVE_RXCR);
111962306a36Sopenharmony_ci	txcr = readl(priv->base + AVE_TXCR);
112062306a36Sopenharmony_ci	rxcr_org = rxcr;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (phydev->duplex) {
112362306a36Sopenharmony_ci		rxcr |= AVE_RXCR_FDUPEN;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci		if (phydev->pause)
112662306a36Sopenharmony_ci			rmt_adv |= LPA_PAUSE_CAP;
112762306a36Sopenharmony_ci		if (phydev->asym_pause)
112862306a36Sopenharmony_ci			rmt_adv |= LPA_PAUSE_ASYM;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		lcl_adv = linkmode_adv_to_lcl_adv_t(phydev->advertising);
113162306a36Sopenharmony_ci		cap = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
113262306a36Sopenharmony_ci		if (cap & FLOW_CTRL_TX)
113362306a36Sopenharmony_ci			txcr |= AVE_TXCR_FLOCTR;
113462306a36Sopenharmony_ci		else
113562306a36Sopenharmony_ci			txcr &= ~AVE_TXCR_FLOCTR;
113662306a36Sopenharmony_ci		if (cap & FLOW_CTRL_RX)
113762306a36Sopenharmony_ci			rxcr |= AVE_RXCR_FLOCTR;
113862306a36Sopenharmony_ci		else
113962306a36Sopenharmony_ci			rxcr &= ~AVE_RXCR_FLOCTR;
114062306a36Sopenharmony_ci	} else {
114162306a36Sopenharmony_ci		rxcr &= ~AVE_RXCR_FDUPEN;
114262306a36Sopenharmony_ci		rxcr &= ~AVE_RXCR_FLOCTR;
114362306a36Sopenharmony_ci		txcr &= ~AVE_TXCR_FLOCTR;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (rxcr_org != rxcr) {
114762306a36Sopenharmony_ci		/* disable Rx mac */
114862306a36Sopenharmony_ci		writel(rxcr & ~AVE_RXCR_RXEN, priv->base + AVE_RXCR);
114962306a36Sopenharmony_ci		/* change and enable TX/Rx mac */
115062306a36Sopenharmony_ci		writel(txcr, priv->base + AVE_TXCR);
115162306a36Sopenharmony_ci		writel(rxcr, priv->base + AVE_RXCR);
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	phy_print_status(phydev);
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic void ave_macaddr_init(struct net_device *ndev)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	ave_hw_write_macaddr(ndev, ndev->dev_addr, AVE_RXMAC1R, AVE_RXMAC2R);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/* pfsel unicast entry */
116262306a36Sopenharmony_ci	ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic int ave_init(struct net_device *ndev)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
116862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
116962306a36Sopenharmony_ci	struct device *dev = ndev->dev.parent;
117062306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
117162306a36Sopenharmony_ci	struct device_node *mdio_np;
117262306a36Sopenharmony_ci	struct phy_device *phydev;
117362306a36Sopenharmony_ci	int nc, nr, ret;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* enable clk because of hw access until ndo_open */
117662306a36Sopenharmony_ci	for (nc = 0; nc < priv->nclks; nc++) {
117762306a36Sopenharmony_ci		ret = clk_prepare_enable(priv->clk[nc]);
117862306a36Sopenharmony_ci		if (ret) {
117962306a36Sopenharmony_ci			dev_err(dev, "can't enable clock\n");
118062306a36Sopenharmony_ci			goto out_clk_disable;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	for (nr = 0; nr < priv->nrsts; nr++) {
118562306a36Sopenharmony_ci		ret = reset_control_deassert(priv->rst[nr]);
118662306a36Sopenharmony_ci		if (ret) {
118762306a36Sopenharmony_ci			dev_err(dev, "can't deassert reset\n");
118862306a36Sopenharmony_ci			goto out_reset_assert;
118962306a36Sopenharmony_ci		}
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	ret = regmap_update_bits(priv->regmap, SG_ETPINMODE,
119362306a36Sopenharmony_ci				 priv->pinmode_mask, priv->pinmode_val);
119462306a36Sopenharmony_ci	if (ret)
119562306a36Sopenharmony_ci		goto out_reset_assert;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	ave_global_reset(ndev);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	mdio_np = of_get_child_by_name(np, "mdio");
120062306a36Sopenharmony_ci	if (!mdio_np) {
120162306a36Sopenharmony_ci		dev_err(dev, "mdio node not found\n");
120262306a36Sopenharmony_ci		ret = -EINVAL;
120362306a36Sopenharmony_ci		goto out_reset_assert;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci	ret = of_mdiobus_register(priv->mdio, mdio_np);
120662306a36Sopenharmony_ci	of_node_put(mdio_np);
120762306a36Sopenharmony_ci	if (ret) {
120862306a36Sopenharmony_ci		dev_err(dev, "failed to register mdiobus\n");
120962306a36Sopenharmony_ci		goto out_reset_assert;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	phydev = of_phy_get_and_connect(ndev, np, ave_phy_adjust_link);
121362306a36Sopenharmony_ci	if (!phydev) {
121462306a36Sopenharmony_ci		dev_err(dev, "could not attach to PHY\n");
121562306a36Sopenharmony_ci		ret = -ENODEV;
121662306a36Sopenharmony_ci		goto out_mdio_unregister;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	priv->phydev = phydev;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	ave_ethtool_get_wol(ndev, &wol);
122262306a36Sopenharmony_ci	device_set_wakeup_capable(&ndev->dev, !!wol.supported);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/* set wol initial state disabled */
122562306a36Sopenharmony_ci	wol.wolopts = 0;
122662306a36Sopenharmony_ci	__ave_ethtool_set_wol(ndev, &wol);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (!phy_interface_is_rgmii(phydev))
122962306a36Sopenharmony_ci		phy_set_max_speed(phydev, SPEED_100);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	phy_support_asym_pause(phydev);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	phydev->mac_managed_pm = true;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	phy_attached_info(phydev);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	return 0;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ciout_mdio_unregister:
124062306a36Sopenharmony_ci	mdiobus_unregister(priv->mdio);
124162306a36Sopenharmony_ciout_reset_assert:
124262306a36Sopenharmony_ci	while (--nr >= 0)
124362306a36Sopenharmony_ci		reset_control_assert(priv->rst[nr]);
124462306a36Sopenharmony_ciout_clk_disable:
124562306a36Sopenharmony_ci	while (--nc >= 0)
124662306a36Sopenharmony_ci		clk_disable_unprepare(priv->clk[nc]);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return ret;
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic void ave_uninit(struct net_device *ndev)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
125462306a36Sopenharmony_ci	int i;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	phy_disconnect(priv->phydev);
125762306a36Sopenharmony_ci	mdiobus_unregister(priv->mdio);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* disable clk because of hw access after ndo_stop */
126062306a36Sopenharmony_ci	for (i = 0; i < priv->nrsts; i++)
126162306a36Sopenharmony_ci		reset_control_assert(priv->rst[i]);
126262306a36Sopenharmony_ci	for (i = 0; i < priv->nclks; i++)
126362306a36Sopenharmony_ci		clk_disable_unprepare(priv->clk[i]);
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic int ave_open(struct net_device *ndev)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
126962306a36Sopenharmony_ci	int entry;
127062306a36Sopenharmony_ci	int ret;
127162306a36Sopenharmony_ci	u32 val;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	ret = request_irq(priv->irq, ave_irq_handler, IRQF_SHARED, ndev->name,
127462306a36Sopenharmony_ci			  ndev);
127562306a36Sopenharmony_ci	if (ret)
127662306a36Sopenharmony_ci		return ret;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	priv->tx.desc = kcalloc(priv->tx.ndesc, sizeof(*priv->tx.desc),
127962306a36Sopenharmony_ci				GFP_KERNEL);
128062306a36Sopenharmony_ci	if (!priv->tx.desc) {
128162306a36Sopenharmony_ci		ret = -ENOMEM;
128262306a36Sopenharmony_ci		goto out_free_irq;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	priv->rx.desc = kcalloc(priv->rx.ndesc, sizeof(*priv->rx.desc),
128662306a36Sopenharmony_ci				GFP_KERNEL);
128762306a36Sopenharmony_ci	if (!priv->rx.desc) {
128862306a36Sopenharmony_ci		kfree(priv->tx.desc);
128962306a36Sopenharmony_ci		ret = -ENOMEM;
129062306a36Sopenharmony_ci		goto out_free_irq;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	/* initialize Tx work and descriptor */
129462306a36Sopenharmony_ci	priv->tx.proc_idx = 0;
129562306a36Sopenharmony_ci	priv->tx.done_idx = 0;
129662306a36Sopenharmony_ci	for (entry = 0; entry < priv->tx.ndesc; entry++) {
129762306a36Sopenharmony_ci		ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, entry, 0);
129862306a36Sopenharmony_ci		ave_desc_write_addr(ndev, AVE_DESCID_TX, entry, 0);
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	writel(AVE_TXDC_ADDR_START |
130162306a36Sopenharmony_ci	       (((priv->tx.ndesc * priv->desc_size) << 16) & AVE_TXDC_SIZE),
130262306a36Sopenharmony_ci	       priv->base + AVE_TXDC);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/* initialize Rx work and descriptor */
130562306a36Sopenharmony_ci	priv->rx.proc_idx = 0;
130662306a36Sopenharmony_ci	priv->rx.done_idx = 0;
130762306a36Sopenharmony_ci	for (entry = 0; entry < priv->rx.ndesc; entry++) {
130862306a36Sopenharmony_ci		if (ave_rxdesc_prepare(ndev, entry))
130962306a36Sopenharmony_ci			break;
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci	writel(AVE_RXDC0_ADDR_START |
131262306a36Sopenharmony_ci	       (((priv->rx.ndesc * priv->desc_size) << 16) & AVE_RXDC0_SIZE),
131362306a36Sopenharmony_ci	       priv->base + AVE_RXDC0);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	ave_desc_switch(ndev, AVE_DESC_START);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	ave_pfsel_init(ndev);
131862306a36Sopenharmony_ci	ave_macaddr_init(ndev);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	/* set Rx configuration */
132162306a36Sopenharmony_ci	/* full duplex, enable pause drop, enalbe flow control */
132262306a36Sopenharmony_ci	val = AVE_RXCR_RXEN | AVE_RXCR_FDUPEN | AVE_RXCR_DRPEN |
132362306a36Sopenharmony_ci		AVE_RXCR_FLOCTR | (AVE_MAX_ETHFRAME & AVE_RXCR_MPSIZ_MASK);
132462306a36Sopenharmony_ci	writel(val, priv->base + AVE_RXCR);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	/* set Tx configuration */
132762306a36Sopenharmony_ci	/* enable flow control, disable loopback */
132862306a36Sopenharmony_ci	writel(AVE_TXCR_FLOCTR, priv->base + AVE_TXCR);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	/* enable timer, clear EN,INTM, and mask interval unit(BSCK) */
133162306a36Sopenharmony_ci	val = readl(priv->base + AVE_IIRQC) & AVE_IIRQC_BSCK;
133262306a36Sopenharmony_ci	val |= AVE_IIRQC_EN0 | (AVE_INTM_COUNT << 16);
133362306a36Sopenharmony_ci	writel(val, priv->base + AVE_IIRQC);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX | AVE_GI_RXDROP;
133662306a36Sopenharmony_ci	ave_irq_restore(ndev, val);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	napi_enable(&priv->napi_rx);
133962306a36Sopenharmony_ci	napi_enable(&priv->napi_tx);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	phy_start(ndev->phydev);
134262306a36Sopenharmony_ci	phy_start_aneg(ndev->phydev);
134362306a36Sopenharmony_ci	netif_start_queue(ndev);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	return 0;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ciout_free_irq:
134862306a36Sopenharmony_ci	disable_irq(priv->irq);
134962306a36Sopenharmony_ci	free_irq(priv->irq, ndev);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	return ret;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_cistatic int ave_stop(struct net_device *ndev)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
135762306a36Sopenharmony_ci	int entry;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	ave_irq_disable_all(ndev);
136062306a36Sopenharmony_ci	disable_irq(priv->irq);
136162306a36Sopenharmony_ci	free_irq(priv->irq, ndev);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	netif_tx_disable(ndev);
136462306a36Sopenharmony_ci	phy_stop(ndev->phydev);
136562306a36Sopenharmony_ci	napi_disable(&priv->napi_tx);
136662306a36Sopenharmony_ci	napi_disable(&priv->napi_rx);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	ave_desc_switch(ndev, AVE_DESC_STOP);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* free Tx buffer */
137162306a36Sopenharmony_ci	for (entry = 0; entry < priv->tx.ndesc; entry++) {
137262306a36Sopenharmony_ci		if (!priv->tx.desc[entry].skbs)
137362306a36Sopenharmony_ci			continue;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		ave_dma_unmap(ndev, &priv->tx.desc[entry], DMA_TO_DEVICE);
137662306a36Sopenharmony_ci		dev_kfree_skb_any(priv->tx.desc[entry].skbs);
137762306a36Sopenharmony_ci		priv->tx.desc[entry].skbs = NULL;
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci	priv->tx.proc_idx = 0;
138062306a36Sopenharmony_ci	priv->tx.done_idx = 0;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* free Rx buffer */
138362306a36Sopenharmony_ci	for (entry = 0; entry < priv->rx.ndesc; entry++) {
138462306a36Sopenharmony_ci		if (!priv->rx.desc[entry].skbs)
138562306a36Sopenharmony_ci			continue;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		ave_dma_unmap(ndev, &priv->rx.desc[entry], DMA_FROM_DEVICE);
138862306a36Sopenharmony_ci		dev_kfree_skb_any(priv->rx.desc[entry].skbs);
138962306a36Sopenharmony_ci		priv->rx.desc[entry].skbs = NULL;
139062306a36Sopenharmony_ci	}
139162306a36Sopenharmony_ci	priv->rx.proc_idx = 0;
139262306a36Sopenharmony_ci	priv->rx.done_idx = 0;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	kfree(priv->tx.desc);
139562306a36Sopenharmony_ci	kfree(priv->rx.desc);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic netdev_tx_t ave_start_xmit(struct sk_buff *skb, struct net_device *ndev)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
140362306a36Sopenharmony_ci	u32 proc_idx, done_idx, ndesc, cmdsts;
140462306a36Sopenharmony_ci	int ret, freepkt;
140562306a36Sopenharmony_ci	dma_addr_t paddr;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	proc_idx = priv->tx.proc_idx;
140862306a36Sopenharmony_ci	done_idx = priv->tx.done_idx;
140962306a36Sopenharmony_ci	ndesc = priv->tx.ndesc;
141062306a36Sopenharmony_ci	freepkt = ((done_idx + ndesc - 1) - proc_idx) % ndesc;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* stop queue when not enough entry */
141362306a36Sopenharmony_ci	if (unlikely(freepkt < 1)) {
141462306a36Sopenharmony_ci		netif_stop_queue(ndev);
141562306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* add padding for short packet */
141962306a36Sopenharmony_ci	if (skb_put_padto(skb, ETH_ZLEN)) {
142062306a36Sopenharmony_ci		priv->stats_tx.dropped++;
142162306a36Sopenharmony_ci		return NETDEV_TX_OK;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	/* map Tx buffer
142562306a36Sopenharmony_ci	 * Tx buffer set to the Tx descriptor doesn't have any restriction.
142662306a36Sopenharmony_ci	 */
142762306a36Sopenharmony_ci	ret = ave_dma_map(ndev, &priv->tx.desc[proc_idx],
142862306a36Sopenharmony_ci			  skb->data, skb->len, DMA_TO_DEVICE, &paddr);
142962306a36Sopenharmony_ci	if (ret) {
143062306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
143162306a36Sopenharmony_ci		priv->stats_tx.dropped++;
143262306a36Sopenharmony_ci		return NETDEV_TX_OK;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	priv->tx.desc[proc_idx].skbs = skb;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	ave_desc_write_addr(ndev, AVE_DESCID_TX, proc_idx, paddr);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	cmdsts = AVE_STS_OWN | AVE_STS_1ST | AVE_STS_LAST |
144062306a36Sopenharmony_ci		(skb->len & AVE_STS_PKTLEN_TX_MASK);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* set interrupt per AVE_FORCE_TXINTCNT or when queue is stopped */
144362306a36Sopenharmony_ci	if (!(proc_idx % AVE_FORCE_TXINTCNT) || netif_queue_stopped(ndev))
144462306a36Sopenharmony_ci		cmdsts |= AVE_STS_INTR;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	/* disable checksum calculation when skb doesn't calurate checksum */
144762306a36Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_NONE ||
144862306a36Sopenharmony_ci	    skb->ip_summed == CHECKSUM_UNNECESSARY)
144962306a36Sopenharmony_ci		cmdsts |= AVE_STS_NOCSUM;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, proc_idx, cmdsts);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	priv->tx.proc_idx = (proc_idx + 1) % ndesc;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return NETDEV_TX_OK;
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_cistatic int ave_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	return phy_mii_ioctl(ndev->phydev, ifr, cmd);
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_cistatic const u8 v4multi_macadr[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
146462306a36Sopenharmony_cistatic const u8 v6multi_macadr[] = { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 };
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic void ave_set_rx_mode(struct net_device *ndev)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
146962306a36Sopenharmony_ci	struct netdev_hw_addr *hw_adr;
147062306a36Sopenharmony_ci	int count, mc_cnt;
147162306a36Sopenharmony_ci	u32 val;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	/* MAC addr filter enable for promiscious mode */
147462306a36Sopenharmony_ci	mc_cnt = netdev_mc_count(ndev);
147562306a36Sopenharmony_ci	val = readl(priv->base + AVE_RXCR);
147662306a36Sopenharmony_ci	if (ndev->flags & IFF_PROMISC || !mc_cnt)
147762306a36Sopenharmony_ci		val &= ~AVE_RXCR_AFEN;
147862306a36Sopenharmony_ci	else
147962306a36Sopenharmony_ci		val |= AVE_RXCR_AFEN;
148062306a36Sopenharmony_ci	writel(val, priv->base + AVE_RXCR);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	/* set all multicast address */
148362306a36Sopenharmony_ci	if ((ndev->flags & IFF_ALLMULTI) || mc_cnt > AVE_PF_MULTICAST_SIZE) {
148462306a36Sopenharmony_ci		ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST,
148562306a36Sopenharmony_ci				      v4multi_macadr, 1);
148662306a36Sopenharmony_ci		ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + 1,
148762306a36Sopenharmony_ci				      v6multi_macadr, 1);
148862306a36Sopenharmony_ci	} else {
148962306a36Sopenharmony_ci		/* stop all multicast filter */
149062306a36Sopenharmony_ci		for (count = 0; count < AVE_PF_MULTICAST_SIZE; count++)
149162306a36Sopenharmony_ci			ave_pfsel_stop(ndev, AVE_PFNUM_MULTICAST + count);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		/* set multicast addresses */
149462306a36Sopenharmony_ci		count = 0;
149562306a36Sopenharmony_ci		netdev_for_each_mc_addr(hw_adr, ndev) {
149662306a36Sopenharmony_ci			if (count == mc_cnt)
149762306a36Sopenharmony_ci				break;
149862306a36Sopenharmony_ci			ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + count,
149962306a36Sopenharmony_ci					      hw_adr->addr, 6);
150062306a36Sopenharmony_ci			count++;
150162306a36Sopenharmony_ci		}
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_cistatic void ave_get_stats64(struct net_device *ndev,
150662306a36Sopenharmony_ci			    struct rtnl_link_stats64 *stats)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
150962306a36Sopenharmony_ci	unsigned int start;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	do {
151262306a36Sopenharmony_ci		start = u64_stats_fetch_begin(&priv->stats_rx.syncp);
151362306a36Sopenharmony_ci		stats->rx_packets = priv->stats_rx.packets;
151462306a36Sopenharmony_ci		stats->rx_bytes	  = priv->stats_rx.bytes;
151562306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(&priv->stats_rx.syncp, start));
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	do {
151862306a36Sopenharmony_ci		start = u64_stats_fetch_begin(&priv->stats_tx.syncp);
151962306a36Sopenharmony_ci		stats->tx_packets = priv->stats_tx.packets;
152062306a36Sopenharmony_ci		stats->tx_bytes	  = priv->stats_tx.bytes;
152162306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(&priv->stats_tx.syncp, start));
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	stats->rx_errors      = priv->stats_rx.errors;
152462306a36Sopenharmony_ci	stats->tx_errors      = priv->stats_tx.errors;
152562306a36Sopenharmony_ci	stats->rx_dropped     = priv->stats_rx.dropped;
152662306a36Sopenharmony_ci	stats->tx_dropped     = priv->stats_tx.dropped;
152762306a36Sopenharmony_ci	stats->rx_fifo_errors = priv->stats_rx.fifo_errors;
152862306a36Sopenharmony_ci	stats->collisions     = priv->stats_tx.collisions;
152962306a36Sopenharmony_ci}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_cistatic int ave_set_mac_address(struct net_device *ndev, void *p)
153262306a36Sopenharmony_ci{
153362306a36Sopenharmony_ci	int ret = eth_mac_addr(ndev, p);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (ret)
153662306a36Sopenharmony_ci		return ret;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	ave_macaddr_init(ndev);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	return 0;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic const struct net_device_ops ave_netdev_ops = {
154462306a36Sopenharmony_ci	.ndo_init		= ave_init,
154562306a36Sopenharmony_ci	.ndo_uninit		= ave_uninit,
154662306a36Sopenharmony_ci	.ndo_open		= ave_open,
154762306a36Sopenharmony_ci	.ndo_stop		= ave_stop,
154862306a36Sopenharmony_ci	.ndo_start_xmit		= ave_start_xmit,
154962306a36Sopenharmony_ci	.ndo_eth_ioctl		= ave_ioctl,
155062306a36Sopenharmony_ci	.ndo_set_rx_mode	= ave_set_rx_mode,
155162306a36Sopenharmony_ci	.ndo_get_stats64	= ave_get_stats64,
155262306a36Sopenharmony_ci	.ndo_set_mac_address	= ave_set_mac_address,
155362306a36Sopenharmony_ci};
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic int ave_probe(struct platform_device *pdev)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	const struct ave_soc_data *data;
155862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
155962306a36Sopenharmony_ci	char buf[ETHTOOL_FWVERS_LEN];
156062306a36Sopenharmony_ci	struct of_phandle_args args;
156162306a36Sopenharmony_ci	phy_interface_t phy_mode;
156262306a36Sopenharmony_ci	struct ave_private *priv;
156362306a36Sopenharmony_ci	struct net_device *ndev;
156462306a36Sopenharmony_ci	struct device_node *np;
156562306a36Sopenharmony_ci	void __iomem *base;
156662306a36Sopenharmony_ci	const char *name;
156762306a36Sopenharmony_ci	int i, irq, ret;
156862306a36Sopenharmony_ci	u64 dma_mask;
156962306a36Sopenharmony_ci	u32 ave_id;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	data = of_device_get_match_data(dev);
157262306a36Sopenharmony_ci	if (WARN_ON(!data))
157362306a36Sopenharmony_ci		return -EINVAL;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	np = dev->of_node;
157662306a36Sopenharmony_ci	ret = of_get_phy_mode(np, &phy_mode);
157762306a36Sopenharmony_ci	if (ret) {
157862306a36Sopenharmony_ci		dev_err(dev, "phy-mode not found\n");
157962306a36Sopenharmony_ci		return ret;
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
158362306a36Sopenharmony_ci	if (irq < 0)
158462306a36Sopenharmony_ci		return irq;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
158762306a36Sopenharmony_ci	if (IS_ERR(base))
158862306a36Sopenharmony_ci		return PTR_ERR(base);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	ndev = devm_alloc_etherdev(dev, sizeof(struct ave_private));
159162306a36Sopenharmony_ci	if (!ndev) {
159262306a36Sopenharmony_ci		dev_err(dev, "can't allocate ethernet device\n");
159362306a36Sopenharmony_ci		return -ENOMEM;
159462306a36Sopenharmony_ci	}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	ndev->netdev_ops = &ave_netdev_ops;
159762306a36Sopenharmony_ci	ndev->ethtool_ops = &ave_ethtool_ops;
159862306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, dev);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	ndev->features    |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
160162306a36Sopenharmony_ci	ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	ndev->max_mtu = AVE_MAX_ETHFRAME - (ETH_HLEN + ETH_FCS_LEN);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	ret = of_get_ethdev_address(np, ndev);
160662306a36Sopenharmony_ci	if (ret) {
160762306a36Sopenharmony_ci		/* if the mac address is invalid, use random mac address */
160862306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
160962306a36Sopenharmony_ci		dev_warn(dev, "Using random MAC address: %pM\n",
161062306a36Sopenharmony_ci			 ndev->dev_addr);
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	priv = netdev_priv(ndev);
161462306a36Sopenharmony_ci	priv->base = base;
161562306a36Sopenharmony_ci	priv->irq = irq;
161662306a36Sopenharmony_ci	priv->ndev = ndev;
161762306a36Sopenharmony_ci	priv->msg_enable = netif_msg_init(-1, AVE_DEFAULT_MSG_ENABLE);
161862306a36Sopenharmony_ci	priv->phy_mode = phy_mode;
161962306a36Sopenharmony_ci	priv->data = data;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (IS_DESC_64BIT(priv)) {
162262306a36Sopenharmony_ci		priv->desc_size = AVE_DESC_SIZE_64;
162362306a36Sopenharmony_ci		priv->tx.daddr  = AVE_TXDM_64;
162462306a36Sopenharmony_ci		priv->rx.daddr  = AVE_RXDM_64;
162562306a36Sopenharmony_ci		dma_mask = DMA_BIT_MASK(64);
162662306a36Sopenharmony_ci	} else {
162762306a36Sopenharmony_ci		priv->desc_size = AVE_DESC_SIZE_32;
162862306a36Sopenharmony_ci		priv->tx.daddr  = AVE_TXDM_32;
162962306a36Sopenharmony_ci		priv->rx.daddr  = AVE_RXDM_32;
163062306a36Sopenharmony_ci		dma_mask = DMA_BIT_MASK(32);
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci	ret = dma_set_mask(dev, dma_mask);
163362306a36Sopenharmony_ci	if (ret)
163462306a36Sopenharmony_ci		return ret;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	priv->tx.ndesc = AVE_NR_TXDESC;
163762306a36Sopenharmony_ci	priv->rx.ndesc = AVE_NR_RXDESC;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	u64_stats_init(&priv->stats_tx.syncp);
164062306a36Sopenharmony_ci	u64_stats_init(&priv->stats_rx.syncp);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	for (i = 0; i < AVE_MAX_CLKS; i++) {
164362306a36Sopenharmony_ci		name = priv->data->clock_names[i];
164462306a36Sopenharmony_ci		if (!name)
164562306a36Sopenharmony_ci			break;
164662306a36Sopenharmony_ci		priv->clk[i] = devm_clk_get(dev, name);
164762306a36Sopenharmony_ci		if (IS_ERR(priv->clk[i]))
164862306a36Sopenharmony_ci			return PTR_ERR(priv->clk[i]);
164962306a36Sopenharmony_ci		priv->nclks++;
165062306a36Sopenharmony_ci	}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	for (i = 0; i < AVE_MAX_RSTS; i++) {
165362306a36Sopenharmony_ci		name = priv->data->reset_names[i];
165462306a36Sopenharmony_ci		if (!name)
165562306a36Sopenharmony_ci			break;
165662306a36Sopenharmony_ci		priv->rst[i] = devm_reset_control_get_shared(dev, name);
165762306a36Sopenharmony_ci		if (IS_ERR(priv->rst[i]))
165862306a36Sopenharmony_ci			return PTR_ERR(priv->rst[i]);
165962306a36Sopenharmony_ci		priv->nrsts++;
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	ret = of_parse_phandle_with_fixed_args(np,
166362306a36Sopenharmony_ci					       "socionext,syscon-phy-mode",
166462306a36Sopenharmony_ci					       1, 0, &args);
166562306a36Sopenharmony_ci	if (ret) {
166662306a36Sopenharmony_ci		dev_err(dev, "can't get syscon-phy-mode property\n");
166762306a36Sopenharmony_ci		return ret;
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci	priv->regmap = syscon_node_to_regmap(args.np);
167062306a36Sopenharmony_ci	of_node_put(args.np);
167162306a36Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
167262306a36Sopenharmony_ci		dev_err(dev, "can't map syscon-phy-mode\n");
167362306a36Sopenharmony_ci		return PTR_ERR(priv->regmap);
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci	ret = priv->data->get_pinmode(priv, phy_mode, args.args[0]);
167662306a36Sopenharmony_ci	if (ret) {
167762306a36Sopenharmony_ci		dev_err(dev, "invalid phy-mode setting\n");
167862306a36Sopenharmony_ci		return ret;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	priv->mdio = devm_mdiobus_alloc(dev);
168262306a36Sopenharmony_ci	if (!priv->mdio)
168362306a36Sopenharmony_ci		return -ENOMEM;
168462306a36Sopenharmony_ci	priv->mdio->priv = ndev;
168562306a36Sopenharmony_ci	priv->mdio->parent = dev;
168662306a36Sopenharmony_ci	priv->mdio->read = ave_mdiobus_read;
168762306a36Sopenharmony_ci	priv->mdio->write = ave_mdiobus_write;
168862306a36Sopenharmony_ci	priv->mdio->name = "uniphier-mdio";
168962306a36Sopenharmony_ci	snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%x",
169062306a36Sopenharmony_ci		 pdev->name, pdev->id);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/* Register as a NAPI supported driver */
169362306a36Sopenharmony_ci	netif_napi_add(ndev, &priv->napi_rx, ave_napi_poll_rx);
169462306a36Sopenharmony_ci	netif_napi_add_tx(ndev, &priv->napi_tx, ave_napi_poll_tx);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	ret = register_netdev(ndev);
169962306a36Sopenharmony_ci	if (ret) {
170062306a36Sopenharmony_ci		dev_err(dev, "failed to register netdevice\n");
170162306a36Sopenharmony_ci		goto out_del_napi;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	/* get ID and version */
170562306a36Sopenharmony_ci	ave_id = readl(priv->base + AVE_IDR);
170662306a36Sopenharmony_ci	ave_hw_read_version(ndev, buf, sizeof(buf));
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	dev_info(dev, "Socionext %c%c%c%c Ethernet IP %s (irq=%d, phy=%s)\n",
170962306a36Sopenharmony_ci		 (ave_id >> 24) & 0xff, (ave_id >> 16) & 0xff,
171062306a36Sopenharmony_ci		 (ave_id >> 8) & 0xff, (ave_id >> 0) & 0xff,
171162306a36Sopenharmony_ci		 buf, priv->irq, phy_modes(phy_mode));
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return 0;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ciout_del_napi:
171662306a36Sopenharmony_ci	netif_napi_del(&priv->napi_rx);
171762306a36Sopenharmony_ci	netif_napi_del(&priv->napi_tx);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return ret;
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_cistatic int ave_remove(struct platform_device *pdev)
172362306a36Sopenharmony_ci{
172462306a36Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
172562306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	unregister_netdev(ndev);
172862306a36Sopenharmony_ci	netif_napi_del(&priv->napi_rx);
172962306a36Sopenharmony_ci	netif_napi_del(&priv->napi_tx);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	return 0;
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
173562306a36Sopenharmony_cistatic int ave_suspend(struct device *dev)
173662306a36Sopenharmony_ci{
173762306a36Sopenharmony_ci	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
173862306a36Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
173962306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
174062306a36Sopenharmony_ci	int ret = 0;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	if (netif_running(ndev)) {
174362306a36Sopenharmony_ci		ret = ave_stop(ndev);
174462306a36Sopenharmony_ci		netif_device_detach(ndev);
174562306a36Sopenharmony_ci	}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	ave_ethtool_get_wol(ndev, &wol);
174862306a36Sopenharmony_ci	priv->wolopts = wol.wolopts;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return ret;
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic int ave_resume(struct device *dev)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
175662306a36Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
175762306a36Sopenharmony_ci	struct ave_private *priv = netdev_priv(ndev);
175862306a36Sopenharmony_ci	int ret = 0;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	ave_global_reset(ndev);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	ret = phy_init_hw(ndev->phydev);
176362306a36Sopenharmony_ci	if (ret)
176462306a36Sopenharmony_ci		return ret;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	ave_ethtool_get_wol(ndev, &wol);
176762306a36Sopenharmony_ci	wol.wolopts = priv->wolopts;
176862306a36Sopenharmony_ci	__ave_ethtool_set_wol(ndev, &wol);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	if (netif_running(ndev)) {
177162306a36Sopenharmony_ci		ret = ave_open(ndev);
177262306a36Sopenharmony_ci		netif_device_attach(ndev);
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	return ret;
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ave_pm_ops, ave_suspend, ave_resume);
177962306a36Sopenharmony_ci#define AVE_PM_OPS	(&ave_pm_ops)
178062306a36Sopenharmony_ci#else
178162306a36Sopenharmony_ci#define AVE_PM_OPS	NULL
178262306a36Sopenharmony_ci#endif
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic int ave_pro4_get_pinmode(struct ave_private *priv,
178562306a36Sopenharmony_ci				phy_interface_t phy_mode, u32 arg)
178662306a36Sopenharmony_ci{
178762306a36Sopenharmony_ci	if (arg > 0)
178862306a36Sopenharmony_ci		return -EINVAL;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	priv->pinmode_mask = SG_ETPINMODE_RMII(0);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	switch (phy_mode) {
179362306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
179462306a36Sopenharmony_ci		priv->pinmode_val = SG_ETPINMODE_RMII(0);
179562306a36Sopenharmony_ci		break;
179662306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_MII:
179762306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
179862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
179962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
180062306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
180162306a36Sopenharmony_ci		priv->pinmode_val = 0;
180262306a36Sopenharmony_ci		break;
180362306a36Sopenharmony_ci	default:
180462306a36Sopenharmony_ci		return -EINVAL;
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	return 0;
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic int ave_ld11_get_pinmode(struct ave_private *priv,
181162306a36Sopenharmony_ci				phy_interface_t phy_mode, u32 arg)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	if (arg > 0)
181462306a36Sopenharmony_ci		return -EINVAL;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	priv->pinmode_mask = SG_ETPINMODE_EXTPHY | SG_ETPINMODE_RMII(0);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	switch (phy_mode) {
181962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_INTERNAL:
182062306a36Sopenharmony_ci		priv->pinmode_val = 0;
182162306a36Sopenharmony_ci		break;
182262306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
182362306a36Sopenharmony_ci		priv->pinmode_val = SG_ETPINMODE_EXTPHY | SG_ETPINMODE_RMII(0);
182462306a36Sopenharmony_ci		break;
182562306a36Sopenharmony_ci	default:
182662306a36Sopenharmony_ci		return -EINVAL;
182762306a36Sopenharmony_ci	}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	return 0;
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_cistatic int ave_ld20_get_pinmode(struct ave_private *priv,
183362306a36Sopenharmony_ci				phy_interface_t phy_mode, u32 arg)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	if (arg > 0)
183662306a36Sopenharmony_ci		return -EINVAL;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	priv->pinmode_mask = SG_ETPINMODE_RMII(0);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	switch (phy_mode) {
184162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
184262306a36Sopenharmony_ci		priv->pinmode_val = SG_ETPINMODE_RMII(0);
184362306a36Sopenharmony_ci		break;
184462306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
184562306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
184662306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
184762306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
184862306a36Sopenharmony_ci		priv->pinmode_val = 0;
184962306a36Sopenharmony_ci		break;
185062306a36Sopenharmony_ci	default:
185162306a36Sopenharmony_ci		return -EINVAL;
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	return 0;
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_cistatic int ave_pxs3_get_pinmode(struct ave_private *priv,
185862306a36Sopenharmony_ci				phy_interface_t phy_mode, u32 arg)
185962306a36Sopenharmony_ci{
186062306a36Sopenharmony_ci	if (arg > 1)
186162306a36Sopenharmony_ci		return -EINVAL;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	priv->pinmode_mask = SG_ETPINMODE_RMII(arg);
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	switch (phy_mode) {
186662306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
186762306a36Sopenharmony_ci		priv->pinmode_val = SG_ETPINMODE_RMII(arg);
186862306a36Sopenharmony_ci		break;
186962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
187062306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
187162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
187262306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
187362306a36Sopenharmony_ci		priv->pinmode_val = 0;
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci	default:
187662306a36Sopenharmony_ci		return -EINVAL;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	return 0;
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic const struct ave_soc_data ave_pro4_data = {
188362306a36Sopenharmony_ci	.is_desc_64bit = false,
188462306a36Sopenharmony_ci	.clock_names = {
188562306a36Sopenharmony_ci		"gio", "ether", "ether-gb", "ether-phy",
188662306a36Sopenharmony_ci	},
188762306a36Sopenharmony_ci	.reset_names = {
188862306a36Sopenharmony_ci		"gio", "ether",
188962306a36Sopenharmony_ci	},
189062306a36Sopenharmony_ci	.get_pinmode = ave_pro4_get_pinmode,
189162306a36Sopenharmony_ci};
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_cistatic const struct ave_soc_data ave_pxs2_data = {
189462306a36Sopenharmony_ci	.is_desc_64bit = false,
189562306a36Sopenharmony_ci	.clock_names = {
189662306a36Sopenharmony_ci		"ether",
189762306a36Sopenharmony_ci	},
189862306a36Sopenharmony_ci	.reset_names = {
189962306a36Sopenharmony_ci		"ether",
190062306a36Sopenharmony_ci	},
190162306a36Sopenharmony_ci	.get_pinmode = ave_pro4_get_pinmode,
190262306a36Sopenharmony_ci};
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_cistatic const struct ave_soc_data ave_ld11_data = {
190562306a36Sopenharmony_ci	.is_desc_64bit = false,
190662306a36Sopenharmony_ci	.clock_names = {
190762306a36Sopenharmony_ci		"ether",
190862306a36Sopenharmony_ci	},
190962306a36Sopenharmony_ci	.reset_names = {
191062306a36Sopenharmony_ci		"ether",
191162306a36Sopenharmony_ci	},
191262306a36Sopenharmony_ci	.get_pinmode = ave_ld11_get_pinmode,
191362306a36Sopenharmony_ci};
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cistatic const struct ave_soc_data ave_ld20_data = {
191662306a36Sopenharmony_ci	.is_desc_64bit = true,
191762306a36Sopenharmony_ci	.clock_names = {
191862306a36Sopenharmony_ci		"ether",
191962306a36Sopenharmony_ci	},
192062306a36Sopenharmony_ci	.reset_names = {
192162306a36Sopenharmony_ci		"ether",
192262306a36Sopenharmony_ci	},
192362306a36Sopenharmony_ci	.get_pinmode = ave_ld20_get_pinmode,
192462306a36Sopenharmony_ci};
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_cistatic const struct ave_soc_data ave_pxs3_data = {
192762306a36Sopenharmony_ci	.is_desc_64bit = false,
192862306a36Sopenharmony_ci	.clock_names = {
192962306a36Sopenharmony_ci		"ether",
193062306a36Sopenharmony_ci	},
193162306a36Sopenharmony_ci	.reset_names = {
193262306a36Sopenharmony_ci		"ether",
193362306a36Sopenharmony_ci	},
193462306a36Sopenharmony_ci	.get_pinmode = ave_pxs3_get_pinmode,
193562306a36Sopenharmony_ci};
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic const struct ave_soc_data ave_nx1_data = {
193862306a36Sopenharmony_ci	.is_desc_64bit = true,
193962306a36Sopenharmony_ci	.clock_names = {
194062306a36Sopenharmony_ci		"ether",
194162306a36Sopenharmony_ci	},
194262306a36Sopenharmony_ci	.reset_names = {
194362306a36Sopenharmony_ci		"ether",
194462306a36Sopenharmony_ci	},
194562306a36Sopenharmony_ci	.get_pinmode = ave_pxs3_get_pinmode,
194662306a36Sopenharmony_ci};
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_cistatic const struct of_device_id of_ave_match[] = {
194962306a36Sopenharmony_ci	{
195062306a36Sopenharmony_ci		.compatible = "socionext,uniphier-pro4-ave4",
195162306a36Sopenharmony_ci		.data = &ave_pro4_data,
195262306a36Sopenharmony_ci	},
195362306a36Sopenharmony_ci	{
195462306a36Sopenharmony_ci		.compatible = "socionext,uniphier-pxs2-ave4",
195562306a36Sopenharmony_ci		.data = &ave_pxs2_data,
195662306a36Sopenharmony_ci	},
195762306a36Sopenharmony_ci	{
195862306a36Sopenharmony_ci		.compatible = "socionext,uniphier-ld11-ave4",
195962306a36Sopenharmony_ci		.data = &ave_ld11_data,
196062306a36Sopenharmony_ci	},
196162306a36Sopenharmony_ci	{
196262306a36Sopenharmony_ci		.compatible = "socionext,uniphier-ld20-ave4",
196362306a36Sopenharmony_ci		.data = &ave_ld20_data,
196462306a36Sopenharmony_ci	},
196562306a36Sopenharmony_ci	{
196662306a36Sopenharmony_ci		.compatible = "socionext,uniphier-pxs3-ave4",
196762306a36Sopenharmony_ci		.data = &ave_pxs3_data,
196862306a36Sopenharmony_ci	},
196962306a36Sopenharmony_ci	{
197062306a36Sopenharmony_ci		.compatible = "socionext,uniphier-nx1-ave4",
197162306a36Sopenharmony_ci		.data = &ave_nx1_data,
197262306a36Sopenharmony_ci	},
197362306a36Sopenharmony_ci	{ /* Sentinel */ }
197462306a36Sopenharmony_ci};
197562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_ave_match);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_cistatic struct platform_driver ave_driver = {
197862306a36Sopenharmony_ci	.probe  = ave_probe,
197962306a36Sopenharmony_ci	.remove = ave_remove,
198062306a36Sopenharmony_ci	.driver	= {
198162306a36Sopenharmony_ci		.name = "ave",
198262306a36Sopenharmony_ci		.pm   = AVE_PM_OPS,
198362306a36Sopenharmony_ci		.of_match_table	= of_ave_match,
198462306a36Sopenharmony_ci	},
198562306a36Sopenharmony_ci};
198662306a36Sopenharmony_cimodule_platform_driver(ave_driver);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ciMODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
198962306a36Sopenharmony_ciMODULE_DESCRIPTION("Socionext UniPhier AVE ethernet driver");
199062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1991