162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*  SuperH Ethernet device driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2014 Renesas Electronics Corporation
562306a36Sopenharmony_ci *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
662306a36Sopenharmony_ci *  Copyright (C) 2008-2014 Renesas Solutions Corp.
762306a36Sopenharmony_ci *  Copyright (C) 2013-2017 Cogent Embedded, Inc.
862306a36Sopenharmony_ci *  Copyright (C) 2014 Codethink Limited
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1662306a36Sopenharmony_ci#include <linux/etherdevice.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/mdio-bitbang.h>
2062306a36Sopenharmony_ci#include <linux/netdevice.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/of_net.h>
2362306a36Sopenharmony_ci#include <linux/phy.h>
2462306a36Sopenharmony_ci#include <linux/cache.h>
2562306a36Sopenharmony_ci#include <linux/io.h>
2662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <linux/ethtool.h>
2962306a36Sopenharmony_ci#include <linux/if_vlan.h>
3062306a36Sopenharmony_ci#include <linux/sh_eth.h>
3162306a36Sopenharmony_ci#include <linux/of_mdio.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "sh_eth.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define SH_ETH_DEF_MSG_ENABLE \
3662306a36Sopenharmony_ci		(NETIF_MSG_LINK	| \
3762306a36Sopenharmony_ci		NETIF_MSG_TIMER	| \
3862306a36Sopenharmony_ci		NETIF_MSG_RX_ERR| \
3962306a36Sopenharmony_ci		NETIF_MSG_TX_ERR)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define SH_ETH_OFFSET_INVALID	((u16)~0)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define SH_ETH_OFFSET_DEFAULTS			\
4462306a36Sopenharmony_ci	[0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* use some intentionally tricky logic here to initialize the whole struct to
4762306a36Sopenharmony_ci * 0xffff, but then override certain fields, requiring us to indicate that we
4862306a36Sopenharmony_ci * "know" that there are overrides in this structure, and we'll need to disable
4962306a36Sopenharmony_ci * that warning from W=1 builds. GCC has supported this option since 4.2.X, but
5062306a36Sopenharmony_ci * the macros available to do this only define GCC 8.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_ci__diag_push();
5362306a36Sopenharmony_ci__diag_ignore(GCC, 8, "-Woverride-init",
5462306a36Sopenharmony_ci	      "logic to initialize all and then override some is OK");
5562306a36Sopenharmony_cistatic const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
5662306a36Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	[EDSR]		= 0x0000,
5962306a36Sopenharmony_ci	[EDMR]		= 0x0400,
6062306a36Sopenharmony_ci	[EDTRR]		= 0x0408,
6162306a36Sopenharmony_ci	[EDRRR]		= 0x0410,
6262306a36Sopenharmony_ci	[EESR]		= 0x0428,
6362306a36Sopenharmony_ci	[EESIPR]	= 0x0430,
6462306a36Sopenharmony_ci	[TDLAR]		= 0x0010,
6562306a36Sopenharmony_ci	[TDFAR]		= 0x0014,
6662306a36Sopenharmony_ci	[TDFXR]		= 0x0018,
6762306a36Sopenharmony_ci	[TDFFR]		= 0x001c,
6862306a36Sopenharmony_ci	[RDLAR]		= 0x0030,
6962306a36Sopenharmony_ci	[RDFAR]		= 0x0034,
7062306a36Sopenharmony_ci	[RDFXR]		= 0x0038,
7162306a36Sopenharmony_ci	[RDFFR]		= 0x003c,
7262306a36Sopenharmony_ci	[TRSCER]	= 0x0438,
7362306a36Sopenharmony_ci	[RMFCR]		= 0x0440,
7462306a36Sopenharmony_ci	[TFTR]		= 0x0448,
7562306a36Sopenharmony_ci	[FDR]		= 0x0450,
7662306a36Sopenharmony_ci	[RMCR]		= 0x0458,
7762306a36Sopenharmony_ci	[RPADIR]	= 0x0460,
7862306a36Sopenharmony_ci	[FCFTR]		= 0x0468,
7962306a36Sopenharmony_ci	[CSMR]		= 0x04E4,
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	[ECMR]		= 0x0500,
8262306a36Sopenharmony_ci	[ECSR]		= 0x0510,
8362306a36Sopenharmony_ci	[ECSIPR]	= 0x0518,
8462306a36Sopenharmony_ci	[PIR]		= 0x0520,
8562306a36Sopenharmony_ci	[PSR]		= 0x0528,
8662306a36Sopenharmony_ci	[PIPR]		= 0x052c,
8762306a36Sopenharmony_ci	[RFLR]		= 0x0508,
8862306a36Sopenharmony_ci	[APR]		= 0x0554,
8962306a36Sopenharmony_ci	[MPR]		= 0x0558,
9062306a36Sopenharmony_ci	[PFTCR]		= 0x055c,
9162306a36Sopenharmony_ci	[PFRCR]		= 0x0560,
9262306a36Sopenharmony_ci	[TPAUSER]	= 0x0564,
9362306a36Sopenharmony_ci	[GECMR]		= 0x05b0,
9462306a36Sopenharmony_ci	[BCULR]		= 0x05b4,
9562306a36Sopenharmony_ci	[MAHR]		= 0x05c0,
9662306a36Sopenharmony_ci	[MALR]		= 0x05c8,
9762306a36Sopenharmony_ci	[TROCR]		= 0x0700,
9862306a36Sopenharmony_ci	[CDCR]		= 0x0708,
9962306a36Sopenharmony_ci	[LCCR]		= 0x0710,
10062306a36Sopenharmony_ci	[CEFCR]		= 0x0740,
10162306a36Sopenharmony_ci	[FRECR]		= 0x0748,
10262306a36Sopenharmony_ci	[TSFRCR]	= 0x0750,
10362306a36Sopenharmony_ci	[TLFRCR]	= 0x0758,
10462306a36Sopenharmony_ci	[RFCR]		= 0x0760,
10562306a36Sopenharmony_ci	[CERCR]		= 0x0768,
10662306a36Sopenharmony_ci	[CEECR]		= 0x0770,
10762306a36Sopenharmony_ci	[MAFCR]		= 0x0778,
10862306a36Sopenharmony_ci	[RMII_MII]	= 0x0790,
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	[ARSTR]		= 0x0000,
11162306a36Sopenharmony_ci	[TSU_CTRST]	= 0x0004,
11262306a36Sopenharmony_ci	[TSU_FWEN0]	= 0x0010,
11362306a36Sopenharmony_ci	[TSU_FWEN1]	= 0x0014,
11462306a36Sopenharmony_ci	[TSU_FCM]	= 0x0018,
11562306a36Sopenharmony_ci	[TSU_BSYSL0]	= 0x0020,
11662306a36Sopenharmony_ci	[TSU_BSYSL1]	= 0x0024,
11762306a36Sopenharmony_ci	[TSU_PRISL0]	= 0x0028,
11862306a36Sopenharmony_ci	[TSU_PRISL1]	= 0x002c,
11962306a36Sopenharmony_ci	[TSU_FWSL0]	= 0x0030,
12062306a36Sopenharmony_ci	[TSU_FWSL1]	= 0x0034,
12162306a36Sopenharmony_ci	[TSU_FWSLC]	= 0x0038,
12262306a36Sopenharmony_ci	[TSU_QTAGM0]	= 0x0040,
12362306a36Sopenharmony_ci	[TSU_QTAGM1]	= 0x0044,
12462306a36Sopenharmony_ci	[TSU_FWSR]	= 0x0050,
12562306a36Sopenharmony_ci	[TSU_FWINMK]	= 0x0054,
12662306a36Sopenharmony_ci	[TSU_ADQT0]	= 0x0048,
12762306a36Sopenharmony_ci	[TSU_ADQT1]	= 0x004c,
12862306a36Sopenharmony_ci	[TSU_VTAG0]	= 0x0058,
12962306a36Sopenharmony_ci	[TSU_VTAG1]	= 0x005c,
13062306a36Sopenharmony_ci	[TSU_ADSBSY]	= 0x0060,
13162306a36Sopenharmony_ci	[TSU_TEN]	= 0x0064,
13262306a36Sopenharmony_ci	[TSU_POST1]	= 0x0070,
13362306a36Sopenharmony_ci	[TSU_POST2]	= 0x0074,
13462306a36Sopenharmony_ci	[TSU_POST3]	= 0x0078,
13562306a36Sopenharmony_ci	[TSU_POST4]	= 0x007c,
13662306a36Sopenharmony_ci	[TSU_ADRH0]	= 0x0100,
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	[TXNLCR0]	= 0x0080,
13962306a36Sopenharmony_ci	[TXALCR0]	= 0x0084,
14062306a36Sopenharmony_ci	[RXNLCR0]	= 0x0088,
14162306a36Sopenharmony_ci	[RXALCR0]	= 0x008c,
14262306a36Sopenharmony_ci	[FWNLCR0]	= 0x0090,
14362306a36Sopenharmony_ci	[FWALCR0]	= 0x0094,
14462306a36Sopenharmony_ci	[TXNLCR1]	= 0x00a0,
14562306a36Sopenharmony_ci	[TXALCR1]	= 0x00a4,
14662306a36Sopenharmony_ci	[RXNLCR1]	= 0x00a8,
14762306a36Sopenharmony_ci	[RXALCR1]	= 0x00ac,
14862306a36Sopenharmony_ci	[FWNLCR1]	= 0x00b0,
14962306a36Sopenharmony_ci	[FWALCR1]	= 0x00b4,
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
15362306a36Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	[ECMR]		= 0x0300,
15662306a36Sopenharmony_ci	[RFLR]		= 0x0308,
15762306a36Sopenharmony_ci	[ECSR]		= 0x0310,
15862306a36Sopenharmony_ci	[ECSIPR]	= 0x0318,
15962306a36Sopenharmony_ci	[PIR]		= 0x0320,
16062306a36Sopenharmony_ci	[PSR]		= 0x0328,
16162306a36Sopenharmony_ci	[RDMLR]		= 0x0340,
16262306a36Sopenharmony_ci	[IPGR]		= 0x0350,
16362306a36Sopenharmony_ci	[APR]		= 0x0354,
16462306a36Sopenharmony_ci	[MPR]		= 0x0358,
16562306a36Sopenharmony_ci	[RFCF]		= 0x0360,
16662306a36Sopenharmony_ci	[TPAUSER]	= 0x0364,
16762306a36Sopenharmony_ci	[TPAUSECR]	= 0x0368,
16862306a36Sopenharmony_ci	[MAHR]		= 0x03c0,
16962306a36Sopenharmony_ci	[MALR]		= 0x03c8,
17062306a36Sopenharmony_ci	[TROCR]		= 0x03d0,
17162306a36Sopenharmony_ci	[CDCR]		= 0x03d4,
17262306a36Sopenharmony_ci	[LCCR]		= 0x03d8,
17362306a36Sopenharmony_ci	[CNDCR]		= 0x03dc,
17462306a36Sopenharmony_ci	[CEFCR]		= 0x03e4,
17562306a36Sopenharmony_ci	[FRECR]		= 0x03e8,
17662306a36Sopenharmony_ci	[TSFRCR]	= 0x03ec,
17762306a36Sopenharmony_ci	[TLFRCR]	= 0x03f0,
17862306a36Sopenharmony_ci	[RFCR]		= 0x03f4,
17962306a36Sopenharmony_ci	[MAFCR]		= 0x03f8,
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	[EDMR]		= 0x0200,
18262306a36Sopenharmony_ci	[EDTRR]		= 0x0208,
18362306a36Sopenharmony_ci	[EDRRR]		= 0x0210,
18462306a36Sopenharmony_ci	[TDLAR]		= 0x0218,
18562306a36Sopenharmony_ci	[RDLAR]		= 0x0220,
18662306a36Sopenharmony_ci	[EESR]		= 0x0228,
18762306a36Sopenharmony_ci	[EESIPR]	= 0x0230,
18862306a36Sopenharmony_ci	[TRSCER]	= 0x0238,
18962306a36Sopenharmony_ci	[RMFCR]		= 0x0240,
19062306a36Sopenharmony_ci	[TFTR]		= 0x0248,
19162306a36Sopenharmony_ci	[FDR]		= 0x0250,
19262306a36Sopenharmony_ci	[RMCR]		= 0x0258,
19362306a36Sopenharmony_ci	[TFUCR]		= 0x0264,
19462306a36Sopenharmony_ci	[RFOCR]		= 0x0268,
19562306a36Sopenharmony_ci	[RMIIMODE]      = 0x026c,
19662306a36Sopenharmony_ci	[FCFTR]		= 0x0270,
19762306a36Sopenharmony_ci	[TRIMD]		= 0x027c,
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
20162306a36Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	[ECMR]		= 0x0100,
20462306a36Sopenharmony_ci	[RFLR]		= 0x0108,
20562306a36Sopenharmony_ci	[ECSR]		= 0x0110,
20662306a36Sopenharmony_ci	[ECSIPR]	= 0x0118,
20762306a36Sopenharmony_ci	[PIR]		= 0x0120,
20862306a36Sopenharmony_ci	[PSR]		= 0x0128,
20962306a36Sopenharmony_ci	[RDMLR]		= 0x0140,
21062306a36Sopenharmony_ci	[IPGR]		= 0x0150,
21162306a36Sopenharmony_ci	[APR]		= 0x0154,
21262306a36Sopenharmony_ci	[MPR]		= 0x0158,
21362306a36Sopenharmony_ci	[TPAUSER]	= 0x0164,
21462306a36Sopenharmony_ci	[RFCF]		= 0x0160,
21562306a36Sopenharmony_ci	[TPAUSECR]	= 0x0168,
21662306a36Sopenharmony_ci	[BCFRR]		= 0x016c,
21762306a36Sopenharmony_ci	[MAHR]		= 0x01c0,
21862306a36Sopenharmony_ci	[MALR]		= 0x01c8,
21962306a36Sopenharmony_ci	[TROCR]		= 0x01d0,
22062306a36Sopenharmony_ci	[CDCR]		= 0x01d4,
22162306a36Sopenharmony_ci	[LCCR]		= 0x01d8,
22262306a36Sopenharmony_ci	[CNDCR]		= 0x01dc,
22362306a36Sopenharmony_ci	[CEFCR]		= 0x01e4,
22462306a36Sopenharmony_ci	[FRECR]		= 0x01e8,
22562306a36Sopenharmony_ci	[TSFRCR]	= 0x01ec,
22662306a36Sopenharmony_ci	[TLFRCR]	= 0x01f0,
22762306a36Sopenharmony_ci	[RFCR]		= 0x01f4,
22862306a36Sopenharmony_ci	[MAFCR]		= 0x01f8,
22962306a36Sopenharmony_ci	[RTRATE]	= 0x01fc,
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	[EDMR]		= 0x0000,
23262306a36Sopenharmony_ci	[EDTRR]		= 0x0008,
23362306a36Sopenharmony_ci	[EDRRR]		= 0x0010,
23462306a36Sopenharmony_ci	[TDLAR]		= 0x0018,
23562306a36Sopenharmony_ci	[RDLAR]		= 0x0020,
23662306a36Sopenharmony_ci	[EESR]		= 0x0028,
23762306a36Sopenharmony_ci	[EESIPR]	= 0x0030,
23862306a36Sopenharmony_ci	[TRSCER]	= 0x0038,
23962306a36Sopenharmony_ci	[RMFCR]		= 0x0040,
24062306a36Sopenharmony_ci	[TFTR]		= 0x0048,
24162306a36Sopenharmony_ci	[FDR]		= 0x0050,
24262306a36Sopenharmony_ci	[RMCR]		= 0x0058,
24362306a36Sopenharmony_ci	[TFUCR]		= 0x0064,
24462306a36Sopenharmony_ci	[RFOCR]		= 0x0068,
24562306a36Sopenharmony_ci	[FCFTR]		= 0x0070,
24662306a36Sopenharmony_ci	[RPADIR]	= 0x0078,
24762306a36Sopenharmony_ci	[TRIMD]		= 0x007c,
24862306a36Sopenharmony_ci	[RBWAR]		= 0x00c8,
24962306a36Sopenharmony_ci	[RDFAR]		= 0x00cc,
25062306a36Sopenharmony_ci	[TBRAR]		= 0x00d4,
25162306a36Sopenharmony_ci	[TDFAR]		= 0x00d8,
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
25562306a36Sopenharmony_ci	SH_ETH_OFFSET_DEFAULTS,
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	[EDMR]		= 0x0000,
25862306a36Sopenharmony_ci	[EDTRR]		= 0x0004,
25962306a36Sopenharmony_ci	[EDRRR]		= 0x0008,
26062306a36Sopenharmony_ci	[TDLAR]		= 0x000c,
26162306a36Sopenharmony_ci	[RDLAR]		= 0x0010,
26262306a36Sopenharmony_ci	[EESR]		= 0x0014,
26362306a36Sopenharmony_ci	[EESIPR]	= 0x0018,
26462306a36Sopenharmony_ci	[TRSCER]	= 0x001c,
26562306a36Sopenharmony_ci	[RMFCR]		= 0x0020,
26662306a36Sopenharmony_ci	[TFTR]		= 0x0024,
26762306a36Sopenharmony_ci	[FDR]		= 0x0028,
26862306a36Sopenharmony_ci	[RMCR]		= 0x002c,
26962306a36Sopenharmony_ci	[EDOCR]		= 0x0030,
27062306a36Sopenharmony_ci	[FCFTR]		= 0x0034,
27162306a36Sopenharmony_ci	[RPADIR]	= 0x0038,
27262306a36Sopenharmony_ci	[TRIMD]		= 0x003c,
27362306a36Sopenharmony_ci	[RBWAR]		= 0x0040,
27462306a36Sopenharmony_ci	[RDFAR]		= 0x0044,
27562306a36Sopenharmony_ci	[TBRAR]		= 0x004c,
27662306a36Sopenharmony_ci	[TDFAR]		= 0x0050,
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	[ECMR]		= 0x0160,
27962306a36Sopenharmony_ci	[ECSR]		= 0x0164,
28062306a36Sopenharmony_ci	[ECSIPR]	= 0x0168,
28162306a36Sopenharmony_ci	[PIR]		= 0x016c,
28262306a36Sopenharmony_ci	[MAHR]		= 0x0170,
28362306a36Sopenharmony_ci	[MALR]		= 0x0174,
28462306a36Sopenharmony_ci	[RFLR]		= 0x0178,
28562306a36Sopenharmony_ci	[PSR]		= 0x017c,
28662306a36Sopenharmony_ci	[TROCR]		= 0x0180,
28762306a36Sopenharmony_ci	[CDCR]		= 0x0184,
28862306a36Sopenharmony_ci	[LCCR]		= 0x0188,
28962306a36Sopenharmony_ci	[CNDCR]		= 0x018c,
29062306a36Sopenharmony_ci	[CEFCR]		= 0x0194,
29162306a36Sopenharmony_ci	[FRECR]		= 0x0198,
29262306a36Sopenharmony_ci	[TSFRCR]	= 0x019c,
29362306a36Sopenharmony_ci	[TLFRCR]	= 0x01a0,
29462306a36Sopenharmony_ci	[RFCR]		= 0x01a4,
29562306a36Sopenharmony_ci	[MAFCR]		= 0x01a8,
29662306a36Sopenharmony_ci	[IPGR]		= 0x01b4,
29762306a36Sopenharmony_ci	[APR]		= 0x01b8,
29862306a36Sopenharmony_ci	[MPR]		= 0x01bc,
29962306a36Sopenharmony_ci	[TPAUSER]	= 0x01c4,
30062306a36Sopenharmony_ci	[BCFR]		= 0x01cc,
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	[ARSTR]		= 0x0000,
30362306a36Sopenharmony_ci	[TSU_CTRST]	= 0x0004,
30462306a36Sopenharmony_ci	[TSU_FWEN0]	= 0x0010,
30562306a36Sopenharmony_ci	[TSU_FWEN1]	= 0x0014,
30662306a36Sopenharmony_ci	[TSU_FCM]	= 0x0018,
30762306a36Sopenharmony_ci	[TSU_BSYSL0]	= 0x0020,
30862306a36Sopenharmony_ci	[TSU_BSYSL1]	= 0x0024,
30962306a36Sopenharmony_ci	[TSU_PRISL0]	= 0x0028,
31062306a36Sopenharmony_ci	[TSU_PRISL1]	= 0x002c,
31162306a36Sopenharmony_ci	[TSU_FWSL0]	= 0x0030,
31262306a36Sopenharmony_ci	[TSU_FWSL1]	= 0x0034,
31362306a36Sopenharmony_ci	[TSU_FWSLC]	= 0x0038,
31462306a36Sopenharmony_ci	[TSU_QTAGM0]	= 0x0040,
31562306a36Sopenharmony_ci	[TSU_QTAGM1]	= 0x0044,
31662306a36Sopenharmony_ci	[TSU_ADQT0]	= 0x0048,
31762306a36Sopenharmony_ci	[TSU_ADQT1]	= 0x004c,
31862306a36Sopenharmony_ci	[TSU_FWSR]	= 0x0050,
31962306a36Sopenharmony_ci	[TSU_FWINMK]	= 0x0054,
32062306a36Sopenharmony_ci	[TSU_ADSBSY]	= 0x0060,
32162306a36Sopenharmony_ci	[TSU_TEN]	= 0x0064,
32262306a36Sopenharmony_ci	[TSU_POST1]	= 0x0070,
32362306a36Sopenharmony_ci	[TSU_POST2]	= 0x0074,
32462306a36Sopenharmony_ci	[TSU_POST3]	= 0x0078,
32562306a36Sopenharmony_ci	[TSU_POST4]	= 0x007c,
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	[TXNLCR0]	= 0x0080,
32862306a36Sopenharmony_ci	[TXALCR0]	= 0x0084,
32962306a36Sopenharmony_ci	[RXNLCR0]	= 0x0088,
33062306a36Sopenharmony_ci	[RXALCR0]	= 0x008c,
33162306a36Sopenharmony_ci	[FWNLCR0]	= 0x0090,
33262306a36Sopenharmony_ci	[FWALCR0]	= 0x0094,
33362306a36Sopenharmony_ci	[TXNLCR1]	= 0x00a0,
33462306a36Sopenharmony_ci	[TXALCR1]	= 0x00a4,
33562306a36Sopenharmony_ci	[RXNLCR1]	= 0x00a8,
33662306a36Sopenharmony_ci	[RXALCR1]	= 0x00ac,
33762306a36Sopenharmony_ci	[FWNLCR1]	= 0x00b0,
33862306a36Sopenharmony_ci	[FWALCR1]	= 0x00b4,
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	[TSU_ADRH0]	= 0x0100,
34162306a36Sopenharmony_ci};
34262306a36Sopenharmony_ci__diag_pop();
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev);
34562306a36Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic void sh_eth_write(struct net_device *ndev, u32 data, int enum_index)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
35062306a36Sopenharmony_ci	u16 offset = mdp->reg_offset[enum_index];
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
35362306a36Sopenharmony_ci		return;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	iowrite32(data, mdp->addr + offset);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic u32 sh_eth_read(struct net_device *ndev, int enum_index)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
36162306a36Sopenharmony_ci	u16 offset = mdp->reg_offset[enum_index];
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
36462306a36Sopenharmony_ci		return ~0U;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return ioread32(mdp->addr + offset);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear,
37062306a36Sopenharmony_ci			  u32 set)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	sh_eth_write(ndev, (sh_eth_read(ndev, enum_index) & ~clear) | set,
37362306a36Sopenharmony_ci		     enum_index);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic u16 sh_eth_tsu_get_offset(struct sh_eth_private *mdp, int enum_index)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	return mdp->reg_offset[enum_index];
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data,
38262306a36Sopenharmony_ci			     int enum_index)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u16 offset = sh_eth_tsu_get_offset(mdp, enum_index);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
38762306a36Sopenharmony_ci		return;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	iowrite32(data, mdp->tsu_addr + offset);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	u16 offset = sh_eth_tsu_get_offset(mdp, enum_index);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
39762306a36Sopenharmony_ci		return ~0U;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return ioread32(mdp->tsu_addr + offset);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void sh_eth_soft_swap(char *src, int len)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
40562306a36Sopenharmony_ci	u32 *p = (u32 *)src;
40662306a36Sopenharmony_ci	u32 *maxp = p + DIV_ROUND_UP(len, sizeof(u32));
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	for (; p < maxp; p++)
40962306a36Sopenharmony_ci		*p = swab32(*p);
41062306a36Sopenharmony_ci#endif
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic void sh_eth_select_mii(struct net_device *ndev)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
41662306a36Sopenharmony_ci	u32 value;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	switch (mdp->phy_interface) {
41962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII ... PHY_INTERFACE_MODE_RGMII_TXID:
42062306a36Sopenharmony_ci		value = 0x3;
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_GMII:
42362306a36Sopenharmony_ci		value = 0x2;
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_MII:
42662306a36Sopenharmony_ci		value = 0x1;
42762306a36Sopenharmony_ci		break;
42862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
42962306a36Sopenharmony_ci		value = 0x0;
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	default:
43262306a36Sopenharmony_ci		netdev_warn(ndev,
43362306a36Sopenharmony_ci			    "PHY interface mode was not setup. Set to MII.\n");
43462306a36Sopenharmony_ci		value = 0x1;
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	sh_eth_write(ndev, value, RMII_MII);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic void sh_eth_set_duplex(struct net_device *ndev)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_DM, mdp->duplex ? ECMR_DM : 0);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void sh_eth_chip_reset(struct net_device *ndev)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* reset device */
45362306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, ARSTR_ARST, ARSTR);
45462306a36Sopenharmony_ci	mdelay(1);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int sh_eth_soft_reset(struct net_device *ndev)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, EDMR_SRST_ETHER);
46062306a36Sopenharmony_ci	mdelay(3);
46162306a36Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, 0);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int sh_eth_check_soft_reset(struct net_device *ndev)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	int cnt;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	for (cnt = 100; cnt > 0; cnt--) {
47162306a36Sopenharmony_ci		if (!(sh_eth_read(ndev, EDMR) & EDMR_SRST_GETHER))
47262306a36Sopenharmony_ci			return 0;
47362306a36Sopenharmony_ci		mdelay(1);
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	netdev_err(ndev, "Device reset failed\n");
47762306a36Sopenharmony_ci	return -ETIMEDOUT;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int sh_eth_soft_reset_gether(struct net_device *ndev)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
48362306a36Sopenharmony_ci	int ret;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	sh_eth_write(ndev, EDSR_ENALL, EDSR);
48662306a36Sopenharmony_ci	sh_eth_modify(ndev, EDMR, EDMR_SRST_GETHER, EDMR_SRST_GETHER);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	ret = sh_eth_check_soft_reset(ndev);
48962306a36Sopenharmony_ci	if (ret)
49062306a36Sopenharmony_ci		return ret;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Table Init */
49362306a36Sopenharmony_ci	sh_eth_write(ndev, 0, TDLAR);
49462306a36Sopenharmony_ci	sh_eth_write(ndev, 0, TDFAR);
49562306a36Sopenharmony_ci	sh_eth_write(ndev, 0, TDFXR);
49662306a36Sopenharmony_ci	sh_eth_write(ndev, 0, TDFFR);
49762306a36Sopenharmony_ci	sh_eth_write(ndev, 0, RDLAR);
49862306a36Sopenharmony_ci	sh_eth_write(ndev, 0, RDFAR);
49962306a36Sopenharmony_ci	sh_eth_write(ndev, 0, RDFXR);
50062306a36Sopenharmony_ci	sh_eth_write(ndev, 0, RDFFR);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/* Reset HW CRC register */
50362306a36Sopenharmony_ci	if (mdp->cd->csmr)
50462306a36Sopenharmony_ci		sh_eth_write(ndev, 0, CSMR);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Select MII mode */
50762306a36Sopenharmony_ci	if (mdp->cd->select_mii)
50862306a36Sopenharmony_ci		sh_eth_select_mii(ndev);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	return ret;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic void sh_eth_set_rate_gether(struct net_device *ndev)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (WARN_ON(!mdp->cd->gecmr))
51862306a36Sopenharmony_ci		return;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	switch (mdp->speed) {
52162306a36Sopenharmony_ci	case 10: /* 10BASE */
52262306a36Sopenharmony_ci		sh_eth_write(ndev, GECMR_10, GECMR);
52362306a36Sopenharmony_ci		break;
52462306a36Sopenharmony_ci	case 100:/* 100BASE */
52562306a36Sopenharmony_ci		sh_eth_write(ndev, GECMR_100, GECMR);
52662306a36Sopenharmony_ci		break;
52762306a36Sopenharmony_ci	case 1000: /* 1000BASE */
52862306a36Sopenharmony_ci		sh_eth_write(ndev, GECMR_1000, GECMR);
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci#ifdef CONFIG_OF
53462306a36Sopenharmony_ci/* R7S72100 */
53562306a36Sopenharmony_cistatic struct sh_eth_cpu_data r7s72100_data = {
53662306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
53962306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
54462306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD,
54562306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_ICDIP,
54662306a36Sopenharmony_ci	.eesipr_value	= EESIPR_TWB1IP | EESIPR_TWBIP | EESIPR_TC1IP |
54762306a36Sopenharmony_ci			  EESIPR_TABTIP | EESIPR_RABTIP | EESIPR_RFCOFIP |
54862306a36Sopenharmony_ci			  EESIPR_ECIIP |
54962306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
55062306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
55162306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
55262306a36Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
55362306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
55662306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
55762306a36Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
55862306a36Sopenharmony_ci			  EESR_TDE,
55962306a36Sopenharmony_ci	.fdr_value	= 0x0000070f,
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	.trscer_err_mask = TRSCER_RMAFCE | TRSCER_RRFCE,
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	.no_psr		= 1,
56462306a36Sopenharmony_ci	.apr		= 1,
56562306a36Sopenharmony_ci	.mpr		= 1,
56662306a36Sopenharmony_ci	.tpauser	= 1,
56762306a36Sopenharmony_ci	.hw_swap	= 1,
56862306a36Sopenharmony_ci	.rpadir		= 1,
56962306a36Sopenharmony_ci	.no_trimd	= 1,
57062306a36Sopenharmony_ci	.no_ade		= 1,
57162306a36Sopenharmony_ci	.xdfar_rw	= 1,
57262306a36Sopenharmony_ci	.csmr		= 1,
57362306a36Sopenharmony_ci	.rx_csum	= 1,
57462306a36Sopenharmony_ci	.tsu		= 1,
57562306a36Sopenharmony_ci	.no_tx_cntrs	= 1,
57662306a36Sopenharmony_ci};
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void sh_eth_chip_reset_r8a7740(struct net_device *ndev)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	sh_eth_chip_reset(ndev);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	sh_eth_select_mii(ndev);
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci/* R8A7740 */
58662306a36Sopenharmony_cistatic struct sh_eth_cpu_data r8a7740_data = {
58762306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset_r8a7740,
59062306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
59162306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
59662306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
59762306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
59862306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
59962306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
60062306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
60162306a36Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
60262306a36Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
60362306a36Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
60462306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
60562306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
60862306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
60962306a36Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
61062306a36Sopenharmony_ci			  EESR_TDE,
61162306a36Sopenharmony_ci	.fdr_value	= 0x0000070f,
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	.apr		= 1,
61462306a36Sopenharmony_ci	.mpr		= 1,
61562306a36Sopenharmony_ci	.tpauser	= 1,
61662306a36Sopenharmony_ci	.gecmr		= 1,
61762306a36Sopenharmony_ci	.bculr		= 1,
61862306a36Sopenharmony_ci	.hw_swap	= 1,
61962306a36Sopenharmony_ci	.rpadir		= 1,
62062306a36Sopenharmony_ci	.no_trimd	= 1,
62162306a36Sopenharmony_ci	.no_ade		= 1,
62262306a36Sopenharmony_ci	.xdfar_rw	= 1,
62362306a36Sopenharmony_ci	.csmr		= 1,
62462306a36Sopenharmony_ci	.rx_csum	= 1,
62562306a36Sopenharmony_ci	.tsu		= 1,
62662306a36Sopenharmony_ci	.select_mii	= 1,
62762306a36Sopenharmony_ci	.magic		= 1,
62862306a36Sopenharmony_ci	.cexcr		= 1,
62962306a36Sopenharmony_ci};
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/* There is CPU dependent code */
63262306a36Sopenharmony_cistatic void sh_eth_set_rate_rcar(struct net_device *ndev)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	switch (mdp->speed) {
63762306a36Sopenharmony_ci	case 10: /* 10BASE */
63862306a36Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_ELB, 0);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	case 100:/* 100BASE */
64162306a36Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_ELB, ECMR_ELB);
64262306a36Sopenharmony_ci		break;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/* R-Car Gen1 */
64762306a36Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen1_data = {
64862306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
65162306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_RCAR,
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
65662306a36Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
65762306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
65862306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
65962306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
66062306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
66162306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
66262306a36Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
66362306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
66662306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
66762306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
66862306a36Sopenharmony_ci	.fdr_value	= 0x00000f0f,
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	.apr		= 1,
67162306a36Sopenharmony_ci	.mpr		= 1,
67262306a36Sopenharmony_ci	.tpauser	= 1,
67362306a36Sopenharmony_ci	.hw_swap	= 1,
67462306a36Sopenharmony_ci	.no_xdfar	= 1,
67562306a36Sopenharmony_ci};
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci/* R-Car Gen2 and RZ/G1 */
67862306a36Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen2_data = {
67962306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
68262306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_RCAR,
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
68762306a36Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD,
68862306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP |
68962306a36Sopenharmony_ci			  ECSIPR_MPDIP,
69062306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
69162306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
69262306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
69362306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
69462306a36Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
69562306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
69862306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
69962306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
70062306a36Sopenharmony_ci	.fdr_value	= 0x00000f0f,
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	.trscer_err_mask = TRSCER_RMAFCE,
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	.apr		= 1,
70562306a36Sopenharmony_ci	.mpr		= 1,
70662306a36Sopenharmony_ci	.tpauser	= 1,
70762306a36Sopenharmony_ci	.hw_swap	= 1,
70862306a36Sopenharmony_ci	.no_xdfar	= 1,
70962306a36Sopenharmony_ci	.rmiimode	= 1,
71062306a36Sopenharmony_ci	.magic		= 1,
71162306a36Sopenharmony_ci};
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci/* R8A77980 */
71462306a36Sopenharmony_cistatic struct sh_eth_cpu_data r8a77980_data = {
71562306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
71862306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	.register_type  = SH_ETH_REG_GIGABIT,
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
72362306a36Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD,
72462306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP |
72562306a36Sopenharmony_ci			  ECSIPR_MPDIP,
72662306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
72762306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
72862306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
72962306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
73062306a36Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
73162306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	.tx_check       = EESR_FTC | EESR_CD | EESR_TRO,
73462306a36Sopenharmony_ci	.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
73562306a36Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER |
73662306a36Sopenharmony_ci			  EESR_TFE | EESR_TDE | EESR_ECI,
73762306a36Sopenharmony_ci	.fdr_value	= 0x0000070f,
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	.apr		= 1,
74062306a36Sopenharmony_ci	.mpr		= 1,
74162306a36Sopenharmony_ci	.tpauser	= 1,
74262306a36Sopenharmony_ci	.gecmr		= 1,
74362306a36Sopenharmony_ci	.bculr		= 1,
74462306a36Sopenharmony_ci	.hw_swap	= 1,
74562306a36Sopenharmony_ci	.nbst		= 1,
74662306a36Sopenharmony_ci	.rpadir		= 1,
74762306a36Sopenharmony_ci	.no_trimd	= 1,
74862306a36Sopenharmony_ci	.no_ade		= 1,
74962306a36Sopenharmony_ci	.xdfar_rw	= 1,
75062306a36Sopenharmony_ci	.csmr		= 1,
75162306a36Sopenharmony_ci	.rx_csum	= 1,
75262306a36Sopenharmony_ci	.select_mii	= 1,
75362306a36Sopenharmony_ci	.magic		= 1,
75462306a36Sopenharmony_ci	.cexcr		= 1,
75562306a36Sopenharmony_ci};
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci/* R7S9210 */
75862306a36Sopenharmony_cistatic struct sh_eth_cpu_data r7s9210_data = {
75962306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
76262306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_rcar,
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
76762306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD,
76862306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_ICDIP,
76962306a36Sopenharmony_ci	.eesipr_value	= EESIPR_TWBIP | EESIPR_TABTIP | EESIPR_RABTIP |
77062306a36Sopenharmony_ci			  EESIPR_RFCOFIP | EESIPR_ECIIP | EESIPR_FTCIP |
77162306a36Sopenharmony_ci			  EESIPR_TDEIP | EESIPR_TFUFIP | EESIPR_FRIP |
77262306a36Sopenharmony_ci			  EESIPR_RDEIP | EESIPR_RFOFIP | EESIPR_CNDIP |
77362306a36Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
77462306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP | EESIPR_RTLFIP |
77562306a36Sopenharmony_ci			  EESIPR_RTSFIP | EESIPR_PREIP | EESIPR_CERFIP,
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
77862306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
77962306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	.fdr_value	= 0x0000070f,
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	.trscer_err_mask = TRSCER_RMAFCE | TRSCER_RRFCE,
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	.apr		= 1,
78662306a36Sopenharmony_ci	.mpr		= 1,
78762306a36Sopenharmony_ci	.tpauser	= 1,
78862306a36Sopenharmony_ci	.hw_swap	= 1,
78962306a36Sopenharmony_ci	.rpadir		= 1,
79062306a36Sopenharmony_ci	.no_ade		= 1,
79162306a36Sopenharmony_ci	.xdfar_rw	= 1,
79262306a36Sopenharmony_ci};
79362306a36Sopenharmony_ci#endif /* CONFIG_OF */
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic void sh_eth_set_rate_sh7724(struct net_device *ndev)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	switch (mdp->speed) {
80062306a36Sopenharmony_ci	case 10: /* 10BASE */
80162306a36Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_RTM, 0);
80262306a36Sopenharmony_ci		break;
80362306a36Sopenharmony_ci	case 100:/* 100BASE */
80462306a36Sopenharmony_ci		sh_eth_modify(ndev, ECMR, ECMR_RTM, ECMR_RTM);
80562306a36Sopenharmony_ci		break;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/* SH7724 */
81062306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7724_data = {
81162306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
81462306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_sh7724,
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
81962306a36Sopenharmony_ci	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
82062306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
82162306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP |
82262306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
82362306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
82462306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_RRFIP |
82562306a36Sopenharmony_ci			  EESIPR_RTLFIP | EESIPR_RTSFIP |
82662306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
82962306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
83062306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	.apr		= 1,
83362306a36Sopenharmony_ci	.mpr		= 1,
83462306a36Sopenharmony_ci	.tpauser	= 1,
83562306a36Sopenharmony_ci	.hw_swap	= 1,
83662306a36Sopenharmony_ci	.rpadir		= 1,
83762306a36Sopenharmony_ci};
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic void sh_eth_set_rate_sh7757(struct net_device *ndev)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	switch (mdp->speed) {
84462306a36Sopenharmony_ci	case 10: /* 10BASE */
84562306a36Sopenharmony_ci		sh_eth_write(ndev, 0, RTRATE);
84662306a36Sopenharmony_ci		break;
84762306a36Sopenharmony_ci	case 100:/* 100BASE */
84862306a36Sopenharmony_ci		sh_eth_write(ndev, 1, RTRATE);
84962306a36Sopenharmony_ci		break;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci/* SH7757 */
85462306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data = {
85562306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
85862306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_sh7757,
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH4,
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
86362306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
86462306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
86562306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
86662306a36Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
86762306a36Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
86862306a36Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
86962306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
87062306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO,
87362306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
87462306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
87762306a36Sopenharmony_ci	.apr		= 1,
87862306a36Sopenharmony_ci	.mpr		= 1,
87962306a36Sopenharmony_ci	.tpauser	= 1,
88062306a36Sopenharmony_ci	.hw_swap	= 1,
88162306a36Sopenharmony_ci	.no_ade		= 1,
88262306a36Sopenharmony_ci	.rpadir		= 1,
88362306a36Sopenharmony_ci	.rtrate		= 1,
88462306a36Sopenharmony_ci	.dual_port	= 1,
88562306a36Sopenharmony_ci};
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci#define SH_GIGA_ETH_BASE	0xfee00000UL
88862306a36Sopenharmony_ci#define GIGA_MALR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8)
88962306a36Sopenharmony_ci#define GIGA_MAHR(port)		(SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0)
89062306a36Sopenharmony_cistatic void sh_eth_chip_reset_giga(struct net_device *ndev)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	u32 mahr[2], malr[2];
89362306a36Sopenharmony_ci	int i;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* save MAHR and MALR */
89662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
89762306a36Sopenharmony_ci		malr[i] = ioread32((void *)GIGA_MALR(i));
89862306a36Sopenharmony_ci		mahr[i] = ioread32((void *)GIGA_MAHR(i));
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	sh_eth_chip_reset(ndev);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/* restore MAHR and MALR */
90462306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
90562306a36Sopenharmony_ci		iowrite32(malr[i], (void *)GIGA_MALR(i));
90662306a36Sopenharmony_ci		iowrite32(mahr[i], (void *)GIGA_MAHR(i));
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic void sh_eth_set_rate_giga(struct net_device *ndev)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (WARN_ON(!mdp->cd->gecmr))
91562306a36Sopenharmony_ci		return;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	switch (mdp->speed) {
91862306a36Sopenharmony_ci	case 10: /* 10BASE */
91962306a36Sopenharmony_ci		sh_eth_write(ndev, 0x00000000, GECMR);
92062306a36Sopenharmony_ci		break;
92162306a36Sopenharmony_ci	case 100:/* 100BASE */
92262306a36Sopenharmony_ci		sh_eth_write(ndev, 0x00000010, GECMR);
92362306a36Sopenharmony_ci		break;
92462306a36Sopenharmony_ci	case 1000: /* 1000BASE */
92562306a36Sopenharmony_ci		sh_eth_write(ndev, 0x00000020, GECMR);
92662306a36Sopenharmony_ci		break;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci/* SH7757(GETHERC) */
93162306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data_giga = {
93262306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset_giga,
93562306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
93662306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_giga,
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
94162306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
94262306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
94362306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
94462306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
94562306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
94662306a36Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
94762306a36Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
94862306a36Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
94962306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
95062306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
95362306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
95462306a36Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
95562306a36Sopenharmony_ci			  EESR_TDE,
95662306a36Sopenharmony_ci	.fdr_value	= 0x0000072f,
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
95962306a36Sopenharmony_ci	.apr		= 1,
96062306a36Sopenharmony_ci	.mpr		= 1,
96162306a36Sopenharmony_ci	.tpauser	= 1,
96262306a36Sopenharmony_ci	.gecmr		= 1,
96362306a36Sopenharmony_ci	.bculr		= 1,
96462306a36Sopenharmony_ci	.hw_swap	= 1,
96562306a36Sopenharmony_ci	.rpadir		= 1,
96662306a36Sopenharmony_ci	.no_trimd	= 1,
96762306a36Sopenharmony_ci	.no_ade		= 1,
96862306a36Sopenharmony_ci	.xdfar_rw	= 1,
96962306a36Sopenharmony_ci	.tsu		= 1,
97062306a36Sopenharmony_ci	.cexcr		= 1,
97162306a36Sopenharmony_ci	.dual_port	= 1,
97262306a36Sopenharmony_ci};
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/* SH7734 */
97562306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7734_data = {
97662306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
97962306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
98062306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
98562306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
98662306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
98762306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
98862306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
98962306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
99062306a36Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
99162306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP |
99262306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
99362306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
99662306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
99762306a36Sopenharmony_ci			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
99862306a36Sopenharmony_ci			  EESR_TDE,
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	.apr		= 1,
100162306a36Sopenharmony_ci	.mpr		= 1,
100262306a36Sopenharmony_ci	.tpauser	= 1,
100362306a36Sopenharmony_ci	.gecmr		= 1,
100462306a36Sopenharmony_ci	.bculr		= 1,
100562306a36Sopenharmony_ci	.hw_swap	= 1,
100662306a36Sopenharmony_ci	.no_trimd	= 1,
100762306a36Sopenharmony_ci	.no_ade		= 1,
100862306a36Sopenharmony_ci	.xdfar_rw	= 1,
100962306a36Sopenharmony_ci	.tsu		= 1,
101062306a36Sopenharmony_ci	.csmr		= 1,
101162306a36Sopenharmony_ci	.rx_csum	= 1,
101262306a36Sopenharmony_ci	.select_mii	= 1,
101362306a36Sopenharmony_ci	.magic		= 1,
101462306a36Sopenharmony_ci	.cexcr		= 1,
101562306a36Sopenharmony_ci};
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci/* SH7763 */
101862306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7763_data = {
101962306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset_gether,
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	.chip_reset	= sh_eth_chip_reset,
102262306a36Sopenharmony_ci	.set_duplex	= sh_eth_set_duplex,
102362306a36Sopenharmony_ci	.set_rate	= sh_eth_set_rate_gether,
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_GIGABIT,
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_GETHER,
102862306a36Sopenharmony_ci	.ecsr_value	= ECSR_ICD | ECSR_MPD,
102962306a36Sopenharmony_ci	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
103062306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
103162306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
103262306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
103362306a36Sopenharmony_ci			  EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP |
103462306a36Sopenharmony_ci			  EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP |
103562306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
103662306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	.tx_check	= EESR_TC1 | EESR_FTC,
103962306a36Sopenharmony_ci	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
104062306a36Sopenharmony_ci			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE,
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	.apr		= 1,
104362306a36Sopenharmony_ci	.mpr		= 1,
104462306a36Sopenharmony_ci	.tpauser	= 1,
104562306a36Sopenharmony_ci	.gecmr		= 1,
104662306a36Sopenharmony_ci	.bculr		= 1,
104762306a36Sopenharmony_ci	.hw_swap	= 1,
104862306a36Sopenharmony_ci	.no_trimd	= 1,
104962306a36Sopenharmony_ci	.no_ade		= 1,
105062306a36Sopenharmony_ci	.xdfar_rw	= 1,
105162306a36Sopenharmony_ci	.tsu		= 1,
105262306a36Sopenharmony_ci	.irq_flags	= IRQF_SHARED,
105362306a36Sopenharmony_ci	.magic		= 1,
105462306a36Sopenharmony_ci	.cexcr		= 1,
105562306a36Sopenharmony_ci	.rx_csum	= 1,
105662306a36Sopenharmony_ci	.dual_port	= 1,
105762306a36Sopenharmony_ci};
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh7619_data = {
106062306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH3_SH2,
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
106562306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
106662306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
106762306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
106862306a36Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
106962306a36Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
107062306a36Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
107162306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
107262306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	.apr		= 1,
107562306a36Sopenharmony_ci	.mpr		= 1,
107662306a36Sopenharmony_ci	.tpauser	= 1,
107762306a36Sopenharmony_ci	.hw_swap	= 1,
107862306a36Sopenharmony_ci};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic struct sh_eth_cpu_data sh771x_data = {
108162306a36Sopenharmony_ci	.soft_reset	= sh_eth_soft_reset,
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	.register_type	= SH_ETH_REG_FAST_SH3_SH2,
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	.edtrr_trns	= EDTRR_TRNS_ETHER,
108662306a36Sopenharmony_ci	.eesipr_value	= EESIPR_RFCOFIP | EESIPR_ECIIP |
108762306a36Sopenharmony_ci			  EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP |
108862306a36Sopenharmony_ci			  EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP |
108962306a36Sopenharmony_ci			  0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP |
109062306a36Sopenharmony_ci			  EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP |
109162306a36Sopenharmony_ci			  EESIPR_CEEFIP | EESIPR_CELFIP |
109262306a36Sopenharmony_ci			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
109362306a36Sopenharmony_ci			  EESIPR_PREIP | EESIPR_CERFIP,
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	.trscer_err_mask = TRSCER_RMAFCE,
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	.tsu		= 1,
109862306a36Sopenharmony_ci	.dual_port	= 1,
109962306a36Sopenharmony_ci};
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	if (!cd->ecsr_value)
110462306a36Sopenharmony_ci		cd->ecsr_value = DEFAULT_ECSR_INIT;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (!cd->ecsipr_value)
110762306a36Sopenharmony_ci		cd->ecsipr_value = DEFAULT_ECSIPR_INIT;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	if (!cd->fcftr_value)
111062306a36Sopenharmony_ci		cd->fcftr_value = DEFAULT_FIFO_F_D_RFF |
111162306a36Sopenharmony_ci				  DEFAULT_FIFO_F_D_RFD;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (!cd->fdr_value)
111462306a36Sopenharmony_ci		cd->fdr_value = DEFAULT_FDR_INIT;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (!cd->tx_check)
111762306a36Sopenharmony_ci		cd->tx_check = DEFAULT_TX_CHECK;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (!cd->eesr_err_check)
112062306a36Sopenharmony_ci		cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (!cd->trscer_err_mask)
112362306a36Sopenharmony_ci		cd->trscer_err_mask = DEFAULT_TRSCER_ERR_MASK;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic void sh_eth_set_receive_align(struct sk_buff *skb)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (reserve)
113162306a36Sopenharmony_ci		skb_reserve(skb, SH_ETH_RX_ALIGN - reserve);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci/* Program the hardware MAC address from dev->dev_addr. */
113562306a36Sopenharmony_cistatic void update_mac_address(struct net_device *ndev)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	sh_eth_write(ndev,
113862306a36Sopenharmony_ci		     (ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
113962306a36Sopenharmony_ci		     (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR);
114062306a36Sopenharmony_ci	sh_eth_write(ndev,
114162306a36Sopenharmony_ci		     (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR);
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci/* Get MAC address from SuperH MAC address register
114562306a36Sopenharmony_ci *
114662306a36Sopenharmony_ci * SuperH's Ethernet device doesn't have 'ROM' to MAC address.
114762306a36Sopenharmony_ci * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g).
114862306a36Sopenharmony_ci * When you want use this device, you must set MAC address in bootloader.
114962306a36Sopenharmony_ci *
115062306a36Sopenharmony_ci */
115162306a36Sopenharmony_cistatic void read_mac_address(struct net_device *ndev, unsigned char *mac)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
115462306a36Sopenharmony_ci		eth_hw_addr_set(ndev, mac);
115562306a36Sopenharmony_ci	} else {
115662306a36Sopenharmony_ci		u32 mahr = sh_eth_read(ndev, MAHR);
115762306a36Sopenharmony_ci		u32 malr = sh_eth_read(ndev, MALR);
115862306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci		addr[0] = (mahr >> 24) & 0xFF;
116162306a36Sopenharmony_ci		addr[1] = (mahr >> 16) & 0xFF;
116262306a36Sopenharmony_ci		addr[2] = (mahr >>  8) & 0xFF;
116362306a36Sopenharmony_ci		addr[3] = (mahr >>  0) & 0xFF;
116462306a36Sopenharmony_ci		addr[4] = (malr >>  8) & 0xFF;
116562306a36Sopenharmony_ci		addr[5] = (malr >>  0) & 0xFF;
116662306a36Sopenharmony_ci		eth_hw_addr_set(ndev, addr);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistruct bb_info {
117162306a36Sopenharmony_ci	void (*set_gate)(void *addr);
117262306a36Sopenharmony_ci	struct mdiobb_ctrl ctrl;
117362306a36Sopenharmony_ci	void *addr;
117462306a36Sopenharmony_ci};
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic void sh_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
117962306a36Sopenharmony_ci	u32 pir;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (bitbang->set_gate)
118262306a36Sopenharmony_ci		bitbang->set_gate(bitbang->addr);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	pir = ioread32(bitbang->addr);
118562306a36Sopenharmony_ci	if (set)
118662306a36Sopenharmony_ci		pir |=  mask;
118762306a36Sopenharmony_ci	else
118862306a36Sopenharmony_ci		pir &= ~mask;
118962306a36Sopenharmony_ci	iowrite32(pir, bitbang->addr);
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci/* Data I/O pin control */
119362306a36Sopenharmony_cistatic void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MMD, bit);
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci/* Set bit data*/
119962306a36Sopenharmony_cistatic void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MDO, bit);
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/* Get bit data*/
120562306a36Sopenharmony_cistatic int sh_get_mdio(struct mdiobb_ctrl *ctrl)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (bitbang->set_gate)
121062306a36Sopenharmony_ci		bitbang->set_gate(bitbang->addr);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	return (ioread32(bitbang->addr) & PIR_MDI) != 0;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci/* MDC pin control */
121662306a36Sopenharmony_cistatic void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	sh_mdio_ctrl(ctrl, PIR_MDC, bit);
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci/* mdio bus control struct */
122262306a36Sopenharmony_cistatic const struct mdiobb_ops bb_ops = {
122362306a36Sopenharmony_ci	.owner = THIS_MODULE,
122462306a36Sopenharmony_ci	.set_mdc = sh_mdc_ctrl,
122562306a36Sopenharmony_ci	.set_mdio_dir = sh_mmd_ctrl,
122662306a36Sopenharmony_ci	.set_mdio_data = sh_set_mdio,
122762306a36Sopenharmony_ci	.get_mdio_data = sh_get_mdio,
122862306a36Sopenharmony_ci};
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci/* free Tx skb function */
123162306a36Sopenharmony_cistatic int sh_eth_tx_free(struct net_device *ndev, bool sent_only)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
123462306a36Sopenharmony_ci	struct sh_eth_txdesc *txdesc;
123562306a36Sopenharmony_ci	int free_num = 0;
123662306a36Sopenharmony_ci	int entry;
123762306a36Sopenharmony_ci	bool sent;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) {
124062306a36Sopenharmony_ci		entry = mdp->dirty_tx % mdp->num_tx_ring;
124162306a36Sopenharmony_ci		txdesc = &mdp->tx_ring[entry];
124262306a36Sopenharmony_ci		sent = !(txdesc->status & cpu_to_le32(TD_TACT));
124362306a36Sopenharmony_ci		if (sent_only && !sent)
124462306a36Sopenharmony_ci			break;
124562306a36Sopenharmony_ci		/* TACT bit must be checked before all the following reads */
124662306a36Sopenharmony_ci		dma_rmb();
124762306a36Sopenharmony_ci		netif_info(mdp, tx_done, ndev,
124862306a36Sopenharmony_ci			   "tx entry %d status 0x%08x\n",
124962306a36Sopenharmony_ci			   entry, le32_to_cpu(txdesc->status));
125062306a36Sopenharmony_ci		/* Free the original skb. */
125162306a36Sopenharmony_ci		if (mdp->tx_skbuff[entry]) {
125262306a36Sopenharmony_ci			dma_unmap_single(&mdp->pdev->dev,
125362306a36Sopenharmony_ci					 le32_to_cpu(txdesc->addr),
125462306a36Sopenharmony_ci					 le32_to_cpu(txdesc->len) >> 16,
125562306a36Sopenharmony_ci					 DMA_TO_DEVICE);
125662306a36Sopenharmony_ci			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
125762306a36Sopenharmony_ci			mdp->tx_skbuff[entry] = NULL;
125862306a36Sopenharmony_ci			free_num++;
125962306a36Sopenharmony_ci		}
126062306a36Sopenharmony_ci		txdesc->status = cpu_to_le32(TD_TFP);
126162306a36Sopenharmony_ci		if (entry >= mdp->num_tx_ring - 1)
126262306a36Sopenharmony_ci			txdesc->status |= cpu_to_le32(TD_TDLE);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		if (sent) {
126562306a36Sopenharmony_ci			ndev->stats.tx_packets++;
126662306a36Sopenharmony_ci			ndev->stats.tx_bytes += le32_to_cpu(txdesc->len) >> 16;
126762306a36Sopenharmony_ci		}
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	return free_num;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/* free skb and descriptor buffer */
127362306a36Sopenharmony_cistatic void sh_eth_ring_free(struct net_device *ndev)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
127662306a36Sopenharmony_ci	int ringsize, i;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (mdp->rx_ring) {
127962306a36Sopenharmony_ci		for (i = 0; i < mdp->num_rx_ring; i++) {
128062306a36Sopenharmony_ci			if (mdp->rx_skbuff[i]) {
128162306a36Sopenharmony_ci				struct sh_eth_rxdesc *rxdesc = &mdp->rx_ring[i];
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci				dma_unmap_single(&mdp->pdev->dev,
128462306a36Sopenharmony_ci						 le32_to_cpu(rxdesc->addr),
128562306a36Sopenharmony_ci						 ALIGN(mdp->rx_buf_sz, 32),
128662306a36Sopenharmony_ci						 DMA_FROM_DEVICE);
128762306a36Sopenharmony_ci			}
128862306a36Sopenharmony_ci		}
128962306a36Sopenharmony_ci		ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
129062306a36Sopenharmony_ci		dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->rx_ring,
129162306a36Sopenharmony_ci				  mdp->rx_desc_dma);
129262306a36Sopenharmony_ci		mdp->rx_ring = NULL;
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* Free Rx skb ringbuffer */
129662306a36Sopenharmony_ci	if (mdp->rx_skbuff) {
129762306a36Sopenharmony_ci		for (i = 0; i < mdp->num_rx_ring; i++)
129862306a36Sopenharmony_ci			dev_kfree_skb(mdp->rx_skbuff[i]);
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	kfree(mdp->rx_skbuff);
130162306a36Sopenharmony_ci	mdp->rx_skbuff = NULL;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (mdp->tx_ring) {
130462306a36Sopenharmony_ci		sh_eth_tx_free(ndev, false);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci		ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
130762306a36Sopenharmony_ci		dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->tx_ring,
130862306a36Sopenharmony_ci				  mdp->tx_desc_dma);
130962306a36Sopenharmony_ci		mdp->tx_ring = NULL;
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	/* Free Tx skb ringbuffer */
131362306a36Sopenharmony_ci	kfree(mdp->tx_skbuff);
131462306a36Sopenharmony_ci	mdp->tx_skbuff = NULL;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci/* format skb and descriptor buffer */
131862306a36Sopenharmony_cistatic void sh_eth_ring_format(struct net_device *ndev)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
132162306a36Sopenharmony_ci	int i;
132262306a36Sopenharmony_ci	struct sk_buff *skb;
132362306a36Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc = NULL;
132462306a36Sopenharmony_ci	struct sh_eth_txdesc *txdesc = NULL;
132562306a36Sopenharmony_ci	int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring;
132662306a36Sopenharmony_ci	int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
132762306a36Sopenharmony_ci	int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
132862306a36Sopenharmony_ci	dma_addr_t dma_addr;
132962306a36Sopenharmony_ci	u32 buf_len;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	mdp->cur_rx = 0;
133262306a36Sopenharmony_ci	mdp->cur_tx = 0;
133362306a36Sopenharmony_ci	mdp->dirty_rx = 0;
133462306a36Sopenharmony_ci	mdp->dirty_tx = 0;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	memset(mdp->rx_ring, 0, rx_ringsize);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* build Rx ring buffer */
133962306a36Sopenharmony_ci	for (i = 0; i < mdp->num_rx_ring; i++) {
134062306a36Sopenharmony_ci		/* skb */
134162306a36Sopenharmony_ci		mdp->rx_skbuff[i] = NULL;
134262306a36Sopenharmony_ci		skb = netdev_alloc_skb(ndev, skbuff_size);
134362306a36Sopenharmony_ci		if (skb == NULL)
134462306a36Sopenharmony_ci			break;
134562306a36Sopenharmony_ci		sh_eth_set_receive_align(skb);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		/* The size of the buffer is a multiple of 32 bytes. */
134862306a36Sopenharmony_ci		buf_len = ALIGN(mdp->rx_buf_sz, 32);
134962306a36Sopenharmony_ci		dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, buf_len,
135062306a36Sopenharmony_ci					  DMA_FROM_DEVICE);
135162306a36Sopenharmony_ci		if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
135262306a36Sopenharmony_ci			kfree_skb(skb);
135362306a36Sopenharmony_ci			break;
135462306a36Sopenharmony_ci		}
135562306a36Sopenharmony_ci		mdp->rx_skbuff[i] = skb;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		/* RX descriptor */
135862306a36Sopenharmony_ci		rxdesc = &mdp->rx_ring[i];
135962306a36Sopenharmony_ci		rxdesc->len = cpu_to_le32(buf_len << 16);
136062306a36Sopenharmony_ci		rxdesc->addr = cpu_to_le32(dma_addr);
136162306a36Sopenharmony_ci		rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		/* Rx descriptor address set */
136462306a36Sopenharmony_ci		if (i == 0) {
136562306a36Sopenharmony_ci			sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
136662306a36Sopenharmony_ci			if (mdp->cd->xdfar_rw)
136762306a36Sopenharmony_ci				sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
136862306a36Sopenharmony_ci		}
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	/* Mark the last entry as wrapping the ring. */
137462306a36Sopenharmony_ci	if (rxdesc)
137562306a36Sopenharmony_ci		rxdesc->status |= cpu_to_le32(RD_RDLE);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	memset(mdp->tx_ring, 0, tx_ringsize);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* build Tx ring buffer */
138062306a36Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++) {
138162306a36Sopenharmony_ci		mdp->tx_skbuff[i] = NULL;
138262306a36Sopenharmony_ci		txdesc = &mdp->tx_ring[i];
138362306a36Sopenharmony_ci		txdesc->status = cpu_to_le32(TD_TFP);
138462306a36Sopenharmony_ci		txdesc->len = cpu_to_le32(0);
138562306a36Sopenharmony_ci		if (i == 0) {
138662306a36Sopenharmony_ci			/* Tx descriptor address set */
138762306a36Sopenharmony_ci			sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
138862306a36Sopenharmony_ci			if (mdp->cd->xdfar_rw)
138962306a36Sopenharmony_ci				sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
139062306a36Sopenharmony_ci		}
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	txdesc->status |= cpu_to_le32(TD_TDLE);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci/* Get skb and descriptor buffer */
139762306a36Sopenharmony_cistatic int sh_eth_ring_init(struct net_device *ndev)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
140062306a36Sopenharmony_ci	int rx_ringsize, tx_ringsize;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
140362306a36Sopenharmony_ci	 * card needs room to do 8 byte alignment, +2 so we can reserve
140462306a36Sopenharmony_ci	 * the first 2 bytes, and +16 gets room for the status word from the
140562306a36Sopenharmony_ci	 * card.
140662306a36Sopenharmony_ci	 */
140762306a36Sopenharmony_ci	mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ :
140862306a36Sopenharmony_ci			  (((ndev->mtu + 26 + 7) & ~7) + 2 + 16));
140962306a36Sopenharmony_ci	if (mdp->cd->rpadir)
141062306a36Sopenharmony_ci		mdp->rx_buf_sz += NET_IP_ALIGN;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* Allocate RX and TX skb rings */
141362306a36Sopenharmony_ci	mdp->rx_skbuff = kcalloc(mdp->num_rx_ring, sizeof(*mdp->rx_skbuff),
141462306a36Sopenharmony_ci				 GFP_KERNEL);
141562306a36Sopenharmony_ci	if (!mdp->rx_skbuff)
141662306a36Sopenharmony_ci		return -ENOMEM;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	mdp->tx_skbuff = kcalloc(mdp->num_tx_ring, sizeof(*mdp->tx_skbuff),
141962306a36Sopenharmony_ci				 GFP_KERNEL);
142062306a36Sopenharmony_ci	if (!mdp->tx_skbuff)
142162306a36Sopenharmony_ci		goto ring_free;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* Allocate all Rx descriptors. */
142462306a36Sopenharmony_ci	rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
142562306a36Sopenharmony_ci	mdp->rx_ring = dma_alloc_coherent(&mdp->pdev->dev, rx_ringsize,
142662306a36Sopenharmony_ci					  &mdp->rx_desc_dma, GFP_KERNEL);
142762306a36Sopenharmony_ci	if (!mdp->rx_ring)
142862306a36Sopenharmony_ci		goto ring_free;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	mdp->dirty_rx = 0;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	/* Allocate all Tx descriptors. */
143362306a36Sopenharmony_ci	tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
143462306a36Sopenharmony_ci	mdp->tx_ring = dma_alloc_coherent(&mdp->pdev->dev, tx_ringsize,
143562306a36Sopenharmony_ci					  &mdp->tx_desc_dma, GFP_KERNEL);
143662306a36Sopenharmony_ci	if (!mdp->tx_ring)
143762306a36Sopenharmony_ci		goto ring_free;
143862306a36Sopenharmony_ci	return 0;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ciring_free:
144162306a36Sopenharmony_ci	/* Free Rx and Tx skb ring buffer and DMA buffer */
144262306a36Sopenharmony_ci	sh_eth_ring_free(ndev);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	return -ENOMEM;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int sh_eth_dev_init(struct net_device *ndev)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
145062306a36Sopenharmony_ci	int ret;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* Soft Reset */
145362306a36Sopenharmony_ci	ret = mdp->cd->soft_reset(ndev);
145462306a36Sopenharmony_ci	if (ret)
145562306a36Sopenharmony_ci		return ret;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (mdp->cd->rmiimode)
145862306a36Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* Descriptor format */
146162306a36Sopenharmony_ci	sh_eth_ring_format(ndev);
146262306a36Sopenharmony_ci	if (mdp->cd->rpadir)
146362306a36Sopenharmony_ci		sh_eth_write(ndev, NET_IP_ALIGN << 16, RPADIR);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* all sh_eth int mask */
146662306a36Sopenharmony_ci	sh_eth_write(ndev, 0, EESIPR);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
146962306a36Sopenharmony_ci	if (mdp->cd->hw_swap)
147062306a36Sopenharmony_ci		sh_eth_write(ndev, EDMR_EL, EDMR);
147162306a36Sopenharmony_ci	else
147262306a36Sopenharmony_ci#endif
147362306a36Sopenharmony_ci		sh_eth_write(ndev, 0, EDMR);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/* FIFO size set */
147662306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->fdr_value, FDR);
147762306a36Sopenharmony_ci	sh_eth_write(ndev, 0, TFTR);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	/* Frame recv control (enable multiple-packets per rx irq) */
148062306a36Sopenharmony_ci	sh_eth_write(ndev, RMCR_RNC, RMCR);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->trscer_err_mask, TRSCER);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	/* DMA transfer burst mode */
148562306a36Sopenharmony_ci	if (mdp->cd->nbst)
148662306a36Sopenharmony_ci		sh_eth_modify(ndev, EDMR, EDMR_NBST, EDMR_NBST);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* Burst cycle count upper-limit */
148962306a36Sopenharmony_ci	if (mdp->cd->bculr)
149062306a36Sopenharmony_ci		sh_eth_write(ndev, 0x800, BCULR);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->fcftr_value, FCFTR);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	if (!mdp->cd->no_trimd)
149562306a36Sopenharmony_ci		sh_eth_write(ndev, 0, TRIMD);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	/* Recv frame limit set register */
149862306a36Sopenharmony_ci	sh_eth_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN,
149962306a36Sopenharmony_ci		     RFLR);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	sh_eth_modify(ndev, EESR, 0, 0);
150262306a36Sopenharmony_ci	mdp->irq_enabled = true;
150362306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	/* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */
150662306a36Sopenharmony_ci	sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) |
150762306a36Sopenharmony_ci		     (ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) |
150862306a36Sopenharmony_ci		     ECMR_TE | ECMR_RE, ECMR);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (mdp->cd->set_rate)
151162306a36Sopenharmony_ci		mdp->cd->set_rate(ndev);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* E-MAC Status Register clear */
151462306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->ecsr_value, ECSR);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	/* E-MAC Interrupt Enable register */
151762306a36Sopenharmony_ci	sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	/* Set MAC address */
152062306a36Sopenharmony_ci	update_mac_address(ndev);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	/* mask reset */
152362306a36Sopenharmony_ci	if (mdp->cd->apr)
152462306a36Sopenharmony_ci		sh_eth_write(ndev, 1, APR);
152562306a36Sopenharmony_ci	if (mdp->cd->mpr)
152662306a36Sopenharmony_ci		sh_eth_write(ndev, 1, MPR);
152762306a36Sopenharmony_ci	if (mdp->cd->tpauser)
152862306a36Sopenharmony_ci		sh_eth_write(ndev, TPAUSER_UNLIMITED, TPAUSER);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/* Setting the Rx mode will start the Rx process. */
153162306a36Sopenharmony_ci	sh_eth_write(ndev, EDRRR_R, EDRRR);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	return ret;
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic void sh_eth_dev_exit(struct net_device *ndev)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
153962306a36Sopenharmony_ci	int i;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	/* Deactivate all TX descriptors, so DMA should stop at next
154262306a36Sopenharmony_ci	 * packet boundary if it's currently running
154362306a36Sopenharmony_ci	 */
154462306a36Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++)
154562306a36Sopenharmony_ci		mdp->tx_ring[i].status &= ~cpu_to_le32(TD_TACT);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	/* Disable TX FIFO egress to MAC */
154862306a36Sopenharmony_ci	sh_eth_rcv_snd_disable(ndev);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/* Stop RX DMA at next packet boundary */
155162306a36Sopenharmony_ci	sh_eth_write(ndev, 0, EDRRR);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/* Aside from TX DMA, we can't tell when the hardware is
155462306a36Sopenharmony_ci	 * really stopped, so we need to reset to make sure.
155562306a36Sopenharmony_ci	 * Before doing that, wait for long enough to *probably*
155662306a36Sopenharmony_ci	 * finish transmitting the last packet and poll stats.
155762306a36Sopenharmony_ci	 */
155862306a36Sopenharmony_ci	msleep(2); /* max frame time at 10 Mbps < 1250 us */
155962306a36Sopenharmony_ci	sh_eth_get_stats(ndev);
156062306a36Sopenharmony_ci	mdp->cd->soft_reset(ndev);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	/* Set the RMII mode again if required */
156362306a36Sopenharmony_ci	if (mdp->cd->rmiimode)
156462306a36Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	/* Set MAC address again */
156762306a36Sopenharmony_ci	update_mac_address(ndev);
156862306a36Sopenharmony_ci}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic void sh_eth_rx_csum(struct sk_buff *skb)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	u8 *hw_csum;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	/* The hardware checksum is 2 bytes appended to packet data */
157562306a36Sopenharmony_ci	if (unlikely(skb->len < sizeof(__sum16)))
157662306a36Sopenharmony_ci		return;
157762306a36Sopenharmony_ci	hw_csum = skb_tail_pointer(skb) - sizeof(__sum16);
157862306a36Sopenharmony_ci	skb->csum = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum));
157962306a36Sopenharmony_ci	skb->ip_summed = CHECKSUM_COMPLETE;
158062306a36Sopenharmony_ci	skb_trim(skb, skb->len - sizeof(__sum16));
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci/* Packet receive function */
158462306a36Sopenharmony_cistatic int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
158762306a36Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	int entry = mdp->cur_rx % mdp->num_rx_ring;
159062306a36Sopenharmony_ci	int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx;
159162306a36Sopenharmony_ci	int limit;
159262306a36Sopenharmony_ci	struct sk_buff *skb;
159362306a36Sopenharmony_ci	u32 desc_status;
159462306a36Sopenharmony_ci	int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
159562306a36Sopenharmony_ci	dma_addr_t dma_addr;
159662306a36Sopenharmony_ci	u16 pkt_len;
159762306a36Sopenharmony_ci	u32 buf_len;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	boguscnt = min(boguscnt, *quota);
160062306a36Sopenharmony_ci	limit = boguscnt;
160162306a36Sopenharmony_ci	rxdesc = &mdp->rx_ring[entry];
160262306a36Sopenharmony_ci	while (!(rxdesc->status & cpu_to_le32(RD_RACT))) {
160362306a36Sopenharmony_ci		/* RACT bit must be checked before all the following reads */
160462306a36Sopenharmony_ci		dma_rmb();
160562306a36Sopenharmony_ci		desc_status = le32_to_cpu(rxdesc->status);
160662306a36Sopenharmony_ci		pkt_len = le32_to_cpu(rxdesc->len) & RD_RFL;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		if (--boguscnt < 0)
160962306a36Sopenharmony_ci			break;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci		netif_info(mdp, rx_status, ndev,
161262306a36Sopenharmony_ci			   "rx entry %d status 0x%08x len %d\n",
161362306a36Sopenharmony_ci			   entry, desc_status, pkt_len);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		if (!(desc_status & RDFEND))
161662306a36Sopenharmony_ci			ndev->stats.rx_length_errors++;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		/* In case of almost all GETHER/ETHERs, the Receive Frame State
161962306a36Sopenharmony_ci		 * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
162062306a36Sopenharmony_ci		 * bit 0. However, in case of the R8A7740 and R7S72100
162162306a36Sopenharmony_ci		 * the RFS bits are from bit 25 to bit 16. So, the
162262306a36Sopenharmony_ci		 * driver needs right shifting by 16.
162362306a36Sopenharmony_ci		 */
162462306a36Sopenharmony_ci		if (mdp->cd->csmr)
162562306a36Sopenharmony_ci			desc_status >>= 16;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci		skb = mdp->rx_skbuff[entry];
162862306a36Sopenharmony_ci		if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
162962306a36Sopenharmony_ci				   RD_RFS5 | RD_RFS6 | RD_RFS10)) {
163062306a36Sopenharmony_ci			ndev->stats.rx_errors++;
163162306a36Sopenharmony_ci			if (desc_status & RD_RFS1)
163262306a36Sopenharmony_ci				ndev->stats.rx_crc_errors++;
163362306a36Sopenharmony_ci			if (desc_status & RD_RFS2)
163462306a36Sopenharmony_ci				ndev->stats.rx_frame_errors++;
163562306a36Sopenharmony_ci			if (desc_status & RD_RFS3)
163662306a36Sopenharmony_ci				ndev->stats.rx_length_errors++;
163762306a36Sopenharmony_ci			if (desc_status & RD_RFS4)
163862306a36Sopenharmony_ci				ndev->stats.rx_length_errors++;
163962306a36Sopenharmony_ci			if (desc_status & RD_RFS6)
164062306a36Sopenharmony_ci				ndev->stats.rx_missed_errors++;
164162306a36Sopenharmony_ci			if (desc_status & RD_RFS10)
164262306a36Sopenharmony_ci				ndev->stats.rx_over_errors++;
164362306a36Sopenharmony_ci		} else	if (skb) {
164462306a36Sopenharmony_ci			dma_addr = le32_to_cpu(rxdesc->addr);
164562306a36Sopenharmony_ci			if (!mdp->cd->hw_swap)
164662306a36Sopenharmony_ci				sh_eth_soft_swap(
164762306a36Sopenharmony_ci					phys_to_virt(ALIGN(dma_addr, 4)),
164862306a36Sopenharmony_ci					pkt_len + 2);
164962306a36Sopenharmony_ci			mdp->rx_skbuff[entry] = NULL;
165062306a36Sopenharmony_ci			if (mdp->cd->rpadir)
165162306a36Sopenharmony_ci				skb_reserve(skb, NET_IP_ALIGN);
165262306a36Sopenharmony_ci			dma_unmap_single(&mdp->pdev->dev, dma_addr,
165362306a36Sopenharmony_ci					 ALIGN(mdp->rx_buf_sz, 32),
165462306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
165562306a36Sopenharmony_ci			skb_put(skb, pkt_len);
165662306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, ndev);
165762306a36Sopenharmony_ci			if (ndev->features & NETIF_F_RXCSUM)
165862306a36Sopenharmony_ci				sh_eth_rx_csum(skb);
165962306a36Sopenharmony_ci			netif_receive_skb(skb);
166062306a36Sopenharmony_ci			ndev->stats.rx_packets++;
166162306a36Sopenharmony_ci			ndev->stats.rx_bytes += pkt_len;
166262306a36Sopenharmony_ci			if (desc_status & RD_RFS8)
166362306a36Sopenharmony_ci				ndev->stats.multicast++;
166462306a36Sopenharmony_ci		}
166562306a36Sopenharmony_ci		entry = (++mdp->cur_rx) % mdp->num_rx_ring;
166662306a36Sopenharmony_ci		rxdesc = &mdp->rx_ring[entry];
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	/* Refill the Rx ring buffers. */
167062306a36Sopenharmony_ci	for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) {
167162306a36Sopenharmony_ci		entry = mdp->dirty_rx % mdp->num_rx_ring;
167262306a36Sopenharmony_ci		rxdesc = &mdp->rx_ring[entry];
167362306a36Sopenharmony_ci		/* The size of the buffer is 32 byte boundary. */
167462306a36Sopenharmony_ci		buf_len = ALIGN(mdp->rx_buf_sz, 32);
167562306a36Sopenharmony_ci		rxdesc->len = cpu_to_le32(buf_len << 16);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		if (mdp->rx_skbuff[entry] == NULL) {
167862306a36Sopenharmony_ci			skb = netdev_alloc_skb(ndev, skbuff_size);
167962306a36Sopenharmony_ci			if (skb == NULL)
168062306a36Sopenharmony_ci				break;	/* Better luck next round. */
168162306a36Sopenharmony_ci			sh_eth_set_receive_align(skb);
168262306a36Sopenharmony_ci			dma_addr = dma_map_single(&mdp->pdev->dev, skb->data,
168362306a36Sopenharmony_ci						  buf_len, DMA_FROM_DEVICE);
168462306a36Sopenharmony_ci			if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
168562306a36Sopenharmony_ci				kfree_skb(skb);
168662306a36Sopenharmony_ci				break;
168762306a36Sopenharmony_ci			}
168862306a36Sopenharmony_ci			mdp->rx_skbuff[entry] = skb;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci			skb_checksum_none_assert(skb);
169162306a36Sopenharmony_ci			rxdesc->addr = cpu_to_le32(dma_addr);
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci		dma_wmb(); /* RACT bit must be set after all the above writes */
169462306a36Sopenharmony_ci		if (entry >= mdp->num_rx_ring - 1)
169562306a36Sopenharmony_ci			rxdesc->status |=
169662306a36Sopenharmony_ci				cpu_to_le32(RD_RACT | RD_RFP | RD_RDLE);
169762306a36Sopenharmony_ci		else
169862306a36Sopenharmony_ci			rxdesc->status |= cpu_to_le32(RD_RACT | RD_RFP);
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	/* Restart Rx engine if stopped. */
170262306a36Sopenharmony_ci	/* If we don't need to check status, don't. -KDU */
170362306a36Sopenharmony_ci	if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
170462306a36Sopenharmony_ci		/* fix the values for the next receiving if RDE is set */
170562306a36Sopenharmony_ci		if (intr_status & EESR_RDE && !mdp->cd->no_xdfar) {
170662306a36Sopenharmony_ci			u32 count = (sh_eth_read(ndev, RDFAR) -
170762306a36Sopenharmony_ci				     sh_eth_read(ndev, RDLAR)) >> 4;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci			mdp->cur_rx = count;
171062306a36Sopenharmony_ci			mdp->dirty_rx = count;
171162306a36Sopenharmony_ci		}
171262306a36Sopenharmony_ci		sh_eth_write(ndev, EDRRR_R, EDRRR);
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	*quota -= limit - boguscnt - 1;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	return *quota <= 0;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	/* disable tx and rx */
172362306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, 0);
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic void sh_eth_rcv_snd_enable(struct net_device *ndev)
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	/* enable tx and rx */
172962306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, ECMR_RE | ECMR_TE);
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/* E-MAC interrupt handler */
173362306a36Sopenharmony_cistatic void sh_eth_emac_interrupt(struct net_device *ndev)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
173662306a36Sopenharmony_ci	u32 felic_stat;
173762306a36Sopenharmony_ci	u32 link_stat;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	felic_stat = sh_eth_read(ndev, ECSR) & sh_eth_read(ndev, ECSIPR);
174062306a36Sopenharmony_ci	sh_eth_write(ndev, felic_stat, ECSR);	/* clear int */
174162306a36Sopenharmony_ci	if (felic_stat & ECSR_ICD)
174262306a36Sopenharmony_ci		ndev->stats.tx_carrier_errors++;
174362306a36Sopenharmony_ci	if (felic_stat & ECSR_MPD)
174462306a36Sopenharmony_ci		pm_wakeup_event(&mdp->pdev->dev, 0);
174562306a36Sopenharmony_ci	if (felic_stat & ECSR_LCHNG) {
174662306a36Sopenharmony_ci		/* Link Changed */
174762306a36Sopenharmony_ci		if (mdp->cd->no_psr || mdp->no_ether_link)
174862306a36Sopenharmony_ci			return;
174962306a36Sopenharmony_ci		link_stat = sh_eth_read(ndev, PSR);
175062306a36Sopenharmony_ci		if (mdp->ether_link_active_low)
175162306a36Sopenharmony_ci			link_stat = ~link_stat;
175262306a36Sopenharmony_ci		if (!(link_stat & PSR_LMON)) {
175362306a36Sopenharmony_ci			sh_eth_rcv_snd_disable(ndev);
175462306a36Sopenharmony_ci		} else {
175562306a36Sopenharmony_ci			/* Link Up */
175662306a36Sopenharmony_ci			sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, 0);
175762306a36Sopenharmony_ci			/* clear int */
175862306a36Sopenharmony_ci			sh_eth_modify(ndev, ECSR, 0, 0);
175962306a36Sopenharmony_ci			sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, EESIPR_ECIIP);
176062306a36Sopenharmony_ci			/* enable tx and rx */
176162306a36Sopenharmony_ci			sh_eth_rcv_snd_enable(ndev);
176262306a36Sopenharmony_ci		}
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci/* error control function */
176762306a36Sopenharmony_cistatic void sh_eth_error(struct net_device *ndev, u32 intr_status)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
177062306a36Sopenharmony_ci	u32 mask;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	if (intr_status & EESR_TWB) {
177362306a36Sopenharmony_ci		/* Unused write back interrupt */
177462306a36Sopenharmony_ci		if (intr_status & EESR_TABT) {	/* Transmit Abort int */
177562306a36Sopenharmony_ci			ndev->stats.tx_aborted_errors++;
177662306a36Sopenharmony_ci			netif_err(mdp, tx_err, ndev, "Transmit Abort\n");
177762306a36Sopenharmony_ci		}
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (intr_status & EESR_RABT) {
178162306a36Sopenharmony_ci		/* Receive Abort int */
178262306a36Sopenharmony_ci		if (intr_status & EESR_RFRMER) {
178362306a36Sopenharmony_ci			/* Receive Frame Overflow int */
178462306a36Sopenharmony_ci			ndev->stats.rx_frame_errors++;
178562306a36Sopenharmony_ci		}
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (intr_status & EESR_TDE) {
178962306a36Sopenharmony_ci		/* Transmit Descriptor Empty int */
179062306a36Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
179162306a36Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n");
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (intr_status & EESR_TFE) {
179562306a36Sopenharmony_ci		/* FIFO under flow */
179662306a36Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
179762306a36Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n");
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (intr_status & EESR_RDE) {
180162306a36Sopenharmony_ci		/* Receive Descriptor Empty int */
180262306a36Sopenharmony_ci		ndev->stats.rx_over_errors++;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (intr_status & EESR_RFE) {
180662306a36Sopenharmony_ci		/* Receive FIFO Overflow int */
180762306a36Sopenharmony_ci		ndev->stats.rx_fifo_errors++;
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
181162306a36Sopenharmony_ci		/* Address Error */
181262306a36Sopenharmony_ci		ndev->stats.tx_fifo_errors++;
181362306a36Sopenharmony_ci		netif_err(mdp, tx_err, ndev, "Address Error\n");
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
181762306a36Sopenharmony_ci	if (mdp->cd->no_ade)
181862306a36Sopenharmony_ci		mask &= ~EESR_ADE;
181962306a36Sopenharmony_ci	if (intr_status & mask) {
182062306a36Sopenharmony_ci		/* Tx error */
182162306a36Sopenharmony_ci		u32 edtrr = sh_eth_read(ndev, EDTRR);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		/* dmesg */
182462306a36Sopenharmony_ci		netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
182562306a36Sopenharmony_ci			   intr_status, mdp->cur_tx, mdp->dirty_tx,
182662306a36Sopenharmony_ci			   (u32)ndev->state, edtrr);
182762306a36Sopenharmony_ci		/* dirty buffer free */
182862306a36Sopenharmony_ci		sh_eth_tx_free(ndev, true);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		/* SH7712 BUG */
183162306a36Sopenharmony_ci		if (edtrr ^ mdp->cd->edtrr_trns) {
183262306a36Sopenharmony_ci			/* tx dma start */
183362306a36Sopenharmony_ci			sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR);
183462306a36Sopenharmony_ci		}
183562306a36Sopenharmony_ci		/* wakeup */
183662306a36Sopenharmony_ci		netif_wake_queue(ndev);
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_cistatic irqreturn_t sh_eth_interrupt(int irq, void *netdev)
184162306a36Sopenharmony_ci{
184262306a36Sopenharmony_ci	struct net_device *ndev = netdev;
184362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
184462306a36Sopenharmony_ci	struct sh_eth_cpu_data *cd = mdp->cd;
184562306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
184662306a36Sopenharmony_ci	u32 intr_status, intr_enable;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	spin_lock(&mdp->lock);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	/* Get interrupt status */
185162306a36Sopenharmony_ci	intr_status = sh_eth_read(ndev, EESR);
185262306a36Sopenharmony_ci	/* Mask it with the interrupt mask, forcing ECI interrupt  to be always
185362306a36Sopenharmony_ci	 * enabled since it's the one that  comes  thru regardless of the mask,
185462306a36Sopenharmony_ci	 * and  we need to fully handle it  in sh_eth_emac_interrupt() in order
185562306a36Sopenharmony_ci	 * to quench it as it doesn't get cleared by just writing 1 to the  ECI
185662306a36Sopenharmony_ci	 * bit...
185762306a36Sopenharmony_ci	 */
185862306a36Sopenharmony_ci	intr_enable = sh_eth_read(ndev, EESIPR);
185962306a36Sopenharmony_ci	intr_status &= intr_enable | EESIPR_ECIIP;
186062306a36Sopenharmony_ci	if (intr_status & (EESR_RX_CHECK | cd->tx_check | EESR_ECI |
186162306a36Sopenharmony_ci			   cd->eesr_err_check))
186262306a36Sopenharmony_ci		ret = IRQ_HANDLED;
186362306a36Sopenharmony_ci	else
186462306a36Sopenharmony_ci		goto out;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (unlikely(!mdp->irq_enabled)) {
186762306a36Sopenharmony_ci		sh_eth_write(ndev, 0, EESIPR);
186862306a36Sopenharmony_ci		goto out;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (intr_status & EESR_RX_CHECK) {
187262306a36Sopenharmony_ci		if (napi_schedule_prep(&mdp->napi)) {
187362306a36Sopenharmony_ci			/* Mask Rx interrupts */
187462306a36Sopenharmony_ci			sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK,
187562306a36Sopenharmony_ci				     EESIPR);
187662306a36Sopenharmony_ci			__napi_schedule(&mdp->napi);
187762306a36Sopenharmony_ci		} else {
187862306a36Sopenharmony_ci			netdev_warn(ndev,
187962306a36Sopenharmony_ci				    "ignoring interrupt, status 0x%08x, mask 0x%08x.\n",
188062306a36Sopenharmony_ci				    intr_status, intr_enable);
188162306a36Sopenharmony_ci		}
188262306a36Sopenharmony_ci	}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	/* Tx Check */
188562306a36Sopenharmony_ci	if (intr_status & cd->tx_check) {
188662306a36Sopenharmony_ci		/* Clear Tx interrupts */
188762306a36Sopenharmony_ci		sh_eth_write(ndev, intr_status & cd->tx_check, EESR);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci		sh_eth_tx_free(ndev, true);
189062306a36Sopenharmony_ci		netif_wake_queue(ndev);
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/* E-MAC interrupt */
189462306a36Sopenharmony_ci	if (intr_status & EESR_ECI)
189562306a36Sopenharmony_ci		sh_eth_emac_interrupt(ndev);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	if (intr_status & cd->eesr_err_check) {
189862306a36Sopenharmony_ci		/* Clear error interrupts */
189962306a36Sopenharmony_ci		sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci		sh_eth_error(ndev, intr_status);
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ciout:
190562306a36Sopenharmony_ci	spin_unlock(&mdp->lock);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	return ret;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_cistatic int sh_eth_poll(struct napi_struct *napi, int budget)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private,
191362306a36Sopenharmony_ci						  napi);
191462306a36Sopenharmony_ci	struct net_device *ndev = napi->dev;
191562306a36Sopenharmony_ci	int quota = budget;
191662306a36Sopenharmony_ci	u32 intr_status;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	for (;;) {
191962306a36Sopenharmony_ci		intr_status = sh_eth_read(ndev, EESR);
192062306a36Sopenharmony_ci		if (!(intr_status & EESR_RX_CHECK))
192162306a36Sopenharmony_ci			break;
192262306a36Sopenharmony_ci		/* Clear Rx interrupts */
192362306a36Sopenharmony_ci		sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci		if (sh_eth_rx(ndev, intr_status, &quota))
192662306a36Sopenharmony_ci			goto out;
192762306a36Sopenharmony_ci	}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	napi_complete(napi);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	/* Reenable Rx interrupts */
193262306a36Sopenharmony_ci	if (mdp->irq_enabled)
193362306a36Sopenharmony_ci		sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
193462306a36Sopenharmony_ciout:
193562306a36Sopenharmony_ci	return budget - quota;
193662306a36Sopenharmony_ci}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci/* PHY state control function */
193962306a36Sopenharmony_cistatic void sh_eth_adjust_link(struct net_device *ndev)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
194262306a36Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
194362306a36Sopenharmony_ci	unsigned long flags;
194462306a36Sopenharmony_ci	int new_state = 0;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	/* Disable TX and RX right over here, if E-MAC change is ignored */
194962306a36Sopenharmony_ci	if (mdp->cd->no_psr || mdp->no_ether_link)
195062306a36Sopenharmony_ci		sh_eth_rcv_snd_disable(ndev);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	if (phydev->link) {
195362306a36Sopenharmony_ci		if (phydev->duplex != mdp->duplex) {
195462306a36Sopenharmony_ci			new_state = 1;
195562306a36Sopenharmony_ci			mdp->duplex = phydev->duplex;
195662306a36Sopenharmony_ci			if (mdp->cd->set_duplex)
195762306a36Sopenharmony_ci				mdp->cd->set_duplex(ndev);
195862306a36Sopenharmony_ci		}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		if (phydev->speed != mdp->speed) {
196162306a36Sopenharmony_ci			new_state = 1;
196262306a36Sopenharmony_ci			mdp->speed = phydev->speed;
196362306a36Sopenharmony_ci			if (mdp->cd->set_rate)
196462306a36Sopenharmony_ci				mdp->cd->set_rate(ndev);
196562306a36Sopenharmony_ci		}
196662306a36Sopenharmony_ci		if (!mdp->link) {
196762306a36Sopenharmony_ci			sh_eth_modify(ndev, ECMR, ECMR_TXF, 0);
196862306a36Sopenharmony_ci			new_state = 1;
196962306a36Sopenharmony_ci			mdp->link = phydev->link;
197062306a36Sopenharmony_ci		}
197162306a36Sopenharmony_ci	} else if (mdp->link) {
197262306a36Sopenharmony_ci		new_state = 1;
197362306a36Sopenharmony_ci		mdp->link = 0;
197462306a36Sopenharmony_ci		mdp->speed = 0;
197562306a36Sopenharmony_ci		mdp->duplex = -1;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	/* Enable TX and RX right over here, if E-MAC change is ignored */
197962306a36Sopenharmony_ci	if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link)
198062306a36Sopenharmony_ci		sh_eth_rcv_snd_enable(ndev);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if (new_state && netif_msg_link(mdp))
198562306a36Sopenharmony_ci		phy_print_status(phydev);
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci/* PHY init function */
198962306a36Sopenharmony_cistatic int sh_eth_phy_init(struct net_device *ndev)
199062306a36Sopenharmony_ci{
199162306a36Sopenharmony_ci	struct device_node *np = ndev->dev.parent->of_node;
199262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
199362306a36Sopenharmony_ci	struct phy_device *phydev;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	mdp->link = 0;
199662306a36Sopenharmony_ci	mdp->speed = 0;
199762306a36Sopenharmony_ci	mdp->duplex = -1;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/* Try connect to PHY */
200062306a36Sopenharmony_ci	if (np) {
200162306a36Sopenharmony_ci		struct device_node *pn;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci		pn = of_parse_phandle(np, "phy-handle", 0);
200462306a36Sopenharmony_ci		phydev = of_phy_connect(ndev, pn,
200562306a36Sopenharmony_ci					sh_eth_adjust_link, 0,
200662306a36Sopenharmony_ci					mdp->phy_interface);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci		of_node_put(pn);
200962306a36Sopenharmony_ci		if (!phydev)
201062306a36Sopenharmony_ci			phydev = ERR_PTR(-ENOENT);
201162306a36Sopenharmony_ci	} else {
201262306a36Sopenharmony_ci		char phy_id[MII_BUS_ID_SIZE + 3];
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
201562306a36Sopenharmony_ci			 mdp->mii_bus->id, mdp->phy_id);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci		phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
201862306a36Sopenharmony_ci				     mdp->phy_interface);
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	if (IS_ERR(phydev)) {
202262306a36Sopenharmony_ci		netdev_err(ndev, "failed to connect PHY\n");
202362306a36Sopenharmony_ci		return PTR_ERR(phydev);
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	/* mask with MAC supported features */
202762306a36Sopenharmony_ci	if (mdp->cd->register_type != SH_ETH_REG_GIGABIT)
202862306a36Sopenharmony_ci		phy_set_max_speed(phydev, SPEED_100);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	phy_attached_info(phydev);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	return 0;
203362306a36Sopenharmony_ci}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci/* PHY control start function */
203662306a36Sopenharmony_cistatic int sh_eth_phy_start(struct net_device *ndev)
203762306a36Sopenharmony_ci{
203862306a36Sopenharmony_ci	int ret;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	ret = sh_eth_phy_init(ndev);
204162306a36Sopenharmony_ci	if (ret)
204262306a36Sopenharmony_ci		return ret;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	phy_start(ndev->phydev);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	return 0;
204762306a36Sopenharmony_ci}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci/* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the
205062306a36Sopenharmony_ci * version must be bumped as well.  Just adding registers up to that
205162306a36Sopenharmony_ci * limit is fine, as long as the existing register indices don't
205262306a36Sopenharmony_ci * change.
205362306a36Sopenharmony_ci */
205462306a36Sopenharmony_ci#define SH_ETH_REG_DUMP_VERSION		1
205562306a36Sopenharmony_ci#define SH_ETH_REG_DUMP_MAX_REGS	256
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_cistatic size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf)
205862306a36Sopenharmony_ci{
205962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
206062306a36Sopenharmony_ci	struct sh_eth_cpu_data *cd = mdp->cd;
206162306a36Sopenharmony_ci	u32 *valid_map;
206262306a36Sopenharmony_ci	size_t len;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	BUILD_BUG_ON(SH_ETH_MAX_REGISTER_OFFSET > SH_ETH_REG_DUMP_MAX_REGS);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	/* Dump starts with a bitmap that tells ethtool which
206762306a36Sopenharmony_ci	 * registers are defined for this chip.
206862306a36Sopenharmony_ci	 */
206962306a36Sopenharmony_ci	len = DIV_ROUND_UP(SH_ETH_REG_DUMP_MAX_REGS, 32);
207062306a36Sopenharmony_ci	if (buf) {
207162306a36Sopenharmony_ci		valid_map = buf;
207262306a36Sopenharmony_ci		buf += len;
207362306a36Sopenharmony_ci	} else {
207462306a36Sopenharmony_ci		valid_map = NULL;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	/* Add a register to the dump, if it has a defined offset.
207862306a36Sopenharmony_ci	 * This automatically skips most undefined registers, but for
207962306a36Sopenharmony_ci	 * some it is also necessary to check a capability flag in
208062306a36Sopenharmony_ci	 * struct sh_eth_cpu_data.
208162306a36Sopenharmony_ci	 */
208262306a36Sopenharmony_ci#define mark_reg_valid(reg) valid_map[reg / 32] |= 1U << (reg % 32)
208362306a36Sopenharmony_ci#define add_reg_from(reg, read_expr) do {				\
208462306a36Sopenharmony_ci		if (mdp->reg_offset[reg] != SH_ETH_OFFSET_INVALID) {	\
208562306a36Sopenharmony_ci			if (buf) {					\
208662306a36Sopenharmony_ci				mark_reg_valid(reg);			\
208762306a36Sopenharmony_ci				*buf++ = read_expr;			\
208862306a36Sopenharmony_ci			}						\
208962306a36Sopenharmony_ci			++len;						\
209062306a36Sopenharmony_ci		}							\
209162306a36Sopenharmony_ci	} while (0)
209262306a36Sopenharmony_ci#define add_reg(reg) add_reg_from(reg, sh_eth_read(ndev, reg))
209362306a36Sopenharmony_ci#define add_tsu_reg(reg) add_reg_from(reg, sh_eth_tsu_read(mdp, reg))
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	add_reg(EDSR);
209662306a36Sopenharmony_ci	add_reg(EDMR);
209762306a36Sopenharmony_ci	add_reg(EDTRR);
209862306a36Sopenharmony_ci	add_reg(EDRRR);
209962306a36Sopenharmony_ci	add_reg(EESR);
210062306a36Sopenharmony_ci	add_reg(EESIPR);
210162306a36Sopenharmony_ci	add_reg(TDLAR);
210262306a36Sopenharmony_ci	if (!cd->no_xdfar)
210362306a36Sopenharmony_ci		add_reg(TDFAR);
210462306a36Sopenharmony_ci	add_reg(TDFXR);
210562306a36Sopenharmony_ci	add_reg(TDFFR);
210662306a36Sopenharmony_ci	add_reg(RDLAR);
210762306a36Sopenharmony_ci	if (!cd->no_xdfar)
210862306a36Sopenharmony_ci		add_reg(RDFAR);
210962306a36Sopenharmony_ci	add_reg(RDFXR);
211062306a36Sopenharmony_ci	add_reg(RDFFR);
211162306a36Sopenharmony_ci	add_reg(TRSCER);
211262306a36Sopenharmony_ci	add_reg(RMFCR);
211362306a36Sopenharmony_ci	add_reg(TFTR);
211462306a36Sopenharmony_ci	add_reg(FDR);
211562306a36Sopenharmony_ci	add_reg(RMCR);
211662306a36Sopenharmony_ci	add_reg(TFUCR);
211762306a36Sopenharmony_ci	add_reg(RFOCR);
211862306a36Sopenharmony_ci	if (cd->rmiimode)
211962306a36Sopenharmony_ci		add_reg(RMIIMODE);
212062306a36Sopenharmony_ci	add_reg(FCFTR);
212162306a36Sopenharmony_ci	if (cd->rpadir)
212262306a36Sopenharmony_ci		add_reg(RPADIR);
212362306a36Sopenharmony_ci	if (!cd->no_trimd)
212462306a36Sopenharmony_ci		add_reg(TRIMD);
212562306a36Sopenharmony_ci	add_reg(ECMR);
212662306a36Sopenharmony_ci	add_reg(ECSR);
212762306a36Sopenharmony_ci	add_reg(ECSIPR);
212862306a36Sopenharmony_ci	add_reg(PIR);
212962306a36Sopenharmony_ci	if (!cd->no_psr)
213062306a36Sopenharmony_ci		add_reg(PSR);
213162306a36Sopenharmony_ci	add_reg(RDMLR);
213262306a36Sopenharmony_ci	add_reg(RFLR);
213362306a36Sopenharmony_ci	add_reg(IPGR);
213462306a36Sopenharmony_ci	if (cd->apr)
213562306a36Sopenharmony_ci		add_reg(APR);
213662306a36Sopenharmony_ci	if (cd->mpr)
213762306a36Sopenharmony_ci		add_reg(MPR);
213862306a36Sopenharmony_ci	add_reg(RFCR);
213962306a36Sopenharmony_ci	add_reg(RFCF);
214062306a36Sopenharmony_ci	if (cd->tpauser)
214162306a36Sopenharmony_ci		add_reg(TPAUSER);
214262306a36Sopenharmony_ci	add_reg(TPAUSECR);
214362306a36Sopenharmony_ci	if (cd->gecmr)
214462306a36Sopenharmony_ci		add_reg(GECMR);
214562306a36Sopenharmony_ci	if (cd->bculr)
214662306a36Sopenharmony_ci		add_reg(BCULR);
214762306a36Sopenharmony_ci	add_reg(MAHR);
214862306a36Sopenharmony_ci	add_reg(MALR);
214962306a36Sopenharmony_ci	if (!cd->no_tx_cntrs) {
215062306a36Sopenharmony_ci		add_reg(TROCR);
215162306a36Sopenharmony_ci		add_reg(CDCR);
215262306a36Sopenharmony_ci		add_reg(LCCR);
215362306a36Sopenharmony_ci		add_reg(CNDCR);
215462306a36Sopenharmony_ci	}
215562306a36Sopenharmony_ci	add_reg(CEFCR);
215662306a36Sopenharmony_ci	add_reg(FRECR);
215762306a36Sopenharmony_ci	add_reg(TSFRCR);
215862306a36Sopenharmony_ci	add_reg(TLFRCR);
215962306a36Sopenharmony_ci	if (cd->cexcr) {
216062306a36Sopenharmony_ci		add_reg(CERCR);
216162306a36Sopenharmony_ci		add_reg(CEECR);
216262306a36Sopenharmony_ci	}
216362306a36Sopenharmony_ci	add_reg(MAFCR);
216462306a36Sopenharmony_ci	if (cd->rtrate)
216562306a36Sopenharmony_ci		add_reg(RTRATE);
216662306a36Sopenharmony_ci	if (cd->csmr)
216762306a36Sopenharmony_ci		add_reg(CSMR);
216862306a36Sopenharmony_ci	if (cd->select_mii)
216962306a36Sopenharmony_ci		add_reg(RMII_MII);
217062306a36Sopenharmony_ci	if (cd->tsu) {
217162306a36Sopenharmony_ci		add_tsu_reg(ARSTR);
217262306a36Sopenharmony_ci		add_tsu_reg(TSU_CTRST);
217362306a36Sopenharmony_ci		if (cd->dual_port) {
217462306a36Sopenharmony_ci			add_tsu_reg(TSU_FWEN0);
217562306a36Sopenharmony_ci			add_tsu_reg(TSU_FWEN1);
217662306a36Sopenharmony_ci			add_tsu_reg(TSU_FCM);
217762306a36Sopenharmony_ci			add_tsu_reg(TSU_BSYSL0);
217862306a36Sopenharmony_ci			add_tsu_reg(TSU_BSYSL1);
217962306a36Sopenharmony_ci			add_tsu_reg(TSU_PRISL0);
218062306a36Sopenharmony_ci			add_tsu_reg(TSU_PRISL1);
218162306a36Sopenharmony_ci			add_tsu_reg(TSU_FWSL0);
218262306a36Sopenharmony_ci			add_tsu_reg(TSU_FWSL1);
218362306a36Sopenharmony_ci		}
218462306a36Sopenharmony_ci		add_tsu_reg(TSU_FWSLC);
218562306a36Sopenharmony_ci		if (cd->dual_port) {
218662306a36Sopenharmony_ci			add_tsu_reg(TSU_QTAGM0);
218762306a36Sopenharmony_ci			add_tsu_reg(TSU_QTAGM1);
218862306a36Sopenharmony_ci			add_tsu_reg(TSU_FWSR);
218962306a36Sopenharmony_ci			add_tsu_reg(TSU_FWINMK);
219062306a36Sopenharmony_ci			add_tsu_reg(TSU_ADQT0);
219162306a36Sopenharmony_ci			add_tsu_reg(TSU_ADQT1);
219262306a36Sopenharmony_ci			add_tsu_reg(TSU_VTAG0);
219362306a36Sopenharmony_ci			add_tsu_reg(TSU_VTAG1);
219462306a36Sopenharmony_ci		}
219562306a36Sopenharmony_ci		add_tsu_reg(TSU_ADSBSY);
219662306a36Sopenharmony_ci		add_tsu_reg(TSU_TEN);
219762306a36Sopenharmony_ci		add_tsu_reg(TSU_POST1);
219862306a36Sopenharmony_ci		add_tsu_reg(TSU_POST2);
219962306a36Sopenharmony_ci		add_tsu_reg(TSU_POST3);
220062306a36Sopenharmony_ci		add_tsu_reg(TSU_POST4);
220162306a36Sopenharmony_ci		/* This is the start of a table, not just a single register. */
220262306a36Sopenharmony_ci		if (buf) {
220362306a36Sopenharmony_ci			unsigned int i;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci			mark_reg_valid(TSU_ADRH0);
220662306a36Sopenharmony_ci			for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES * 2; i++)
220762306a36Sopenharmony_ci				*buf++ = ioread32(mdp->tsu_addr +
220862306a36Sopenharmony_ci						  mdp->reg_offset[TSU_ADRH0] +
220962306a36Sopenharmony_ci						  i * 4);
221062306a36Sopenharmony_ci		}
221162306a36Sopenharmony_ci		len += SH_ETH_TSU_CAM_ENTRIES * 2;
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci#undef mark_reg_valid
221562306a36Sopenharmony_ci#undef add_reg_from
221662306a36Sopenharmony_ci#undef add_reg
221762306a36Sopenharmony_ci#undef add_tsu_reg
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	return len * 4;
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic int sh_eth_get_regs_len(struct net_device *ndev)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	return __sh_eth_get_regs(ndev, NULL);
222562306a36Sopenharmony_ci}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_cistatic void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs,
222862306a36Sopenharmony_ci			    void *buf)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	regs->version = SH_ETH_REG_DUMP_VERSION;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	pm_runtime_get_sync(&mdp->pdev->dev);
223562306a36Sopenharmony_ci	__sh_eth_get_regs(ndev, buf);
223662306a36Sopenharmony_ci	pm_runtime_put_sync(&mdp->pdev->dev);
223762306a36Sopenharmony_ci}
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_cistatic u32 sh_eth_get_msglevel(struct net_device *ndev)
224062306a36Sopenharmony_ci{
224162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
224262306a36Sopenharmony_ci	return mdp->msg_enable;
224362306a36Sopenharmony_ci}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_cistatic void sh_eth_set_msglevel(struct net_device *ndev, u32 value)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
224862306a36Sopenharmony_ci	mdp->msg_enable = value;
224962306a36Sopenharmony_ci}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_cistatic const char sh_eth_gstrings_stats[][ETH_GSTRING_LEN] = {
225262306a36Sopenharmony_ci	"rx_current", "tx_current",
225362306a36Sopenharmony_ci	"rx_dirty", "tx_dirty",
225462306a36Sopenharmony_ci};
225562306a36Sopenharmony_ci#define SH_ETH_STATS_LEN  ARRAY_SIZE(sh_eth_gstrings_stats)
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_cistatic int sh_eth_get_sset_count(struct net_device *netdev, int sset)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	switch (sset) {
226062306a36Sopenharmony_ci	case ETH_SS_STATS:
226162306a36Sopenharmony_ci		return SH_ETH_STATS_LEN;
226262306a36Sopenharmony_ci	default:
226362306a36Sopenharmony_ci		return -EOPNOTSUPP;
226462306a36Sopenharmony_ci	}
226562306a36Sopenharmony_ci}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_cistatic void sh_eth_get_ethtool_stats(struct net_device *ndev,
226862306a36Sopenharmony_ci				     struct ethtool_stats *stats, u64 *data)
226962306a36Sopenharmony_ci{
227062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
227162306a36Sopenharmony_ci	int i = 0;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	/* device-specific stats */
227462306a36Sopenharmony_ci	data[i++] = mdp->cur_rx;
227562306a36Sopenharmony_ci	data[i++] = mdp->cur_tx;
227662306a36Sopenharmony_ci	data[i++] = mdp->dirty_rx;
227762306a36Sopenharmony_ci	data[i++] = mdp->dirty_tx;
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
228162306a36Sopenharmony_ci{
228262306a36Sopenharmony_ci	switch (stringset) {
228362306a36Sopenharmony_ci	case ETH_SS_STATS:
228462306a36Sopenharmony_ci		memcpy(data, sh_eth_gstrings_stats,
228562306a36Sopenharmony_ci		       sizeof(sh_eth_gstrings_stats));
228662306a36Sopenharmony_ci		break;
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_cistatic void sh_eth_get_ringparam(struct net_device *ndev,
229162306a36Sopenharmony_ci				 struct ethtool_ringparam *ring,
229262306a36Sopenharmony_ci				 struct kernel_ethtool_ringparam *kernel_ring,
229362306a36Sopenharmony_ci				 struct netlink_ext_ack *extack)
229462306a36Sopenharmony_ci{
229562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	ring->rx_max_pending = RX_RING_MAX;
229862306a36Sopenharmony_ci	ring->tx_max_pending = TX_RING_MAX;
229962306a36Sopenharmony_ci	ring->rx_pending = mdp->num_rx_ring;
230062306a36Sopenharmony_ci	ring->tx_pending = mdp->num_tx_ring;
230162306a36Sopenharmony_ci}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_cistatic int sh_eth_set_ringparam(struct net_device *ndev,
230462306a36Sopenharmony_ci				struct ethtool_ringparam *ring,
230562306a36Sopenharmony_ci				struct kernel_ethtool_ringparam *kernel_ring,
230662306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
230962306a36Sopenharmony_ci	int ret;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	if (ring->tx_pending > TX_RING_MAX ||
231262306a36Sopenharmony_ci	    ring->rx_pending > RX_RING_MAX ||
231362306a36Sopenharmony_ci	    ring->tx_pending < TX_RING_MIN ||
231462306a36Sopenharmony_ci	    ring->rx_pending < RX_RING_MIN)
231562306a36Sopenharmony_ci		return -EINVAL;
231662306a36Sopenharmony_ci	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
231762306a36Sopenharmony_ci		return -EINVAL;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (netif_running(ndev)) {
232062306a36Sopenharmony_ci		netif_device_detach(ndev);
232162306a36Sopenharmony_ci		netif_tx_disable(ndev);
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		/* Serialise with the interrupt handler and NAPI, then
232462306a36Sopenharmony_ci		 * disable interrupts.  We have to clear the
232562306a36Sopenharmony_ci		 * irq_enabled flag first to ensure that interrupts
232662306a36Sopenharmony_ci		 * won't be re-enabled.
232762306a36Sopenharmony_ci		 */
232862306a36Sopenharmony_ci		mdp->irq_enabled = false;
232962306a36Sopenharmony_ci		synchronize_irq(ndev->irq);
233062306a36Sopenharmony_ci		napi_synchronize(&mdp->napi);
233162306a36Sopenharmony_ci		sh_eth_write(ndev, 0x0000, EESIPR);
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci		sh_eth_dev_exit(ndev);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci		/* Free all the skbuffs in the Rx queue and the DMA buffers. */
233662306a36Sopenharmony_ci		sh_eth_ring_free(ndev);
233762306a36Sopenharmony_ci	}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	/* Set new parameters */
234062306a36Sopenharmony_ci	mdp->num_rx_ring = ring->rx_pending;
234162306a36Sopenharmony_ci	mdp->num_tx_ring = ring->tx_pending;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	if (netif_running(ndev)) {
234462306a36Sopenharmony_ci		ret = sh_eth_ring_init(ndev);
234562306a36Sopenharmony_ci		if (ret < 0) {
234662306a36Sopenharmony_ci			netdev_err(ndev, "%s: sh_eth_ring_init failed.\n",
234762306a36Sopenharmony_ci				   __func__);
234862306a36Sopenharmony_ci			return ret;
234962306a36Sopenharmony_ci		}
235062306a36Sopenharmony_ci		ret = sh_eth_dev_init(ndev);
235162306a36Sopenharmony_ci		if (ret < 0) {
235262306a36Sopenharmony_ci			netdev_err(ndev, "%s: sh_eth_dev_init failed.\n",
235362306a36Sopenharmony_ci				   __func__);
235462306a36Sopenharmony_ci			return ret;
235562306a36Sopenharmony_ci		}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci		netif_device_attach(ndev);
235862306a36Sopenharmony_ci	}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	return 0;
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_cistatic void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	wol->supported = 0;
236862306a36Sopenharmony_ci	wol->wolopts = 0;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	if (mdp->cd->magic) {
237162306a36Sopenharmony_ci		wol->supported = WAKE_MAGIC;
237262306a36Sopenharmony_ci		wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0;
237362306a36Sopenharmony_ci	}
237462306a36Sopenharmony_ci}
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_cistatic int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC)
238162306a36Sopenharmony_ci		return -EOPNOTSUPP;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC);
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	device_set_wakeup_enable(&mdp->pdev->dev, mdp->wol_enabled);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	return 0;
238862306a36Sopenharmony_ci}
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_cistatic const struct ethtool_ops sh_eth_ethtool_ops = {
239162306a36Sopenharmony_ci	.get_regs_len	= sh_eth_get_regs_len,
239262306a36Sopenharmony_ci	.get_regs	= sh_eth_get_regs,
239362306a36Sopenharmony_ci	.nway_reset	= phy_ethtool_nway_reset,
239462306a36Sopenharmony_ci	.get_msglevel	= sh_eth_get_msglevel,
239562306a36Sopenharmony_ci	.set_msglevel	= sh_eth_set_msglevel,
239662306a36Sopenharmony_ci	.get_link	= ethtool_op_get_link,
239762306a36Sopenharmony_ci	.get_strings	= sh_eth_get_strings,
239862306a36Sopenharmony_ci	.get_ethtool_stats  = sh_eth_get_ethtool_stats,
239962306a36Sopenharmony_ci	.get_sset_count     = sh_eth_get_sset_count,
240062306a36Sopenharmony_ci	.get_ringparam	= sh_eth_get_ringparam,
240162306a36Sopenharmony_ci	.set_ringparam	= sh_eth_set_ringparam,
240262306a36Sopenharmony_ci	.get_link_ksettings = phy_ethtool_get_link_ksettings,
240362306a36Sopenharmony_ci	.set_link_ksettings = phy_ethtool_set_link_ksettings,
240462306a36Sopenharmony_ci	.get_wol	= sh_eth_get_wol,
240562306a36Sopenharmony_ci	.set_wol	= sh_eth_set_wol,
240662306a36Sopenharmony_ci};
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci/* network device open function */
240962306a36Sopenharmony_cistatic int sh_eth_open(struct net_device *ndev)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
241262306a36Sopenharmony_ci	int ret;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	pm_runtime_get_sync(&mdp->pdev->dev);
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	napi_enable(&mdp->napi);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	ret = request_irq(ndev->irq, sh_eth_interrupt,
241962306a36Sopenharmony_ci			  mdp->cd->irq_flags, ndev->name, ndev);
242062306a36Sopenharmony_ci	if (ret) {
242162306a36Sopenharmony_ci		netdev_err(ndev, "Can not assign IRQ number\n");
242262306a36Sopenharmony_ci		goto out_napi_off;
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	/* Descriptor set */
242662306a36Sopenharmony_ci	ret = sh_eth_ring_init(ndev);
242762306a36Sopenharmony_ci	if (ret)
242862306a36Sopenharmony_ci		goto out_free_irq;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	/* device init */
243162306a36Sopenharmony_ci	ret = sh_eth_dev_init(ndev);
243262306a36Sopenharmony_ci	if (ret)
243362306a36Sopenharmony_ci		goto out_free_irq;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	/* PHY control start*/
243662306a36Sopenharmony_ci	ret = sh_eth_phy_start(ndev);
243762306a36Sopenharmony_ci	if (ret)
243862306a36Sopenharmony_ci		goto out_free_irq;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	netif_start_queue(ndev);
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	mdp->is_opened = 1;
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	return ret;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ciout_free_irq:
244762306a36Sopenharmony_ci	free_irq(ndev->irq, ndev);
244862306a36Sopenharmony_ciout_napi_off:
244962306a36Sopenharmony_ci	napi_disable(&mdp->napi);
245062306a36Sopenharmony_ci	pm_runtime_put_sync(&mdp->pdev->dev);
245162306a36Sopenharmony_ci	return ret;
245262306a36Sopenharmony_ci}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci/* Timeout function */
245562306a36Sopenharmony_cistatic void sh_eth_tx_timeout(struct net_device *ndev, unsigned int txqueue)
245662306a36Sopenharmony_ci{
245762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
245862306a36Sopenharmony_ci	struct sh_eth_rxdesc *rxdesc;
245962306a36Sopenharmony_ci	int i;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	netif_stop_queue(ndev);
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	netif_err(mdp, timer, ndev,
246462306a36Sopenharmony_ci		  "transmit timed out, status %8.8x, resetting...\n",
246562306a36Sopenharmony_ci		  sh_eth_read(ndev, EESR));
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	/* tx_errors count up */
246862306a36Sopenharmony_ci	ndev->stats.tx_errors++;
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	/* Free all the skbuffs in the Rx queue. */
247162306a36Sopenharmony_ci	for (i = 0; i < mdp->num_rx_ring; i++) {
247262306a36Sopenharmony_ci		rxdesc = &mdp->rx_ring[i];
247362306a36Sopenharmony_ci		rxdesc->status = cpu_to_le32(0);
247462306a36Sopenharmony_ci		rxdesc->addr = cpu_to_le32(0xBADF00D0);
247562306a36Sopenharmony_ci		dev_kfree_skb(mdp->rx_skbuff[i]);
247662306a36Sopenharmony_ci		mdp->rx_skbuff[i] = NULL;
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci	for (i = 0; i < mdp->num_tx_ring; i++) {
247962306a36Sopenharmony_ci		dev_kfree_skb(mdp->tx_skbuff[i]);
248062306a36Sopenharmony_ci		mdp->tx_skbuff[i] = NULL;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	/* device init */
248462306a36Sopenharmony_ci	sh_eth_dev_init(ndev);
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	netif_start_queue(ndev);
248762306a36Sopenharmony_ci}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci/* Packet transmit function */
249062306a36Sopenharmony_cistatic netdev_tx_t sh_eth_start_xmit(struct sk_buff *skb,
249162306a36Sopenharmony_ci				     struct net_device *ndev)
249262306a36Sopenharmony_ci{
249362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
249462306a36Sopenharmony_ci	struct sh_eth_txdesc *txdesc;
249562306a36Sopenharmony_ci	dma_addr_t dma_addr;
249662306a36Sopenharmony_ci	u32 entry;
249762306a36Sopenharmony_ci	unsigned long flags;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
250062306a36Sopenharmony_ci	if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) {
250162306a36Sopenharmony_ci		if (!sh_eth_tx_free(ndev, true)) {
250262306a36Sopenharmony_ci			netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n");
250362306a36Sopenharmony_ci			netif_stop_queue(ndev);
250462306a36Sopenharmony_ci			spin_unlock_irqrestore(&mdp->lock, flags);
250562306a36Sopenharmony_ci			return NETDEV_TX_BUSY;
250662306a36Sopenharmony_ci		}
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	if (skb_put_padto(skb, ETH_ZLEN))
251162306a36Sopenharmony_ci		return NETDEV_TX_OK;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	entry = mdp->cur_tx % mdp->num_tx_ring;
251462306a36Sopenharmony_ci	mdp->tx_skbuff[entry] = skb;
251562306a36Sopenharmony_ci	txdesc = &mdp->tx_ring[entry];
251662306a36Sopenharmony_ci	/* soft swap. */
251762306a36Sopenharmony_ci	if (!mdp->cd->hw_swap)
251862306a36Sopenharmony_ci		sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2);
251962306a36Sopenharmony_ci	dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, skb->len,
252062306a36Sopenharmony_ci				  DMA_TO_DEVICE);
252162306a36Sopenharmony_ci	if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) {
252262306a36Sopenharmony_ci		kfree_skb(skb);
252362306a36Sopenharmony_ci		return NETDEV_TX_OK;
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci	txdesc->addr = cpu_to_le32(dma_addr);
252662306a36Sopenharmony_ci	txdesc->len  = cpu_to_le32(skb->len << 16);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	dma_wmb(); /* TACT bit must be set after all the above writes */
252962306a36Sopenharmony_ci	if (entry >= mdp->num_tx_ring - 1)
253062306a36Sopenharmony_ci		txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE);
253162306a36Sopenharmony_ci	else
253262306a36Sopenharmony_ci		txdesc->status |= cpu_to_le32(TD_TACT);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	wmb(); /* cur_tx must be incremented after TACT bit was set */
253562306a36Sopenharmony_ci	mdp->cur_tx++;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (!(sh_eth_read(ndev, EDTRR) & mdp->cd->edtrr_trns))
253862306a36Sopenharmony_ci		sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	return NETDEV_TX_OK;
254162306a36Sopenharmony_ci}
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci/* The statistics registers have write-clear behaviour, which means we
254462306a36Sopenharmony_ci * will lose any increment between the read and write.  We mitigate
254562306a36Sopenharmony_ci * this by only clearing when we read a non-zero value, so we will
254662306a36Sopenharmony_ci * never falsely report a total of zero.
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_cistatic void
254962306a36Sopenharmony_cish_eth_update_stat(struct net_device *ndev, unsigned long *stat, int reg)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	u32 delta = sh_eth_read(ndev, reg);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	if (delta) {
255462306a36Sopenharmony_ci		*stat += delta;
255562306a36Sopenharmony_ci		sh_eth_write(ndev, 0, reg);
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
256062306a36Sopenharmony_ci{
256162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	if (mdp->cd->no_tx_cntrs)
256462306a36Sopenharmony_ci		return &ndev->stats;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	if (!mdp->is_opened)
256762306a36Sopenharmony_ci		return &ndev->stats;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.tx_dropped, TROCR);
257062306a36Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.collisions, CDCR);
257162306a36Sopenharmony_ci	sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, LCCR);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (mdp->cd->cexcr) {
257462306a36Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
257562306a36Sopenharmony_ci				   CERCR);
257662306a36Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
257762306a36Sopenharmony_ci				   CEECR);
257862306a36Sopenharmony_ci	} else {
257962306a36Sopenharmony_ci		sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors,
258062306a36Sopenharmony_ci				   CNDCR);
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	return &ndev->stats;
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci/* device close function */
258762306a36Sopenharmony_cistatic int sh_eth_close(struct net_device *ndev)
258862306a36Sopenharmony_ci{
258962306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	netif_stop_queue(ndev);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* Serialise with the interrupt handler and NAPI, then disable
259462306a36Sopenharmony_ci	 * interrupts.  We have to clear the irq_enabled flag first to
259562306a36Sopenharmony_ci	 * ensure that interrupts won't be re-enabled.
259662306a36Sopenharmony_ci	 */
259762306a36Sopenharmony_ci	mdp->irq_enabled = false;
259862306a36Sopenharmony_ci	synchronize_irq(ndev->irq);
259962306a36Sopenharmony_ci	napi_disable(&mdp->napi);
260062306a36Sopenharmony_ci	sh_eth_write(ndev, 0x0000, EESIPR);
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	sh_eth_dev_exit(ndev);
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	/* PHY Disconnect */
260562306a36Sopenharmony_ci	if (ndev->phydev) {
260662306a36Sopenharmony_ci		phy_stop(ndev->phydev);
260762306a36Sopenharmony_ci		phy_disconnect(ndev->phydev);
260862306a36Sopenharmony_ci	}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	free_irq(ndev->irq, ndev);
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	/* Free all the skbuffs in the Rx queue and the DMA buffer. */
261362306a36Sopenharmony_ci	sh_eth_ring_free(ndev);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	mdp->is_opened = 0;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	pm_runtime_put(&mdp->pdev->dev);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	return 0;
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_cistatic int sh_eth_change_mtu(struct net_device *ndev, int new_mtu)
262362306a36Sopenharmony_ci{
262462306a36Sopenharmony_ci	if (netif_running(ndev))
262562306a36Sopenharmony_ci		return -EBUSY;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	ndev->mtu = new_mtu;
262862306a36Sopenharmony_ci	netdev_update_features(ndev);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	return 0;
263162306a36Sopenharmony_ci}
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci/* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */
263462306a36Sopenharmony_cistatic u32 sh_eth_tsu_get_post_mask(int entry)
263562306a36Sopenharmony_ci{
263662306a36Sopenharmony_ci	return 0x0f << (28 - ((entry % 8) * 4));
263762306a36Sopenharmony_ci}
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_cistatic u32 sh_eth_tsu_get_post_bit(struct sh_eth_private *mdp, int entry)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	return (0x08 >> (mdp->port << 1)) << (28 - ((entry % 8) * 4));
264262306a36Sopenharmony_ci}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_cistatic void sh_eth_tsu_enable_cam_entry_post(struct net_device *ndev,
264562306a36Sopenharmony_ci					     int entry)
264662306a36Sopenharmony_ci{
264762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
264862306a36Sopenharmony_ci	int reg = TSU_POST1 + entry / 8;
264962306a36Sopenharmony_ci	u32 tmp;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	tmp = sh_eth_tsu_read(mdp, reg);
265262306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, tmp | sh_eth_tsu_get_post_bit(mdp, entry), reg);
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic bool sh_eth_tsu_disable_cam_entry_post(struct net_device *ndev,
265662306a36Sopenharmony_ci					      int entry)
265762306a36Sopenharmony_ci{
265862306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
265962306a36Sopenharmony_ci	int reg = TSU_POST1 + entry / 8;
266062306a36Sopenharmony_ci	u32 post_mask, ref_mask, tmp;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	post_mask = sh_eth_tsu_get_post_mask(entry);
266362306a36Sopenharmony_ci	ref_mask = sh_eth_tsu_get_post_bit(mdp, entry) & ~post_mask;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	tmp = sh_eth_tsu_read(mdp, reg);
266662306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, tmp & ~post_mask, reg);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	/* If other port enables, the function returns "true" */
266962306a36Sopenharmony_ci	return tmp & ref_mask;
267062306a36Sopenharmony_ci}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_cistatic int sh_eth_tsu_busy(struct net_device *ndev)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	int timeout = SH_ETH_TSU_TIMEOUT_MS * 100;
267562306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	while ((sh_eth_tsu_read(mdp, TSU_ADSBSY) & TSU_ADSBSY_0)) {
267862306a36Sopenharmony_ci		udelay(10);
267962306a36Sopenharmony_ci		timeout--;
268062306a36Sopenharmony_ci		if (timeout <= 0) {
268162306a36Sopenharmony_ci			netdev_err(ndev, "%s: timeout\n", __func__);
268262306a36Sopenharmony_ci			return -ETIMEDOUT;
268362306a36Sopenharmony_ci		}
268462306a36Sopenharmony_ci	}
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	return 0;
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_cistatic int sh_eth_tsu_write_entry(struct net_device *ndev, u16 offset,
269062306a36Sopenharmony_ci				  const u8 *addr)
269162306a36Sopenharmony_ci{
269262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
269362306a36Sopenharmony_ci	u32 val;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	val = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3];
269662306a36Sopenharmony_ci	iowrite32(val, mdp->tsu_addr + offset);
269762306a36Sopenharmony_ci	if (sh_eth_tsu_busy(ndev) < 0)
269862306a36Sopenharmony_ci		return -EBUSY;
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	val = addr[4] << 8 | addr[5];
270162306a36Sopenharmony_ci	iowrite32(val, mdp->tsu_addr + offset + 4);
270262306a36Sopenharmony_ci	if (sh_eth_tsu_busy(ndev) < 0)
270362306a36Sopenharmony_ci		return -EBUSY;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	return 0;
270662306a36Sopenharmony_ci}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_cistatic void sh_eth_tsu_read_entry(struct net_device *ndev, u16 offset, u8 *addr)
270962306a36Sopenharmony_ci{
271062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
271162306a36Sopenharmony_ci	u32 val;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	val = ioread32(mdp->tsu_addr + offset);
271462306a36Sopenharmony_ci	addr[0] = (val >> 24) & 0xff;
271562306a36Sopenharmony_ci	addr[1] = (val >> 16) & 0xff;
271662306a36Sopenharmony_ci	addr[2] = (val >> 8) & 0xff;
271762306a36Sopenharmony_ci	addr[3] = val & 0xff;
271862306a36Sopenharmony_ci	val = ioread32(mdp->tsu_addr + offset + 4);
271962306a36Sopenharmony_ci	addr[4] = (val >> 8) & 0xff;
272062306a36Sopenharmony_ci	addr[5] = val & 0xff;
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_cistatic int sh_eth_tsu_find_entry(struct net_device *ndev, const u8 *addr)
272562306a36Sopenharmony_ci{
272662306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
272762306a36Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
272862306a36Sopenharmony_ci	int i;
272962306a36Sopenharmony_ci	u8 c_addr[ETH_ALEN];
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
273262306a36Sopenharmony_ci		sh_eth_tsu_read_entry(ndev, reg_offset, c_addr);
273362306a36Sopenharmony_ci		if (ether_addr_equal(addr, c_addr))
273462306a36Sopenharmony_ci			return i;
273562306a36Sopenharmony_ci	}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	return -ENOENT;
273862306a36Sopenharmony_ci}
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_cistatic int sh_eth_tsu_find_empty(struct net_device *ndev)
274162306a36Sopenharmony_ci{
274262306a36Sopenharmony_ci	u8 blank[ETH_ALEN];
274362306a36Sopenharmony_ci	int entry;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	memset(blank, 0, sizeof(blank));
274662306a36Sopenharmony_ci	entry = sh_eth_tsu_find_entry(ndev, blank);
274762306a36Sopenharmony_ci	return (entry < 0) ? -ENOMEM : entry;
274862306a36Sopenharmony_ci}
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_cistatic int sh_eth_tsu_disable_cam_entry_table(struct net_device *ndev,
275162306a36Sopenharmony_ci					      int entry)
275262306a36Sopenharmony_ci{
275362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
275462306a36Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
275562306a36Sopenharmony_ci	int ret;
275662306a36Sopenharmony_ci	u8 blank[ETH_ALEN];
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) &
275962306a36Sopenharmony_ci			 ~(1 << (31 - entry)), TSU_TEN);
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	memset(blank, 0, sizeof(blank));
276262306a36Sopenharmony_ci	ret = sh_eth_tsu_write_entry(ndev, reg_offset + entry * 8, blank);
276362306a36Sopenharmony_ci	if (ret < 0)
276462306a36Sopenharmony_ci		return ret;
276562306a36Sopenharmony_ci	return 0;
276662306a36Sopenharmony_ci}
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_cistatic int sh_eth_tsu_add_entry(struct net_device *ndev, const u8 *addr)
276962306a36Sopenharmony_ci{
277062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
277162306a36Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
277262306a36Sopenharmony_ci	int i, ret;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	if (!mdp->cd->tsu)
277562306a36Sopenharmony_ci		return 0;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	i = sh_eth_tsu_find_entry(ndev, addr);
277862306a36Sopenharmony_ci	if (i < 0) {
277962306a36Sopenharmony_ci		/* No entry found, create one */
278062306a36Sopenharmony_ci		i = sh_eth_tsu_find_empty(ndev);
278162306a36Sopenharmony_ci		if (i < 0)
278262306a36Sopenharmony_ci			return -ENOMEM;
278362306a36Sopenharmony_ci		ret = sh_eth_tsu_write_entry(ndev, reg_offset + i * 8, addr);
278462306a36Sopenharmony_ci		if (ret < 0)
278562306a36Sopenharmony_ci			return ret;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		/* Enable the entry */
278862306a36Sopenharmony_ci		sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) |
278962306a36Sopenharmony_ci				 (1 << (31 - i)), TSU_TEN);
279062306a36Sopenharmony_ci	}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	/* Entry found or created, enable POST */
279362306a36Sopenharmony_ci	sh_eth_tsu_enable_cam_entry_post(ndev, i);
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	return 0;
279662306a36Sopenharmony_ci}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_cistatic int sh_eth_tsu_del_entry(struct net_device *ndev, const u8 *addr)
279962306a36Sopenharmony_ci{
280062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
280162306a36Sopenharmony_ci	int i, ret;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (!mdp->cd->tsu)
280462306a36Sopenharmony_ci		return 0;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	i = sh_eth_tsu_find_entry(ndev, addr);
280762306a36Sopenharmony_ci	if (i) {
280862306a36Sopenharmony_ci		/* Entry found */
280962306a36Sopenharmony_ci		if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
281062306a36Sopenharmony_ci			goto done;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci		/* Disable the entry if both ports was disabled */
281362306a36Sopenharmony_ci		ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
281462306a36Sopenharmony_ci		if (ret < 0)
281562306a36Sopenharmony_ci			return ret;
281662306a36Sopenharmony_ci	}
281762306a36Sopenharmony_cidone:
281862306a36Sopenharmony_ci	return 0;
281962306a36Sopenharmony_ci}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_cistatic int sh_eth_tsu_purge_all(struct net_device *ndev)
282262306a36Sopenharmony_ci{
282362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
282462306a36Sopenharmony_ci	int i, ret;
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	if (!mdp->cd->tsu)
282762306a36Sopenharmony_ci		return 0;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) {
283062306a36Sopenharmony_ci		if (sh_eth_tsu_disable_cam_entry_post(ndev, i))
283162306a36Sopenharmony_ci			continue;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci		/* Disable the entry if both ports was disabled */
283462306a36Sopenharmony_ci		ret = sh_eth_tsu_disable_cam_entry_table(ndev, i);
283562306a36Sopenharmony_ci		if (ret < 0)
283662306a36Sopenharmony_ci			return ret;
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	return 0;
284062306a36Sopenharmony_ci}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_cistatic void sh_eth_tsu_purge_mcast(struct net_device *ndev)
284362306a36Sopenharmony_ci{
284462306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
284562306a36Sopenharmony_ci	u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
284662306a36Sopenharmony_ci	u8 addr[ETH_ALEN];
284762306a36Sopenharmony_ci	int i;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	if (!mdp->cd->tsu)
285062306a36Sopenharmony_ci		return;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
285362306a36Sopenharmony_ci		sh_eth_tsu_read_entry(ndev, reg_offset, addr);
285462306a36Sopenharmony_ci		if (is_multicast_ether_addr(addr))
285562306a36Sopenharmony_ci			sh_eth_tsu_del_entry(ndev, addr);
285662306a36Sopenharmony_ci	}
285762306a36Sopenharmony_ci}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci/* Update promiscuous flag and multicast filter */
286062306a36Sopenharmony_cistatic void sh_eth_set_rx_mode(struct net_device *ndev)
286162306a36Sopenharmony_ci{
286262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
286362306a36Sopenharmony_ci	u32 ecmr_bits;
286462306a36Sopenharmony_ci	int mcast_all = 0;
286562306a36Sopenharmony_ci	unsigned long flags;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
286862306a36Sopenharmony_ci	/* Initial condition is MCT = 1, PRM = 0.
286962306a36Sopenharmony_ci	 * Depending on ndev->flags, set PRM or clear MCT
287062306a36Sopenharmony_ci	 */
287162306a36Sopenharmony_ci	ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM;
287262306a36Sopenharmony_ci	if (mdp->cd->tsu)
287362306a36Sopenharmony_ci		ecmr_bits |= ECMR_MCT;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (!(ndev->flags & IFF_MULTICAST)) {
287662306a36Sopenharmony_ci		sh_eth_tsu_purge_mcast(ndev);
287762306a36Sopenharmony_ci		mcast_all = 1;
287862306a36Sopenharmony_ci	}
287962306a36Sopenharmony_ci	if (ndev->flags & IFF_ALLMULTI) {
288062306a36Sopenharmony_ci		sh_eth_tsu_purge_mcast(ndev);
288162306a36Sopenharmony_ci		ecmr_bits &= ~ECMR_MCT;
288262306a36Sopenharmony_ci		mcast_all = 1;
288362306a36Sopenharmony_ci	}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	if (ndev->flags & IFF_PROMISC) {
288662306a36Sopenharmony_ci		sh_eth_tsu_purge_all(ndev);
288762306a36Sopenharmony_ci		ecmr_bits = (ecmr_bits & ~ECMR_MCT) | ECMR_PRM;
288862306a36Sopenharmony_ci	} else if (mdp->cd->tsu) {
288962306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
289062306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, ndev) {
289162306a36Sopenharmony_ci			if (mcast_all && is_multicast_ether_addr(ha->addr))
289262306a36Sopenharmony_ci				continue;
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci			if (sh_eth_tsu_add_entry(ndev, ha->addr) < 0) {
289562306a36Sopenharmony_ci				if (!mcast_all) {
289662306a36Sopenharmony_ci					sh_eth_tsu_purge_mcast(ndev);
289762306a36Sopenharmony_ci					ecmr_bits &= ~ECMR_MCT;
289862306a36Sopenharmony_ci					mcast_all = 1;
289962306a36Sopenharmony_ci				}
290062306a36Sopenharmony_ci			}
290162306a36Sopenharmony_ci		}
290262306a36Sopenharmony_ci	}
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	/* update the ethernet mode */
290562306a36Sopenharmony_ci	sh_eth_write(ndev, ecmr_bits, ECMR);
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
290862306a36Sopenharmony_ci}
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_cistatic void sh_eth_set_rx_csum(struct net_device *ndev, bool enable)
291162306a36Sopenharmony_ci{
291262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
291362306a36Sopenharmony_ci	unsigned long flags;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	spin_lock_irqsave(&mdp->lock, flags);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	/* Disable TX and RX */
291862306a36Sopenharmony_ci	sh_eth_rcv_snd_disable(ndev);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	/* Modify RX Checksum setting */
292162306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_RCSC, enable ? ECMR_RCSC : 0);
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	/* Enable TX and RX */
292462306a36Sopenharmony_ci	sh_eth_rcv_snd_enable(ndev);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	spin_unlock_irqrestore(&mdp->lock, flags);
292762306a36Sopenharmony_ci}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_cistatic int sh_eth_set_features(struct net_device *ndev,
293062306a36Sopenharmony_ci			       netdev_features_t features)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	netdev_features_t changed = ndev->features ^ features;
293362306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	if (changed & NETIF_F_RXCSUM && mdp->cd->rx_csum)
293662306a36Sopenharmony_ci		sh_eth_set_rx_csum(ndev, features & NETIF_F_RXCSUM);
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	ndev->features = features;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	return 0;
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_cistatic int sh_eth_get_vtag_index(struct sh_eth_private *mdp)
294462306a36Sopenharmony_ci{
294562306a36Sopenharmony_ci	if (!mdp->port)
294662306a36Sopenharmony_ci		return TSU_VTAG0;
294762306a36Sopenharmony_ci	else
294862306a36Sopenharmony_ci		return TSU_VTAG1;
294962306a36Sopenharmony_ci}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_cistatic int sh_eth_vlan_rx_add_vid(struct net_device *ndev,
295262306a36Sopenharmony_ci				  __be16 proto, u16 vid)
295362306a36Sopenharmony_ci{
295462306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
295562306a36Sopenharmony_ci	int vtag_reg_index = sh_eth_get_vtag_index(mdp);
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	if (unlikely(!mdp->cd->tsu))
295862306a36Sopenharmony_ci		return -EPERM;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	/* No filtering if vid = 0 */
296162306a36Sopenharmony_ci	if (!vid)
296262306a36Sopenharmony_ci		return 0;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	mdp->vlan_num_ids++;
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	/* The controller has one VLAN tag HW filter. So, if the filter is
296762306a36Sopenharmony_ci	 * already enabled, the driver disables it and the filte
296862306a36Sopenharmony_ci	 */
296962306a36Sopenharmony_ci	if (mdp->vlan_num_ids > 1) {
297062306a36Sopenharmony_ci		/* disable VLAN filter */
297162306a36Sopenharmony_ci		sh_eth_tsu_write(mdp, 0, vtag_reg_index);
297262306a36Sopenharmony_ci		return 0;
297362306a36Sopenharmony_ci	}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, TSU_VTAG_ENABLE | (vid & TSU_VTAG_VID_MASK),
297662306a36Sopenharmony_ci			 vtag_reg_index);
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	return 0;
297962306a36Sopenharmony_ci}
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_cistatic int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
298262306a36Sopenharmony_ci				   __be16 proto, u16 vid)
298362306a36Sopenharmony_ci{
298462306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
298562306a36Sopenharmony_ci	int vtag_reg_index = sh_eth_get_vtag_index(mdp);
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	if (unlikely(!mdp->cd->tsu))
298862306a36Sopenharmony_ci		return -EPERM;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	/* No filtering if vid = 0 */
299162306a36Sopenharmony_ci	if (!vid)
299262306a36Sopenharmony_ci		return 0;
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	mdp->vlan_num_ids--;
299562306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, vtag_reg_index);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	return 0;
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci/* SuperH's TSU register init function */
300162306a36Sopenharmony_cistatic void sh_eth_tsu_init(struct sh_eth_private *mdp)
300262306a36Sopenharmony_ci{
300362306a36Sopenharmony_ci	if (!mdp->cd->dual_port) {
300462306a36Sopenharmony_ci		sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */
300562306a36Sopenharmony_ci		sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL,
300662306a36Sopenharmony_ci				 TSU_FWSLC);	/* Enable POST registers */
300762306a36Sopenharmony_ci		return;
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWEN0);	/* Disable forward(0->1) */
301162306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWEN1);	/* Disable forward(1->0) */
301262306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FCM);	/* forward fifo 3k-3k */
301362306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL0);
301462306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL1);
301562306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_PRISL0);
301662306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_PRISL1);
301762306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSL0);
301862306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSL1);
301962306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC);
302062306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_QTAGM0);	/* Disable QTAG(0->1) */
302162306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_QTAGM1);	/* Disable QTAG(1->0) */
302262306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWSR);	/* all interrupt status clear */
302362306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_FWINMK);	/* Disable all interrupt */
302462306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_TEN);	/* Disable all CAM entry */
302562306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST1);	/* Disable CAM entry [ 0- 7] */
302662306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST2);	/* Disable CAM entry [ 8-15] */
302762306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST3);	/* Disable CAM entry [16-23] */
302862306a36Sopenharmony_ci	sh_eth_tsu_write(mdp, 0, TSU_POST4);	/* Disable CAM entry [24-31] */
302962306a36Sopenharmony_ci}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci/* MDIO bus release function */
303262306a36Sopenharmony_cistatic int sh_mdio_release(struct sh_eth_private *mdp)
303362306a36Sopenharmony_ci{
303462306a36Sopenharmony_ci	/* unregister mdio bus */
303562306a36Sopenharmony_ci	mdiobus_unregister(mdp->mii_bus);
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	/* free bitbang info */
303862306a36Sopenharmony_ci	free_mdio_bitbang(mdp->mii_bus);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	return 0;
304162306a36Sopenharmony_ci}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_cistatic int sh_mdiobb_read_c22(struct mii_bus *bus, int phy, int reg)
304462306a36Sopenharmony_ci{
304562306a36Sopenharmony_ci	int res;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	pm_runtime_get_sync(bus->parent);
304862306a36Sopenharmony_ci	res = mdiobb_read_c22(bus, phy, reg);
304962306a36Sopenharmony_ci	pm_runtime_put(bus->parent);
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci	return res;
305262306a36Sopenharmony_ci}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_cistatic int sh_mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, u16 val)
305562306a36Sopenharmony_ci{
305662306a36Sopenharmony_ci	int res;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	pm_runtime_get_sync(bus->parent);
305962306a36Sopenharmony_ci	res = mdiobb_write_c22(bus, phy, reg, val);
306062306a36Sopenharmony_ci	pm_runtime_put(bus->parent);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	return res;
306362306a36Sopenharmony_ci}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_cistatic int sh_mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, int reg)
306662306a36Sopenharmony_ci{
306762306a36Sopenharmony_ci	int res;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	pm_runtime_get_sync(bus->parent);
307062306a36Sopenharmony_ci	res = mdiobb_read_c45(bus, phy, devad, reg);
307162306a36Sopenharmony_ci	pm_runtime_put(bus->parent);
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	return res;
307462306a36Sopenharmony_ci}
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_cistatic int sh_mdiobb_write_c45(struct mii_bus *bus, int phy, int devad,
307762306a36Sopenharmony_ci			       int reg, u16 val)
307862306a36Sopenharmony_ci{
307962306a36Sopenharmony_ci	int res;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	pm_runtime_get_sync(bus->parent);
308262306a36Sopenharmony_ci	res = mdiobb_write_c45(bus, phy, devad, reg, val);
308362306a36Sopenharmony_ci	pm_runtime_put(bus->parent);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	return res;
308662306a36Sopenharmony_ci}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci/* MDIO bus init function */
308962306a36Sopenharmony_cistatic int sh_mdio_init(struct sh_eth_private *mdp,
309062306a36Sopenharmony_ci			struct sh_eth_plat_data *pd)
309162306a36Sopenharmony_ci{
309262306a36Sopenharmony_ci	int ret;
309362306a36Sopenharmony_ci	struct bb_info *bitbang;
309462306a36Sopenharmony_ci	struct platform_device *pdev = mdp->pdev;
309562306a36Sopenharmony_ci	struct device *dev = &mdp->pdev->dev;
309662306a36Sopenharmony_ci	struct phy_device *phydev;
309762306a36Sopenharmony_ci	struct device_node *pn;
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	/* create bit control struct for PHY */
310062306a36Sopenharmony_ci	bitbang = devm_kzalloc(dev, sizeof(struct bb_info), GFP_KERNEL);
310162306a36Sopenharmony_ci	if (!bitbang)
310262306a36Sopenharmony_ci		return -ENOMEM;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	/* bitbang init */
310562306a36Sopenharmony_ci	bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
310662306a36Sopenharmony_ci	bitbang->set_gate = pd->set_mdio_gate;
310762306a36Sopenharmony_ci	bitbang->ctrl.ops = &bb_ops;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	/* MII controller setting */
311062306a36Sopenharmony_ci	mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
311162306a36Sopenharmony_ci	if (!mdp->mii_bus)
311262306a36Sopenharmony_ci		return -ENOMEM;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	/* Wrap accessors with Runtime PM-aware ops */
311562306a36Sopenharmony_ci	mdp->mii_bus->read = sh_mdiobb_read_c22;
311662306a36Sopenharmony_ci	mdp->mii_bus->write = sh_mdiobb_write_c22;
311762306a36Sopenharmony_ci	mdp->mii_bus->read_c45 = sh_mdiobb_read_c45;
311862306a36Sopenharmony_ci	mdp->mii_bus->write_c45 = sh_mdiobb_write_c45;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	/* Hook up MII support for ethtool */
312162306a36Sopenharmony_ci	mdp->mii_bus->name = "sh_mii";
312262306a36Sopenharmony_ci	mdp->mii_bus->parent = dev;
312362306a36Sopenharmony_ci	snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
312462306a36Sopenharmony_ci		 pdev->name, pdev->id);
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	/* register MDIO bus */
312762306a36Sopenharmony_ci	if (pd->phy_irq > 0)
312862306a36Sopenharmony_ci		mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci	ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
313162306a36Sopenharmony_ci	if (ret)
313262306a36Sopenharmony_ci		goto out_free_bus;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	pn = of_parse_phandle(dev->of_node, "phy-handle", 0);
313562306a36Sopenharmony_ci	phydev = of_phy_find_device(pn);
313662306a36Sopenharmony_ci	if (phydev) {
313762306a36Sopenharmony_ci		phydev->mac_managed_pm = true;
313862306a36Sopenharmony_ci		put_device(&phydev->mdio.dev);
313962306a36Sopenharmony_ci	}
314062306a36Sopenharmony_ci	of_node_put(pn);
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	return 0;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ciout_free_bus:
314562306a36Sopenharmony_ci	free_mdio_bitbang(mdp->mii_bus);
314662306a36Sopenharmony_ci	return ret;
314762306a36Sopenharmony_ci}
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_cistatic const u16 *sh_eth_get_register_offset(int register_type)
315062306a36Sopenharmony_ci{
315162306a36Sopenharmony_ci	const u16 *reg_offset = NULL;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	switch (register_type) {
315462306a36Sopenharmony_ci	case SH_ETH_REG_GIGABIT:
315562306a36Sopenharmony_ci		reg_offset = sh_eth_offset_gigabit;
315662306a36Sopenharmony_ci		break;
315762306a36Sopenharmony_ci	case SH_ETH_REG_FAST_RCAR:
315862306a36Sopenharmony_ci		reg_offset = sh_eth_offset_fast_rcar;
315962306a36Sopenharmony_ci		break;
316062306a36Sopenharmony_ci	case SH_ETH_REG_FAST_SH4:
316162306a36Sopenharmony_ci		reg_offset = sh_eth_offset_fast_sh4;
316262306a36Sopenharmony_ci		break;
316362306a36Sopenharmony_ci	case SH_ETH_REG_FAST_SH3_SH2:
316462306a36Sopenharmony_ci		reg_offset = sh_eth_offset_fast_sh3_sh2;
316562306a36Sopenharmony_ci		break;
316662306a36Sopenharmony_ci	}
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	return reg_offset;
316962306a36Sopenharmony_ci}
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops = {
317262306a36Sopenharmony_ci	.ndo_open		= sh_eth_open,
317362306a36Sopenharmony_ci	.ndo_stop		= sh_eth_close,
317462306a36Sopenharmony_ci	.ndo_start_xmit		= sh_eth_start_xmit,
317562306a36Sopenharmony_ci	.ndo_get_stats		= sh_eth_get_stats,
317662306a36Sopenharmony_ci	.ndo_set_rx_mode	= sh_eth_set_rx_mode,
317762306a36Sopenharmony_ci	.ndo_tx_timeout		= sh_eth_tx_timeout,
317862306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl_running,
317962306a36Sopenharmony_ci	.ndo_change_mtu		= sh_eth_change_mtu,
318062306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
318162306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
318262306a36Sopenharmony_ci	.ndo_set_features	= sh_eth_set_features,
318362306a36Sopenharmony_ci};
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops_tsu = {
318662306a36Sopenharmony_ci	.ndo_open		= sh_eth_open,
318762306a36Sopenharmony_ci	.ndo_stop		= sh_eth_close,
318862306a36Sopenharmony_ci	.ndo_start_xmit		= sh_eth_start_xmit,
318962306a36Sopenharmony_ci	.ndo_get_stats		= sh_eth_get_stats,
319062306a36Sopenharmony_ci	.ndo_set_rx_mode	= sh_eth_set_rx_mode,
319162306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= sh_eth_vlan_rx_add_vid,
319262306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= sh_eth_vlan_rx_kill_vid,
319362306a36Sopenharmony_ci	.ndo_tx_timeout		= sh_eth_tx_timeout,
319462306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl_running,
319562306a36Sopenharmony_ci	.ndo_change_mtu		= sh_eth_change_mtu,
319662306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
319762306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
319862306a36Sopenharmony_ci	.ndo_set_features	= sh_eth_set_features,
319962306a36Sopenharmony_ci};
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci#ifdef CONFIG_OF
320262306a36Sopenharmony_cistatic struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
320562306a36Sopenharmony_ci	struct sh_eth_plat_data *pdata;
320662306a36Sopenharmony_ci	phy_interface_t interface;
320762306a36Sopenharmony_ci	int ret;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
321062306a36Sopenharmony_ci	if (!pdata)
321162306a36Sopenharmony_ci		return NULL;
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	ret = of_get_phy_mode(np, &interface);
321462306a36Sopenharmony_ci	if (ret)
321562306a36Sopenharmony_ci		return NULL;
321662306a36Sopenharmony_ci	pdata->phy_interface = interface;
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci	of_get_mac_address(np, pdata->mac_addr);
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	pdata->no_ether_link =
322162306a36Sopenharmony_ci		of_property_read_bool(np, "renesas,no-ether-link");
322262306a36Sopenharmony_ci	pdata->ether_link_active_low =
322362306a36Sopenharmony_ci		of_property_read_bool(np, "renesas,ether-link-active-low");
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci	return pdata;
322662306a36Sopenharmony_ci}
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_cistatic const struct of_device_id sh_eth_match_table[] = {
322962306a36Sopenharmony_ci	{ .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data },
323062306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7743", .data = &rcar_gen2_data },
323162306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7745", .data = &rcar_gen2_data },
323262306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7778", .data = &rcar_gen1_data },
323362306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7779", .data = &rcar_gen1_data },
323462306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7790", .data = &rcar_gen2_data },
323562306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7791", .data = &rcar_gen2_data },
323662306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7793", .data = &rcar_gen2_data },
323762306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r8a7794", .data = &rcar_gen2_data },
323862306a36Sopenharmony_ci	{ .compatible = "renesas,gether-r8a77980", .data = &r8a77980_data },
323962306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data },
324062306a36Sopenharmony_ci	{ .compatible = "renesas,ether-r7s9210", .data = &r7s9210_data },
324162306a36Sopenharmony_ci	{ .compatible = "renesas,rcar-gen1-ether", .data = &rcar_gen1_data },
324262306a36Sopenharmony_ci	{ .compatible = "renesas,rcar-gen2-ether", .data = &rcar_gen2_data },
324362306a36Sopenharmony_ci	{ }
324462306a36Sopenharmony_ci};
324562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_eth_match_table);
324662306a36Sopenharmony_ci#else
324762306a36Sopenharmony_cistatic inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
324862306a36Sopenharmony_ci{
324962306a36Sopenharmony_ci	return NULL;
325062306a36Sopenharmony_ci}
325162306a36Sopenharmony_ci#endif
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_cistatic int sh_eth_drv_probe(struct platform_device *pdev)
325462306a36Sopenharmony_ci{
325562306a36Sopenharmony_ci	struct resource *res;
325662306a36Sopenharmony_ci	struct sh_eth_plat_data *pd = dev_get_platdata(&pdev->dev);
325762306a36Sopenharmony_ci	const struct platform_device_id *id = platform_get_device_id(pdev);
325862306a36Sopenharmony_ci	struct sh_eth_private *mdp;
325962306a36Sopenharmony_ci	struct net_device *ndev;
326062306a36Sopenharmony_ci	int ret;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	ndev = alloc_etherdev(sizeof(struct sh_eth_private));
326362306a36Sopenharmony_ci	if (!ndev)
326462306a36Sopenharmony_ci		return -ENOMEM;
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
326762306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	ret = platform_get_irq(pdev, 0);
327062306a36Sopenharmony_ci	if (ret < 0)
327162306a36Sopenharmony_ci		goto out_release;
327262306a36Sopenharmony_ci	ndev->irq = ret;
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	mdp = netdev_priv(ndev);
327762306a36Sopenharmony_ci	mdp->num_tx_ring = TX_RING_SIZE;
327862306a36Sopenharmony_ci	mdp->num_rx_ring = RX_RING_SIZE;
327962306a36Sopenharmony_ci	mdp->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
328062306a36Sopenharmony_ci	if (IS_ERR(mdp->addr)) {
328162306a36Sopenharmony_ci		ret = PTR_ERR(mdp->addr);
328262306a36Sopenharmony_ci		goto out_release;
328362306a36Sopenharmony_ci	}
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	ndev->base_addr = res->start;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	spin_lock_init(&mdp->lock);
328862306a36Sopenharmony_ci	mdp->pdev = pdev;
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	if (pdev->dev.of_node)
329162306a36Sopenharmony_ci		pd = sh_eth_parse_dt(&pdev->dev);
329262306a36Sopenharmony_ci	if (!pd) {
329362306a36Sopenharmony_ci		dev_err(&pdev->dev, "no platform data\n");
329462306a36Sopenharmony_ci		ret = -EINVAL;
329562306a36Sopenharmony_ci		goto out_release;
329662306a36Sopenharmony_ci	}
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	/* get PHY ID */
329962306a36Sopenharmony_ci	mdp->phy_id = pd->phy;
330062306a36Sopenharmony_ci	mdp->phy_interface = pd->phy_interface;
330162306a36Sopenharmony_ci	mdp->no_ether_link = pd->no_ether_link;
330262306a36Sopenharmony_ci	mdp->ether_link_active_low = pd->ether_link_active_low;
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	/* set cpu data */
330562306a36Sopenharmony_ci	if (id)
330662306a36Sopenharmony_ci		mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
330762306a36Sopenharmony_ci	else
330862306a36Sopenharmony_ci		mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci	mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);
331162306a36Sopenharmony_ci	if (!mdp->reg_offset) {
331262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unknown register type (%d)\n",
331362306a36Sopenharmony_ci			mdp->cd->register_type);
331462306a36Sopenharmony_ci		ret = -EINVAL;
331562306a36Sopenharmony_ci		goto out_release;
331662306a36Sopenharmony_ci	}
331762306a36Sopenharmony_ci	sh_eth_set_default_cpu_data(mdp->cd);
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	/* User's manual states max MTU should be 2048 but due to the
332062306a36Sopenharmony_ci	 * alignment calculations in sh_eth_ring_init() the practical
332162306a36Sopenharmony_ci	 * MTU is a bit less. Maybe this can be optimized some more.
332262306a36Sopenharmony_ci	 */
332362306a36Sopenharmony_ci	ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
332462306a36Sopenharmony_ci	ndev->min_mtu = ETH_MIN_MTU;
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci	if (mdp->cd->rx_csum) {
332762306a36Sopenharmony_ci		ndev->features = NETIF_F_RXCSUM;
332862306a36Sopenharmony_ci		ndev->hw_features = NETIF_F_RXCSUM;
332962306a36Sopenharmony_ci	}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	/* set function */
333262306a36Sopenharmony_ci	if (mdp->cd->tsu)
333362306a36Sopenharmony_ci		ndev->netdev_ops = &sh_eth_netdev_ops_tsu;
333462306a36Sopenharmony_ci	else
333562306a36Sopenharmony_ci		ndev->netdev_ops = &sh_eth_netdev_ops;
333662306a36Sopenharmony_ci	ndev->ethtool_ops = &sh_eth_ethtool_ops;
333762306a36Sopenharmony_ci	ndev->watchdog_timeo = TX_TIMEOUT;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	/* debug message level */
334062306a36Sopenharmony_ci	mdp->msg_enable = SH_ETH_DEF_MSG_ENABLE;
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	/* read and set MAC address */
334362306a36Sopenharmony_ci	read_mac_address(ndev, pd->mac_addr);
334462306a36Sopenharmony_ci	if (!is_valid_ether_addr(ndev->dev_addr)) {
334562306a36Sopenharmony_ci		dev_warn(&pdev->dev,
334662306a36Sopenharmony_ci			 "no valid MAC address supplied, using a random one.\n");
334762306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	if (mdp->cd->tsu) {
335162306a36Sopenharmony_ci		int port = pdev->id < 0 ? 0 : pdev->id % 2;
335262306a36Sopenharmony_ci		struct resource *rtsu;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci		rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
335562306a36Sopenharmony_ci		if (!rtsu) {
335662306a36Sopenharmony_ci			dev_err(&pdev->dev, "no TSU resource\n");
335762306a36Sopenharmony_ci			ret = -ENODEV;
335862306a36Sopenharmony_ci			goto out_release;
335962306a36Sopenharmony_ci		}
336062306a36Sopenharmony_ci		/* We can only request the  TSU region  for the first port
336162306a36Sopenharmony_ci		 * of the two  sharing this TSU for the probe to succeed...
336262306a36Sopenharmony_ci		 */
336362306a36Sopenharmony_ci		if (port == 0 &&
336462306a36Sopenharmony_ci		    !devm_request_mem_region(&pdev->dev, rtsu->start,
336562306a36Sopenharmony_ci					     resource_size(rtsu),
336662306a36Sopenharmony_ci					     dev_name(&pdev->dev))) {
336762306a36Sopenharmony_ci			dev_err(&pdev->dev, "can't request TSU resource.\n");
336862306a36Sopenharmony_ci			ret = -EBUSY;
336962306a36Sopenharmony_ci			goto out_release;
337062306a36Sopenharmony_ci		}
337162306a36Sopenharmony_ci		/* ioremap the TSU registers */
337262306a36Sopenharmony_ci		mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start,
337362306a36Sopenharmony_ci					     resource_size(rtsu));
337462306a36Sopenharmony_ci		if (!mdp->tsu_addr) {
337562306a36Sopenharmony_ci			dev_err(&pdev->dev, "TSU region ioremap() failed.\n");
337662306a36Sopenharmony_ci			ret = -ENOMEM;
337762306a36Sopenharmony_ci			goto out_release;
337862306a36Sopenharmony_ci		}
337962306a36Sopenharmony_ci		mdp->port = port;
338062306a36Sopenharmony_ci		ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci		/* Need to init only the first port of the two sharing a TSU */
338362306a36Sopenharmony_ci		if (port == 0) {
338462306a36Sopenharmony_ci			if (mdp->cd->chip_reset)
338562306a36Sopenharmony_ci				mdp->cd->chip_reset(ndev);
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci			/* TSU init (Init only)*/
338862306a36Sopenharmony_ci			sh_eth_tsu_init(mdp);
338962306a36Sopenharmony_ci		}
339062306a36Sopenharmony_ci	}
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	if (mdp->cd->rmiimode)
339362306a36Sopenharmony_ci		sh_eth_write(ndev, 0x1, RMIIMODE);
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	/* MDIO bus init */
339662306a36Sopenharmony_ci	ret = sh_mdio_init(mdp, pd);
339762306a36Sopenharmony_ci	if (ret) {
339862306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret, "MDIO init failed\n");
339962306a36Sopenharmony_ci		goto out_release;
340062306a36Sopenharmony_ci	}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	netif_napi_add(ndev, &mdp->napi, sh_eth_poll);
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci	/* network device register */
340562306a36Sopenharmony_ci	ret = register_netdev(ndev);
340662306a36Sopenharmony_ci	if (ret)
340762306a36Sopenharmony_ci		goto out_napi_del;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	if (mdp->cd->magic)
341062306a36Sopenharmony_ci		device_set_wakeup_capable(&pdev->dev, 1);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	/* print device information */
341362306a36Sopenharmony_ci	netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n",
341462306a36Sopenharmony_ci		    (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
341762306a36Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	return ret;
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ciout_napi_del:
342262306a36Sopenharmony_ci	netif_napi_del(&mdp->napi);
342362306a36Sopenharmony_ci	sh_mdio_release(mdp);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ciout_release:
342662306a36Sopenharmony_ci	/* net_dev free */
342762306a36Sopenharmony_ci	free_netdev(ndev);
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
343062306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
343162306a36Sopenharmony_ci	return ret;
343262306a36Sopenharmony_ci}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_cistatic int sh_eth_drv_remove(struct platform_device *pdev)
343562306a36Sopenharmony_ci{
343662306a36Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
343762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci	unregister_netdev(ndev);
344062306a36Sopenharmony_ci	netif_napi_del(&mdp->napi);
344162306a36Sopenharmony_ci	sh_mdio_release(mdp);
344262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
344362306a36Sopenharmony_ci	free_netdev(ndev);
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	return 0;
344662306a36Sopenharmony_ci}
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci#ifdef CONFIG_PM
344962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
345062306a36Sopenharmony_cistatic int sh_eth_wol_setup(struct net_device *ndev)
345162306a36Sopenharmony_ci{
345262306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	/* Only allow ECI interrupts */
345562306a36Sopenharmony_ci	synchronize_irq(ndev->irq);
345662306a36Sopenharmony_ci	napi_disable(&mdp->napi);
345762306a36Sopenharmony_ci	sh_eth_write(ndev, EESIPR_ECIIP, EESIPR);
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	/* Enable MagicPacket */
346062306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	return enable_irq_wake(ndev->irq);
346362306a36Sopenharmony_ci}
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_cistatic int sh_eth_wol_restore(struct net_device *ndev)
346662306a36Sopenharmony_ci{
346762306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
346862306a36Sopenharmony_ci	int ret;
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	napi_enable(&mdp->napi);
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	/* Disable MagicPacket */
347362306a36Sopenharmony_ci	sh_eth_modify(ndev, ECMR, ECMR_MPDE, 0);
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	/* The device needs to be reset to restore MagicPacket logic
347662306a36Sopenharmony_ci	 * for next wakeup. If we close and open the device it will
347762306a36Sopenharmony_ci	 * both be reset and all registers restored. This is what
347862306a36Sopenharmony_ci	 * happens during suspend and resume without WoL enabled.
347962306a36Sopenharmony_ci	 */
348062306a36Sopenharmony_ci	sh_eth_close(ndev);
348162306a36Sopenharmony_ci	ret = sh_eth_open(ndev);
348262306a36Sopenharmony_ci	if (ret < 0)
348362306a36Sopenharmony_ci		return ret;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	return disable_irq_wake(ndev->irq);
348662306a36Sopenharmony_ci}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_cistatic int sh_eth_suspend(struct device *dev)
348962306a36Sopenharmony_ci{
349062306a36Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
349162306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
349262306a36Sopenharmony_ci	int ret;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	if (!netif_running(ndev))
349562306a36Sopenharmony_ci		return 0;
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	netif_device_detach(ndev);
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci	if (mdp->wol_enabled)
350062306a36Sopenharmony_ci		ret = sh_eth_wol_setup(ndev);
350162306a36Sopenharmony_ci	else
350262306a36Sopenharmony_ci		ret = sh_eth_close(ndev);
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	return ret;
350562306a36Sopenharmony_ci}
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_cistatic int sh_eth_resume(struct device *dev)
350862306a36Sopenharmony_ci{
350962306a36Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
351062306a36Sopenharmony_ci	struct sh_eth_private *mdp = netdev_priv(ndev);
351162306a36Sopenharmony_ci	int ret;
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	if (!netif_running(ndev))
351462306a36Sopenharmony_ci		return 0;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	if (mdp->wol_enabled)
351762306a36Sopenharmony_ci		ret = sh_eth_wol_restore(ndev);
351862306a36Sopenharmony_ci	else
351962306a36Sopenharmony_ci		ret = sh_eth_open(ndev);
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	if (ret < 0)
352262306a36Sopenharmony_ci		return ret;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	netif_device_attach(ndev);
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	return ret;
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci#endif
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_cistatic int sh_eth_runtime_nop(struct device *dev)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	/* Runtime PM callback shared between ->runtime_suspend()
353362306a36Sopenharmony_ci	 * and ->runtime_resume(). Simply returns success.
353462306a36Sopenharmony_ci	 *
353562306a36Sopenharmony_ci	 * This driver re-initializes all registers after
353662306a36Sopenharmony_ci	 * pm_runtime_get_sync() anyway so there is no need
353762306a36Sopenharmony_ci	 * to save and restore registers here.
353862306a36Sopenharmony_ci	 */
353962306a36Sopenharmony_ci	return 0;
354062306a36Sopenharmony_ci}
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_cistatic const struct dev_pm_ops sh_eth_dev_pm_ops = {
354362306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume)
354462306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL)
354562306a36Sopenharmony_ci};
354662306a36Sopenharmony_ci#define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops)
354762306a36Sopenharmony_ci#else
354862306a36Sopenharmony_ci#define SH_ETH_PM_OPS NULL
354962306a36Sopenharmony_ci#endif
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_cistatic const struct platform_device_id sh_eth_id_table[] = {
355262306a36Sopenharmony_ci	{ "sh7619-ether", (kernel_ulong_t)&sh7619_data },
355362306a36Sopenharmony_ci	{ "sh771x-ether", (kernel_ulong_t)&sh771x_data },
355462306a36Sopenharmony_ci	{ "sh7724-ether", (kernel_ulong_t)&sh7724_data },
355562306a36Sopenharmony_ci	{ "sh7734-gether", (kernel_ulong_t)&sh7734_data },
355662306a36Sopenharmony_ci	{ "sh7757-ether", (kernel_ulong_t)&sh7757_data },
355762306a36Sopenharmony_ci	{ "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
355862306a36Sopenharmony_ci	{ "sh7763-gether", (kernel_ulong_t)&sh7763_data },
355962306a36Sopenharmony_ci	{ }
356062306a36Sopenharmony_ci};
356162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sh_eth_id_table);
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_cistatic struct platform_driver sh_eth_driver = {
356462306a36Sopenharmony_ci	.probe = sh_eth_drv_probe,
356562306a36Sopenharmony_ci	.remove = sh_eth_drv_remove,
356662306a36Sopenharmony_ci	.id_table = sh_eth_id_table,
356762306a36Sopenharmony_ci	.driver = {
356862306a36Sopenharmony_ci		   .name = CARDNAME,
356962306a36Sopenharmony_ci		   .pm = SH_ETH_PM_OPS,
357062306a36Sopenharmony_ci		   .of_match_table = of_match_ptr(sh_eth_match_table),
357162306a36Sopenharmony_ci	},
357262306a36Sopenharmony_ci};
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_cimodule_platform_driver(sh_eth_driver);
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ciMODULE_AUTHOR("Nobuhiro Iwamatsu, Yoshihiro Shimoda");
357762306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas SuperH Ethernet driver");
357862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
3579